From 86c845b49b9dd36110ac7907290c244e23d56b12 Mon Sep 17 00:00:00 2001 From: peima Date: Wed, 23 Dec 2020 00:43:59 -0500 Subject: [PATCH] backup. --- assets/images/navbar_logo.svg | 103 +++++ assets/images/not_found.png | Bin 0 -> 1602 bytes fonts/company.ttf | Bin 0 -> 3596 bytes fonts/wisetronic.ttf | Bin 0 -> 2264 bytes lib/constants.dart | 8 + lib/events/eventbus.dart | 4 + lib/events/events.dart | 4 + lib/generated/intl/messages_all.dart | 4 + lib/generated/intl/messages_en.dart | 31 +- lib/generated/intl/messages_zh_CN.dart | 55 +++ lib/generated/l10n.dart | 299 ++++++++++++++ lib/l10n/intl_en.arb | 33 +- lib/l10n/intl_zh_CN.arb | 32 ++ lib/main.dart | 170 ++++---- lib/models/gallery.dart | 24 ++ lib/models/stripe_payment_method.dart | 46 +++ lib/models/user.dart | 68 ++++ lib/pages/home.dart | 96 +++++ lib/routes.dart | 16 + lib/store/actions.dart | 18 + lib/store/reducer/app_reducer.dart | 13 + lib/store/reducer/context_reducer.dart | 12 + lib/store/reducer/locale_reducer.dart | 11 + lib/store/reducer/user_reducer.dart | 13 + lib/store/state/app_state.dart | 42 ++ lib/store/store.dart | 9 + lib/utils/double_back_to_close_app.dart | 98 +++++ lib/utils/http_util.dart | 370 ++++++++++++++++++ lib/utils/util_io.dart | 46 +++ lib/utils/util_web.dart | 52 +++ lib/utils/utils.dart | 277 +++++++++++++ .../desktop/desktop_Index_carousel.dart | 113 ++++++ .../desktop/desktop_index_main_content_1.dart | 60 +++ .../desktop/desktop_index_main_content_2.dart | 247 ++++++++++++ .../desktop/desktop_index_main_content_3.dart | 179 +++++++++ .../desktop/desktop_navigationbar.dart | 99 +++++ lib/widgets/general/bottom_nav.dart | 51 +++ lib/widgets/general/download_item.dart | 90 +++++ lib/widgets/general/index_carousel.dart | 21 + lib/widgets/general/index_main_content_1.dart | 20 + lib/widgets/general/index_main_content_2.dart | 20 + lib/widgets/general/index_main_content_3.dart | 20 + lib/widgets/general/navigationbar.dart | 37 ++ lib/widgets/general/navigationbar_logo.dart | 25 ++ lib/widgets/general/text_link.dart | 58 +++ lib/widgets/mobile/mobile_index_carousel.dart | 94 +++++ .../mobile/mobile_index_main_content_1.dart | 40 ++ .../mobile/mobile_index_main_content_2.dart | 119 ++++++ .../mobile/mobile_index_main_content_3.dart | 122 ++++++ .../mobile/mobile_navigation_drawer.dart | 233 +++++++++++ .../mobile_navigation_drawer_header.dart | 30 ++ lib/widgets/mobile/mobile_navigationbar.dart | 74 ++++ pubspec.lock | 26 +- pubspec.yaml | 13 +- 54 files changed, 3638 insertions(+), 107 deletions(-) create mode 100644 assets/images/navbar_logo.svg create mode 100644 assets/images/not_found.png create mode 100644 fonts/company.ttf create mode 100644 fonts/wisetronic.ttf create mode 100644 lib/constants.dart create mode 100644 lib/events/eventbus.dart create mode 100644 lib/events/events.dart create mode 100644 lib/generated/intl/messages_zh_CN.dart create mode 100644 lib/l10n/intl_zh_CN.arb create mode 100644 lib/models/gallery.dart create mode 100644 lib/models/stripe_payment_method.dart create mode 100644 lib/models/user.dart create mode 100644 lib/pages/home.dart create mode 100644 lib/routes.dart create mode 100644 lib/store/actions.dart create mode 100644 lib/store/reducer/app_reducer.dart create mode 100644 lib/store/reducer/context_reducer.dart create mode 100644 lib/store/reducer/locale_reducer.dart create mode 100644 lib/store/reducer/user_reducer.dart create mode 100644 lib/store/state/app_state.dart create mode 100644 lib/store/store.dart create mode 100644 lib/utils/double_back_to_close_app.dart create mode 100644 lib/utils/http_util.dart create mode 100644 lib/utils/util_io.dart create mode 100644 lib/utils/util_web.dart create mode 100644 lib/utils/utils.dart create mode 100644 lib/widgets/desktop/desktop_Index_carousel.dart create mode 100644 lib/widgets/desktop/desktop_index_main_content_1.dart create mode 100644 lib/widgets/desktop/desktop_index_main_content_2.dart create mode 100644 lib/widgets/desktop/desktop_index_main_content_3.dart create mode 100644 lib/widgets/desktop/desktop_navigationbar.dart create mode 100644 lib/widgets/general/bottom_nav.dart create mode 100644 lib/widgets/general/download_item.dart create mode 100644 lib/widgets/general/index_carousel.dart create mode 100644 lib/widgets/general/index_main_content_1.dart create mode 100644 lib/widgets/general/index_main_content_2.dart create mode 100644 lib/widgets/general/index_main_content_3.dart create mode 100644 lib/widgets/general/navigationbar.dart create mode 100644 lib/widgets/general/navigationbar_logo.dart create mode 100644 lib/widgets/general/text_link.dart create mode 100644 lib/widgets/mobile/mobile_index_carousel.dart create mode 100644 lib/widgets/mobile/mobile_index_main_content_1.dart create mode 100644 lib/widgets/mobile/mobile_index_main_content_2.dart create mode 100644 lib/widgets/mobile/mobile_index_main_content_3.dart create mode 100644 lib/widgets/mobile/mobile_navigation_drawer.dart create mode 100644 lib/widgets/mobile/mobile_navigation_drawer_header.dart create mode 100644 lib/widgets/mobile/mobile_navigationbar.dart diff --git a/assets/images/navbar_logo.svg b/assets/images/navbar_logo.svg new file mode 100644 index 0000000..2aa53ef --- /dev/null +++ b/assets/images/navbar_logo.svg @@ -0,0 +1,103 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/not_found.png b/assets/images/not_found.png new file mode 100644 index 0000000000000000000000000000000000000000..bbe50f0fb6da179a337401186dee42026b9db1aa GIT binary patch literal 1602 zcmcIk`!|#c7=FL`h8e?LFlpSz6I53pI#*q+>wMCj2K@ z#~sBfDm~X)_P~{{tu3iUrb@iUBG@BwX5F_N`5b?CVDQU|?$VQ)G>4Okzo!{#+@DH2 zxFXhltYGZK2Q!)Dd3nICJ%+Kd9Y#XWu%>k=fAu(BIn8+T8ZnQ&8^vTr-XKSBAlpuj z6`f~HF^aF3C3UW@>E(jyPzttVbCp&u|6`!cY&)g4czsKlbn=^tawefaWG7><+2*xM zf5@e@bpZ_Q!WOhT>TTs}+u)>x4vMnU6Ep<>fipclde%^=0Pf*-h#mW{ar#4;EBsmf7XFDgq_ozLVwKPX}HdJg6>gv4Qn zH@rPuU5=1z(rCik1`}gK|C_i7R55YN3gwjdW17m#nL5Hcx%OO)kmqa5Zp$6!5~*7x z+Dff^l3}p6#p@W-%Z(yLXvlqnFhU@Ov@oTJq@u}yR-S2!&7kj%R4r`fJ`s*Pj}%2G z7i+5UqC^ue(%1;P_@+YLyRdNdj1nL%{zr9tUZ#P0o@slwZ*<^{eN6ar>w5XLQ>dmS zZLGaVFkM22j}9AlyI9>>degJ6QxuYG6=u<=VRi9`2&B03S!{AcLC_J=>oT@`cg)%| zQTu*VCA1`Elss#D?p%1>(HU*N)J3j)rP)3xIo6UzSLE%kNsIuxi@A?PauB{36)WtzR`KN{}8X|E~$u5BnBiFo5HkVh`HY;J1Yv_@7$KI zaImH$sRbqI$)+aAbuOMd(EZE9vUzxqG2T7GU)JS>2tExpEFZ7t*9gwepG&UK*W%GY zqQ%pOJSyR(U?F7RCO+r}ODH_A!6Z$>tFal#il&92E0SpNyzb{fyrM=5sY5v?pxZ7o z0mF7V8@Q_-*nqSb7=n4(D-PI~jW-(*WUs&D#6ev~Q1%H%6J$P*=poSN z43}dRUWVIzdnSHO+?k>&Wbe}sD!u~%9pZakXN z>}<9FfxzQm5#2=*hTyA$;VKiu7MYGC{cKrY&?E$uTHRn`-izFaQB~?%*I`sD2%H32 zp{*EnN-ykZ0y8@M&`Mlv*@|?cNz~|WivHI}KHE|gBF?gGmOXxo=e(%aByAPrIwMC3 zhrz)*SL0y&zHU%9e&PuZbQ&maE)GTc;}1#~?|sS;DoX9%U7thvPhT~4ks$yWXY)+! h*n}|l3;tboG=Y4-!SKOxRS z_5VH;GXWQ^G+;*P;iJ>cAk8ApFxIwhOE-mK@h1~L` z+RdetiD6Yy_g*86e&YI<7H==&cVcK$ctvy zL?J@mjK`uTYlhGZppZ8`{XDCf#00K1AIy)UCnr=@h{c9dipB;9^Z~Ez413l71A4!I zB2@^-2Kq+gOJS$O=JKk(tY7uHY!2thp@AWnU3TQcA>n{gbVQ63>@XS1gdzrUIdh@N z4>OtE@$q z$b+6zQ(Xfl_$eV|g5d?5qPzXsaFh_IW76=tb=4;EWIEy>;&X)MMOk%6HT&U_!3-~k zgNMRn4km$12`701$vyUr;bs_4RCHh9pwZ{m6p3e;9K#6`+U<8~lE^TBBxp#{`~l|R z_W0!6xeH65?esfUNnptL7)F#dC-DVcI^_u?*fe+E-D4!(MV5#lIXod%mo-8Zn@iCd z$KJoN_=AGT+c;s+C>#t91O-mQ5MRAW6laVVd5PnRLk&p!P{QvfZciv1iEFG^@u^OR zWCw>8O>^rmSrJ9MO|jW%deD|)(-qaOIUGKx*RDyA&y&=9@Ab=)CMz<2HAyB!liiv_ zQ+3s8S5?`qI#i@xcJ-nl;!{=#o+y_ti#$u)674^ohwOKlC*Xk*I0C17_u9PHpI>Rw zET@M$Viqq;%j9=v(nXTRW93czJi;h(iV=-?@G9jZv26Ybab}$4N&WIlzEH@oTz=dm z>X%+Tl}IKNr(XO`kGOL;Iu#C2Mf+p1{^BS5=xOH3Q)^8l#i!PqM(*x?J3jN}*?4h$ zZk$X_$7Ye99zQm|_XqL{#)*Bk^A`Ja>`_^_wpB}kG4DUuK|doi{>^D5-BXokFyoL5E_ z2lG7Ragax$m}hb>*dOMxtc#LnyUU9?3D@eTgmF$5MX(Iih(CZ+yVb ziLyghR6$`s{UFT-oXo3z())J72o&Bg`W?Zc?2JzpgMFgJ=(1$j6-jfezR*z7 z<)LQ;zy*J$e|^lcfWKXuV1He(Xa?V+&RR5!_{$c}Azij;9^XQ5ShRrn9gCJ>6uxEA zcC61Y=vxVA!+q|-?=6}@A31B$3~1z z#*EE1n!B4D>y?%K7rNrvX7g-$eY;xP+z;)im&%)48;!a#kx1=_kC*G^%~Gp;m2SUv zb3NT^tr=^ZjheAw?PD}I8`sLKtwg2OY93A|_wNsL(10fF!X|9MI#i$q2EHZC;hi=h zjqk8@8gKL<*+wh%px{UiCz`0+i-9Q1#Q zFB&3Y2unD^6M=|C0+pVrt;zBAMq|BN?z6a3t#qqVA1_tQJEiezW4+<*37XAn*+lFX gQod5!?MZKJZ>(Ow(r8@Y(k$s#rP172+ciD;550RWF#rGn literal 0 HcmV?d00001 diff --git a/fonts/wisetronic.ttf b/fonts/wisetronic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f6b6f81bd5a95fe475109a912ea3f47199bf8be1 GIT binary patch literal 2264 zcmd^AU2has7=F*pZWlWgyV%{W)Z(xM1=7-Pce^b?p!29h}ciKY|2;( zgGpSL&)`y(HD>Z`8{LDx9hR|flt@m%uAIQ6X1iqnthdRK245=y7*t#Sj?~aV*xGH@eGSLGA-WG%)(W^K%Efl zARJ^dAsu8~75BOVNG|#vzum&Gk?o3i1rW^-_kaei7WZQw?)wxncWU!}ikn9P^YhZj|Cz zO94eun9_8u)LAaoDfPkNb@p4G5-OLvO7opp%K;_GyrsUrV9W587WNIqa=G^klRmjL zBHg@nG=F5M)ah3yy9ehxeYLFN*bHL`87i?P&%jb}5I%?=UnnzeSt>4LJSefds}ZS~ zTF~`Vdo}-7wO&65*ij$eQKKI{91h2IU1v?Y{_%_ZG;QBayJKl+^{;SRXR)C-nzhws zc306mUR|Tx?2jMcemB^=dQWGI@6>n0hgB>3>T7I76J{dKElv9>9PT;q#5|Alu$6vr z&IItl`uPB}8Im|Fc))!$>S7uEX%~BdO&5FdwtmUQRp2kWxSE>jbr&o21bxJxXwPHF zGf%f&%&4A?x>%wuY|_Ot_!$>_fEQfsr65~!aTWN_TwG0K>{}Nr)Fid^Tlv{SdLm`3 zd;0gP(MU9+o|{!IQ0bhJQH?1(Wfh8QkDAO(*|u3oC#+m+!pgR&Nh@cYnT*Ay;n@L4 z-J8#kniEqQqfkjz;xV&OOj|j%y){xv51Ki%VA$q3PhXs#h}w2iO%|-II^gC}^95_t zOxUd{+s+?oYpcvp{bW&|W~o4FnxGWfq|zR+d$C6GuIE#wbFffh=~$&HM+RlU7&HZs zl+Y9*_h2TW;jE4O$L$l)=BQPyS-fqz1!uTEgP-+}ZWvhx9`f!*ZF!sz6SYl2V<6&2 zRvYnSqK+ae;aOE`N5060Q3he16CQ@Ba2y`a?u#^yDxzX%NwJFpB4&XG{<9wyHFMo0 y;v`_-D*9@JJwR>vZM6UO?=b)7K59rzVlvgeoGzMn!OEo*XK|*c%>r&dH~$;G0C=GQ literal 0 HcmV?d00001 diff --git a/lib/constants.dart b/lib/constants.dart new file mode 100644 index 0000000..cbb2a96 --- /dev/null +++ b/lib/constants.dart @@ -0,0 +1,8 @@ + +class Constants { + static const bool DEBUG = false; + static const BASE_API_URL = 'https://api.minipos.us/'; + static const String API_SECRET = 'pei326sami1223HellowWorldabcdEd'; + static const KEY_USER_ID = 'user_id'; + static const KEY_ACCESS_TOKEN = 'access_token'; +} \ No newline at end of file diff --git a/lib/events/eventbus.dart b/lib/events/eventbus.dart new file mode 100644 index 0000000..28ff482 --- /dev/null +++ b/lib/events/eventbus.dart @@ -0,0 +1,4 @@ + +import 'package:event_bus/event_bus.dart'; + +final eventBus = new EventBus(); \ No newline at end of file diff --git a/lib/events/events.dart b/lib/events/events.dart new file mode 100644 index 0000000..1bd8007 --- /dev/null +++ b/lib/events/events.dart @@ -0,0 +1,4 @@ + +class OpenDrawer { + +} \ No newline at end of file diff --git a/lib/generated/intl/messages_all.dart b/lib/generated/intl/messages_all.dart index b285749..531e7cd 100644 --- a/lib/generated/intl/messages_all.dart +++ b/lib/generated/intl/messages_all.dart @@ -16,16 +16,20 @@ import 'package:intl/message_lookup_by_library.dart'; import 'package:intl/src/intl_helpers.dart'; import 'messages_en.dart' as messages_en; +import 'messages_zh_CN.dart' as messages_zh_cn; typedef Future LibraryLoader(); Map _deferredLibraries = { 'en': () => new Future.value(null), + 'zh_CN': () => new Future.value(null), }; MessageLookupByLibrary _findExact(String localeName) { switch (localeName) { case 'en': return messages_en.messages; + case 'zh_CN': + return messages_zh_cn.messages; default: return null; } diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart index 26a77ab..90384e9 100644 --- a/lib/generated/intl/messages_en.dart +++ b/lib/generated/intl/messages_en.dart @@ -21,6 +21,35 @@ class MessageLookup extends MessageLookupByLibrary { final messages = _notInlinedMessages(_notInlinedMessages); static _notInlinedMessages(_) => { - + "about" : MessageLookupByLibrary.simpleMessage("About"), + "about_us" : MessageLookupByLibrary.simpleMessage("About us"), + "blog" : MessageLookupByLibrary.simpleMessage("Blog"), + "contact_us" : MessageLookupByLibrary.simpleMessage("Contact us"), + "developer_of" : MessageLookupByLibrary.simpleMessage("Developers of"), + "download" : MessageLookupByLibrary.simpleMessage("Download"), + "home" : MessageLookupByLibrary.simpleMessage("Home"), + "information" : MessageLookupByLibrary.simpleMessage("Information"), + "learn_more" : MessageLookupByLibrary.simpleMessage("Learn more..."), + "license_agreement" : MessageLookupByLibrary.simpleMessage("License agreement"), + "loading_please_wait" : MessageLookupByLibrary.simpleMessage("Loading, please wait..."), + "login" : MessageLookupByLibrary.simpleMessage("Login"), + "logout" : MessageLookupByLibrary.simpleMessage("Logout"), + "main_content_1" : MessageLookupByLibrary.simpleMessage("Since 1999, we have been committed to developing a complete and powerful sales system, helping thousands of small businesses handle sales smoothly. Currently we have two main products."), + "minipos" : MessageLookupByLibrary.simpleMessage("MiniPOS"), + "navigation" : MessageLookupByLibrary.simpleMessage("Navigation"), + "point_of_sale_system_solution" : MessageLookupByLibrary.simpleMessage("Point of sale system solution"), + "privacy_policy" : MessageLookupByLibrary.simpleMessage("Privacy policy"), + "recalculating" : MessageLookupByLibrary.simpleMessage("Recalculating..."), + "renew_license" : MessageLookupByLibrary.simpleMessage("Renew license"), + "return_policy" : MessageLookupByLibrary.simpleMessage("Return policy"), + "service_policy" : MessageLookupByLibrary.simpleMessage("Service policy"), + "shop" : MessageLookupByLibrary.simpleMessage("Shop"), + "submitting" : MessageLookupByLibrary.simpleMessage("Submitting..."), + "submitting_please_wait" : MessageLookupByLibrary.simpleMessage("Submitting, please wait..."), + "support" : MessageLookupByLibrary.simpleMessage("Support"), + "support_ticket" : MessageLookupByLibrary.simpleMessage("Support ticket"), + "tap_back_again_to_exit" : MessageLookupByLibrary.simpleMessage("Tap back again to exit"), + "tutorials" : MessageLookupByLibrary.simpleMessage("Tutorials"), + "wiki" : MessageLookupByLibrary.simpleMessage("Wiki") }; } diff --git a/lib/generated/intl/messages_zh_CN.dart b/lib/generated/intl/messages_zh_CN.dart new file mode 100644 index 0000000..6332746 --- /dev/null +++ b/lib/generated/intl/messages_zh_CN.dart @@ -0,0 +1,55 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a zh_CN locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'zh_CN'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static _notInlinedMessages(_) => { + "about" : MessageLookupByLibrary.simpleMessage("关于"), + "about_us" : MessageLookupByLibrary.simpleMessage("关于我们"), + "blog" : MessageLookupByLibrary.simpleMessage("博客"), + "contact_us" : MessageLookupByLibrary.simpleMessage("联系我们"), + "developer_of" : MessageLookupByLibrary.simpleMessage("开发者"), + "download" : MessageLookupByLibrary.simpleMessage("下载"), + "home" : MessageLookupByLibrary.simpleMessage("首页"), + "information" : MessageLookupByLibrary.simpleMessage("信息"), + "learn_more" : MessageLookupByLibrary.simpleMessage("了解更多..."), + "license_agreement" : MessageLookupByLibrary.simpleMessage("许可协议"), + "loading_please_wait" : MessageLookupByLibrary.simpleMessage("装载中,清稍候..."), + "login" : MessageLookupByLibrary.simpleMessage("登入"), + "logout" : MessageLookupByLibrary.simpleMessage("登出"), + "main_content_1" : MessageLookupByLibrary.simpleMessage("自从1999年来,我们一直致力于开发完整的强大的销售系统,帮助了上千小企业平滑的处理销售业务。当前我们有两个主要的产品。"), + "minipos" : MessageLookupByLibrary.simpleMessage("MiniPOS"), + "navigation" : MessageLookupByLibrary.simpleMessage("导航"), + "point_of_sale_system_solution" : MessageLookupByLibrary.simpleMessage("收款系统方案"), + "privacy_policy" : MessageLookupByLibrary.simpleMessage("私隐条款"), + "recalculating" : MessageLookupByLibrary.simpleMessage("运算中..."), + "renew_license" : MessageLookupByLibrary.simpleMessage("证书续期"), + "return_policy" : MessageLookupByLibrary.simpleMessage("退货条款"), + "service_policy" : MessageLookupByLibrary.simpleMessage("服务条款"), + "shop" : MessageLookupByLibrary.simpleMessage("线上购买"), + "submitting" : MessageLookupByLibrary.simpleMessage("提交中..."), + "submitting_please_wait" : MessageLookupByLibrary.simpleMessage("提交中,清稍候..."), + "support" : MessageLookupByLibrary.simpleMessage("技术支持"), + "support_ticket" : MessageLookupByLibrary.simpleMessage("客户提问"), + "tap_back_again_to_exit" : MessageLookupByLibrary.simpleMessage("再次点击返回退出"), + "tutorials" : MessageLookupByLibrary.simpleMessage("教程"), + "wiki" : MessageLookupByLibrary.simpleMessage("维基") + }; +} diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index eff322c..948a21e 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -35,7 +35,305 @@ class S { return Localizations.of(context, S); } + /// `About` + String get about { + return Intl.message( + 'About', + name: 'about', + desc: '', + args: [], + ); + } + /// `Navigation` + String get navigation { + return Intl.message( + 'Navigation', + name: 'navigation', + desc: '', + args: [], + ); + } + + /// `Submitting...` + String get submitting { + return Intl.message( + 'Submitting...', + name: 'submitting', + desc: '', + args: [], + ); + } + + /// `Submitting, please wait...` + String get submitting_please_wait { + return Intl.message( + 'Submitting, please wait...', + name: 'submitting_please_wait', + desc: '', + args: [], + ); + } + + /// `Recalculating...` + String get recalculating { + return Intl.message( + 'Recalculating...', + name: 'recalculating', + desc: '', + args: [], + ); + } + + /// `Loading, please wait...` + String get loading_please_wait { + return Intl.message( + 'Loading, please wait...', + name: 'loading_please_wait', + desc: '', + args: [], + ); + } + + /// `Tap back again to exit` + String get tap_back_again_to_exit { + return Intl.message( + 'Tap back again to exit', + name: 'tap_back_again_to_exit', + desc: '', + args: [], + ); + } + + /// `Since 1999, we have been committed to developing a complete and powerful sales system, helping thousands of small businesses handle sales smoothly. Currently we have two main products.` + String get main_content_1 { + return Intl.message( + 'Since 1999, we have been committed to developing a complete and powerful sales system, helping thousands of small businesses handle sales smoothly. Currently we have two main products.', + name: 'main_content_1', + desc: '', + args: [], + ); + } + + /// `MiniPOS` + String get minipos { + return Intl.message( + 'MiniPOS', + name: 'minipos', + desc: '', + args: [], + ); + } + + /// `Point of sale system solution` + String get point_of_sale_system_solution { + return Intl.message( + 'Point of sale system solution', + name: 'point_of_sale_system_solution', + desc: '', + args: [], + ); + } + + /// `Learn more...` + String get learn_more { + return Intl.message( + 'Learn more...', + name: 'learn_more', + desc: '', + args: [], + ); + } + + /// `Information` + String get information { + return Intl.message( + 'Information', + name: 'information', + desc: '', + args: [], + ); + } + + /// `Service policy` + String get service_policy { + return Intl.message( + 'Service policy', + name: 'service_policy', + desc: '', + args: [], + ); + } + + /// `Return policy` + String get return_policy { + return Intl.message( + 'Return policy', + name: 'return_policy', + desc: '', + args: [], + ); + } + + /// `Privacy policy` + String get privacy_policy { + return Intl.message( + 'Privacy policy', + name: 'privacy_policy', + desc: '', + args: [], + ); + } + + /// `License agreement` + String get license_agreement { + return Intl.message( + 'License agreement', + name: 'license_agreement', + desc: '', + args: [], + ); + } + + /// `Support` + String get support { + return Intl.message( + 'Support', + name: 'support', + desc: '', + args: [], + ); + } + + /// `Wiki` + String get wiki { + return Intl.message( + 'Wiki', + name: 'wiki', + desc: '', + args: [], + ); + } + + /// `Support ticket` + String get support_ticket { + return Intl.message( + 'Support ticket', + name: 'support_ticket', + desc: '', + args: [], + ); + } + + /// `Contact us` + String get contact_us { + return Intl.message( + 'Contact us', + name: 'contact_us', + desc: '', + args: [], + ); + } + + /// `About us` + String get about_us { + return Intl.message( + 'About us', + name: 'about_us', + desc: '', + args: [], + ); + } + + /// `Renew license` + String get renew_license { + return Intl.message( + 'Renew license', + name: 'renew_license', + desc: '', + args: [], + ); + } + + /// `Developers of` + String get developer_of { + return Intl.message( + 'Developers of', + name: 'developer_of', + desc: '', + args: [], + ); + } + + /// `Home` + String get home { + return Intl.message( + 'Home', + name: 'home', + desc: '', + args: [], + ); + } + + /// `Download` + String get download { + return Intl.message( + 'Download', + name: 'download', + desc: '', + args: [], + ); + } + + /// `Tutorials` + String get tutorials { + return Intl.message( + 'Tutorials', + name: 'tutorials', + desc: '', + args: [], + ); + } + + /// `Shop` + String get shop { + return Intl.message( + 'Shop', + name: 'shop', + desc: '', + args: [], + ); + } + + /// `Blog` + String get blog { + return Intl.message( + 'Blog', + name: 'blog', + desc: '', + args: [], + ); + } + + /// `Login` + String get login { + return Intl.message( + 'Login', + name: 'login', + desc: '', + args: [], + ); + } + + /// `Logout` + String get logout { + return Intl.message( + 'Logout', + name: 'logout', + desc: '', + args: [], + ); + } } class AppLocalizationDelegate extends LocalizationsDelegate { @@ -44,6 +342,7 @@ class AppLocalizationDelegate extends LocalizationsDelegate { List get supportedLocales { return const [ Locale.fromSubtags(languageCode: 'en'), + Locale.fromSubtags(languageCode: 'zh', countryCode: 'CN'), ]; } diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 9e26dfe..36ada03 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -1 +1,32 @@ -{} \ No newline at end of file +{ + "about": "About", + "navigation": "Navigation", + "submitting": "Submitting...", + "submitting_please_wait": "Submitting, please wait...", + "recalculating": "Recalculating...", + "loading_please_wait": "Loading, please wait...", + "tap_back_again_to_exit": "Tap back again to exit", + "main_content_1": "Since 1999, we have been committed to developing a complete and powerful sales system, helping thousands of small businesses handle sales smoothly. Currently we have two main products.", + "minipos": "MiniPOS", + "point_of_sale_system_solution": "Point of sale system solution", + "learn_more": "Learn more...", + "information": "Information", + "service_policy": "Service policy", + "return_policy": "Return policy", + "privacy_policy": "Privacy policy", + "license_agreement": "License agreement", + "support": "Support", + "wiki": "Wiki", + "support_ticket": "Support ticket", + "contact_us": "Contact us", + "about_us": "About us", + "renew_license": "Renew license", + "developer_of": "Developers of", + "home": "Home", + "download": "Download", + "tutorials": "Tutorials", + "shop": "Shop", + "blog": "Blog", + "login": "Login", + "logout": "Logout" +} \ No newline at end of file diff --git a/lib/l10n/intl_zh_CN.arb b/lib/l10n/intl_zh_CN.arb new file mode 100644 index 0000000..3a202bf --- /dev/null +++ b/lib/l10n/intl_zh_CN.arb @@ -0,0 +1,32 @@ +{ + "about": "关于", + "navigation": "导航", + "submitting": "提交中...", + "submitting_please_wait": "提交中,清稍候...", + "recalculating": "运算中...", + "loading_please_wait": "装载中,清稍候...", + "tap_back_again_to_exit": "再次点击返回退出", + "main_content_1": "自从1999年来,我们一直致力于开发完整的强大的销售系统,帮助了上千小企业平滑的处理销售业务。当前我们有两个主要的产品。", + "minipos": "MiniPOS", + "point_of_sale_system_solution": "收款系统方案", + "learn_more": "了解更多...", + "information": "信息", + "service_policy": "服务条款", + "return_policy": "退货条款", + "privacy_policy": "私隐条款", + "license_agreement": "许可协议", + "support": "技术支持", + "wiki": "维基", + "support_ticket": "客户提问", + "contact_us": "联系我们", + "about_us": "关于我们", + "renew_license": "证书续期", + "developer_of": "开发者", + "home": "首页", + "download": "下载", + "tutorials": "教程", + "shop": "线上购买", + "blog": "博客", + "login": "登入", + "logout": "登出" +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index d8a0526..62b5686 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,113 +1,87 @@ +import 'package:catcher/catcher.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_device_locale/flutter_device_locale.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_redux/flutter_redux.dart'; +import 'package:flutter_wisetronic/events/events.dart'; +import 'package:flutter_wisetronic/routes.dart'; +import 'package:flutter_wisetronic/store/actions.dart'; +import 'package:flutter_wisetronic/widgets/general/navigationbar.dart'; +import 'package:flutter_wisetronic/widgets/mobile/mobile_navigation_drawer.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:responsive_builder/responsive_builder.dart'; +import 'package:splashscreen/splashscreen.dart'; -void main() { - runApp(MyApp()); +import 'constants.dart'; +import 'events/eventbus.dart'; +import 'generated/l10n.dart'; +import 'pages/home.dart'; +import 'store/store.dart'; + +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + Locale locale = await DeviceLocale.getCurrentLocale(); + + runApp(MyApp(locale)); } class MyApp extends StatelessWidget { + final Locale localLocate; + + MyApp(this.localLocate) { + Routes.configure(); + store.dispatch(UpdateLocale(localLocate)); + } + // This widget is the root of your application. @override Widget build(BuildContext context) { + Widget _buildBody() { + return SplashScreen( + seconds: 5, + routeName: '/', + navigateAfterSeconds: Home(localLocate, title: 'Welcome',), + styleTextUnderTheLoader: new TextStyle( + fontWeight: FontWeight.bold, + fontSize: 20.0, + ), + // imageBackground: (Image.network(Constants.BASE_API_URL + 'gallery/get-wisetronic-slpash')).image, + imageBackground: (new Image.network(Constants.BASE_API_URL + 'gallery/get-minimanager-splash/')).image, + backgroundColor: Colors.white, + onClick: () { + + }, + loaderColor: Colors.blue, + ); + } + return MaterialApp( - title: 'Flutter Demo', + debugShowCheckedModeBanner: Constants.DEBUG, + navigatorKey: kIsWeb ? null : Catcher.navigatorKey, + localizationsDelegates: [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + RefreshLocalizations.delegate, + S.delegate, + ], + supportedLocales: S.delegate.supportedLocales, + localeResolutionCallback: (Locale locale, Iterable supportedLocales) { + print('Language code: ${localLocate.languageCode}'); + for (final supportedLocale in supportedLocales) { + return supportedLocale; + } + return supportedLocales.first; + }, + title: 'Wisetronic Inc.', theme: ThemeData( - // This is the theme of your application. - // - // Try running your application with "flutter run". You'll see the - // application has a blue toolbar. Then, without quitting the app, try - // changing the primarySwatch below to Colors.green and then invoke - // "hot reload" (press "r" in the console where you ran "flutter run", - // or simply save your changes to "hot reload" in a Flutter IDE). - // Notice that the counter didn't reset back to zero; the application - // is not restarted. primarySwatch: Colors.blue, ), - home: MyHomePage(title: 'Flutter Demo Home Page'), - ); - } -} - -class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); - - // This widget is the home page of your application. It is stateful, meaning - // that it has a State object (defined below) that contains fields that affect - // how it looks. - - // This class is the configuration for the state. It holds the values (in this - // case the title) provided by the parent (in this case the App widget) and - // used by the build method of the State. Fields in a Widget subclass are - // always marked "final". - - final String title; - - @override - _MyHomePageState createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - int _counter = 0; - - void _incrementCounter() { - setState(() { - // This call to setState tells the Flutter framework that something has - // changed in this State, which causes it to rerun the build method below - // so that the display can reflect the updated values. If we changed - // _counter without calling setState(), then the build method would not be - // called again, and so nothing would appear to happen. - _counter++; - }); - } - - @override - Widget build(BuildContext context) { - // This method is rerun every time setState is called, for instance as done - // by the _incrementCounter method above. - // - // The Flutter framework has been optimized to make rerunning build methods - // fast, so that you can just rebuild anything that needs updating rather - // than having to individually change instances of widgets. - return Scaffold( - appBar: AppBar( - // Here we take the value from the MyHomePage object that was created by - // the App.build method, and use it to set our appbar title. - title: Text(widget.title), - ), - body: Center( - // Center is a layout widget. It takes a single child and positions it - // in the middle of the parent. - child: Column( - // Column is also a layout widget. It takes a list of children and - // arranges them vertically. By default, it sizes itself to fit its - // children horizontally, and tries to be as tall as its parent. - // - // Invoke "debug painting" (press "p" in the console, choose the - // "Toggle Debug Paint" action from the Flutter Inspector in Android - // Studio, or the "Toggle Debug Paint" command in Visual Studio Code) - // to see the wireframe for each widget. - // - // Column has various properties to control how it sizes itself and - // how it positions its children. Here we use mainAxisAlignment to - // center the children vertically; the main axis here is the vertical - // axis because Columns are vertical (the cross axis would be - // horizontal). - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'You have pushed the button this many times:', - ), - Text( - '$_counter', - style: Theme.of(context).textTheme.headline4, - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: _incrementCounter, - tooltip: 'Increment', - child: Icon(Icons.add), - ), // This trailing comma makes auto-formatting nicer for build methods. + home: StoreProvider( + store: store, + child: _buildBody(), + ), ); } } diff --git a/lib/models/gallery.dart b/lib/models/gallery.dart new file mode 100644 index 0000000..47358d1 --- /dev/null +++ b/lib/models/gallery.dart @@ -0,0 +1,24 @@ + +import 'dart:convert'; + +class Gallery { + int id; + String image; + String linkUrl; + + Gallery.fromJson(Map json) + : id = json['id'], + image = json['image'], + linkUrl = json['link_url']; + + Map toJson() => { + 'id': id, + 'image': image, + 'link_url': linkUrl + }; + + @override + String toString() { + return json.encode(this); + } +} \ No newline at end of file diff --git a/lib/models/stripe_payment_method.dart b/lib/models/stripe_payment_method.dart new file mode 100644 index 0000000..1286035 --- /dev/null +++ b/lib/models/stripe_payment_method.dart @@ -0,0 +1,46 @@ + +import 'dart:convert'; + +class StripePaymentMethod { + int id; + String customerId; + String paymentMethodId; + String paymentMethodType; + String cardBrand; + String cardCountry; + int cardExpMonth; + int cardExpYear; + String cardFunding; + String cardLast4; + + StripePaymentMethod.fromJson(Map json) : + id = json['id'], + customerId = json['customer_id'], + paymentMethodId = json['payment_method_id'], + paymentMethodType = json['payment_method_type'], + cardBrand = json['card_brand'], + cardCountry = json['card_country'], + cardExpMonth = json['card_exp_month'], + cardExpYear = json['card_exp_year'], + cardFunding = json['card_funding'], + cardLast4 = json['card_last4']; + + Map toJson() => { + 'id': id, + 'customer_id': customerId, + 'payment_method_id': paymentMethodId, + 'payment_method_type': paymentMethodType, + 'card_brand': cardBrand, + 'card_country': cardCountry, + 'card_exp_month': cardExpMonth, + 'card_exp_year': cardExpYear, + 'card_funding': cardFunding, + 'card_last4': cardLast4, + }; + + @override + String toString() { + return json.encode(this); + } + +} \ No newline at end of file diff --git a/lib/models/user.dart b/lib/models/user.dart new file mode 100644 index 0000000..e532ade --- /dev/null +++ b/lib/models/user.dart @@ -0,0 +1,68 @@ + +import 'dart:convert'; + +import 'stripe_payment_method.dart'; + +class User { + int id; + String username; + String nickname; + String mobile; + String email; + String avatarUrl; + int lastAddressId; + String passCode; + double credit; + double wallet; + int coupon; + int points; + int orderNum; + double pointsToCreditsConversionRate; + String contactNumber; + String flutterMiniStoreToken; + List stripePaymentMethods; + + User.fromJson(Map json) + : id = json['id'], + username = json['username'], + nickname = json['nickname'], + mobile = json['mobile'], + email = json['email'], + avatarUrl = json['avatar_url'], + lastAddressId = json['last_address_id'], + passCode = json['pass_code'], + credit = double.parse(json['credit'].toString()), + wallet = double.parse((json['wallet'] == null) ? "0": json['wallet'].toString()), + coupon = json['coupon'], + points = json['points'], + orderNum = json['order_num'], + pointsToCreditsConversionRate = double.parse(json['points_to_credits_conversion_rate'].toString()), + contactNumber = json['contact_number'], + flutterMiniStoreToken = json['flutter_ministore_token'], + stripePaymentMethods = (json['stripe_payment_methods'] as List).map((e) => StripePaymentMethod.fromJson(e)).toList(); + + Map toJson() => { + 'id': id, + 'username': username, + 'nickname': nickname, + 'mobile': mobile, + 'email': email, + 'avatar_url': avatarUrl, + 'last_address_id': lastAddressId, + 'pass_code': passCode, + 'credit': credit, + 'wallet': wallet, + 'coupon': coupon, + 'points': points, + 'order_num': orderNum, + 'points_to_credits_conversion_rate': pointsToCreditsConversionRate, + 'contact_number': contactNumber, + 'flutter_ministore_token': flutterMiniStoreToken, + 'stripe_payment_methods': stripePaymentMethods, + }; + + @override + String toString() { + return json.encode(this); + } +} \ No newline at end of file diff --git a/lib/pages/home.dart b/lib/pages/home.dart new file mode 100644 index 0000000..31bcaee --- /dev/null +++ b/lib/pages/home.dart @@ -0,0 +1,96 @@ + + +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/models/gallery.dart'; +import '../widgets/general/bottom_nav.dart'; +import '../widgets/general/index_carousel.dart'; +import '../widgets/general/index_main_content_1.dart'; +import '../widgets/general/index_main_content_2.dart'; +import '../widgets/general/index_main_content_3.dart'; +import '../events/eventbus.dart'; +import '../events/events.dart'; +import '../generated/l10n.dart'; +import '../store/actions.dart'; +import '../store/store.dart'; +import '../utils/http_util.dart'; +import '../utils/double_back_to_close_app.dart'; +import '../widgets/general/navigationbar.dart'; +import '../widgets/mobile/mobile_navigation_drawer.dart'; +import 'package:responsive_builder/responsive_builder.dart'; + +class Home extends StatefulWidget { + final Locale locale; + final String title; + + Home(this.locale, {Key key, this.title}) : super(key: key); + + @override + State createState() { + return HomeState(); + } + +} + +class HomeState extends State { + final _scaffoldKey = GlobalKey(); + List galleries = []; + String content1Message = ''; + Map content2; + + @override + Widget build(BuildContext context) { + store.dispatch(UpdateContext(context)); + + return ResponsiveBuilder( + builder: (context, sizingInformation) => + Scaffold( + key: _scaffoldKey, + appBar: NavigationBar(), + drawer: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? MobileNavigationDrawer() : null, + body: DoubleBackToCloseApp( + snackBar: SnackBar( + content: Text(S.of(context).tap_back_again_to_exit), + ), + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + IndexCarousel(galleries), + IndexMainContent1(content1Message), + IndexMainContent2(content2), + IndexMainContent3(content2), + ], + ), + ), + ), + bottomNavigationBar: BottomNav(), + ), + ); + } + + @override + void initState() { + super.initState(); + _loadData(); + eventBus.on().listen((event) { + if (mounted) { + _scaffoldKey.currentState.openDrawer(); + } + }); + + } + + void _loadData() { + HttpUtil.httpGet('v1/get-wisetronic-index-carousel') + .then((value) { + print('$value'); + if (mounted) { + setState(() { + galleries = (value['index_carousel'] as List).map((i) => Gallery.fromJson(i)).toList(); + content1Message = value['content']['index_content_1']; + content2 = value['content']['index_content_2']; + }); + } + }); + } +} \ No newline at end of file diff --git a/lib/routes.dart b/lib/routes.dart new file mode 100644 index 0000000..778a059 --- /dev/null +++ b/lib/routes.dart @@ -0,0 +1,16 @@ + +import 'package:fluro/fluro.dart'; +import 'package:flutter/material.dart'; + +class Routes { + static final router = FluroRouter(); + + static void configure() { + router.define('/', handler: new Handler( + handlerFunc: (BuildContext context, Map> params) { + return null; + }), + transitionType: TransitionType.fadeIn + ); + } +} \ No newline at end of file diff --git a/lib/store/actions.dart b/lib/store/actions.dart new file mode 100644 index 0000000..9716b02 --- /dev/null +++ b/lib/store/actions.dart @@ -0,0 +1,18 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/models/user.dart'; + +class UpdateContext { + final BuildContext context; + UpdateContext(this.context); +} + +class UpdateLocale { + final Locale locale; + UpdateLocale(this.locale); +} + +class UpdateCurrentUser { + final User user; + UpdateCurrentUser(this.user); +} \ No newline at end of file diff --git a/lib/store/reducer/app_reducer.dart b/lib/store/reducer/app_reducer.dart new file mode 100644 index 0000000..deec659 --- /dev/null +++ b/lib/store/reducer/app_reducer.dart @@ -0,0 +1,13 @@ + +import 'package:flutter_wisetronic/store/reducer/context_reducer.dart'; +import 'package:flutter_wisetronic/store/reducer/locale_reducer.dart'; +import 'package:flutter_wisetronic/store/reducer/user_reducer.dart'; +import 'package:flutter_wisetronic/store/state/app_state.dart'; + +AppState appReducer(AppState state, action) { + return AppState( + context: contextReducer(state.context, action), + locale: localeReducer(state.locale, action), + user: userReducer(state.user, action), + ); +} \ No newline at end of file diff --git a/lib/store/reducer/context_reducer.dart b/lib/store/reducer/context_reducer.dart new file mode 100644 index 0000000..586d72c --- /dev/null +++ b/lib/store/reducer/context_reducer.dart @@ -0,0 +1,12 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/store/actions.dart'; +import 'package:redux/redux.dart'; + +final contextReducer = combineReducers([ + TypedReducer(_updateContext) +]); + +BuildContext _updateContext(BuildContext context, action) { + return action.context; +} \ No newline at end of file diff --git a/lib/store/reducer/locale_reducer.dart b/lib/store/reducer/locale_reducer.dart new file mode 100644 index 0000000..d27f351 --- /dev/null +++ b/lib/store/reducer/locale_reducer.dart @@ -0,0 +1,11 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/store/actions.dart'; +import 'package:redux/redux.dart'; + +final localeReducer = combineReducers([ + TypedReducer(_updateLocale) +]); + +Locale _updateLocale(Locale locale, action) { + return action.locale; +} \ No newline at end of file diff --git a/lib/store/reducer/user_reducer.dart b/lib/store/reducer/user_reducer.dart new file mode 100644 index 0000000..d15912d --- /dev/null +++ b/lib/store/reducer/user_reducer.dart @@ -0,0 +1,13 @@ + +import 'package:redux/redux.dart'; +import 'package:flutter_wisetronic/models/user.dart'; + +import '../actions.dart'; + +final userReducer = combineReducers([ + TypedReducer(_updateCurrentUser) +]); + +User _updateCurrentUser(User user, action) { + return action.user; +} \ No newline at end of file diff --git a/lib/store/state/app_state.dart b/lib/store/state/app_state.dart new file mode 100644 index 0000000..f9c1e61 --- /dev/null +++ b/lib/store/state/app_state.dart @@ -0,0 +1,42 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/models/user.dart'; + +@immutable +class AppState { + final BuildContext context; + final Locale locale; + final User user; + + AppState({this.context, this.locale, this.user}); + + factory AppState.init() => AppState(); + + AppState copyWith({ + BuildContext context, + Locale locale}) { + return AppState( + context: context ?? this.context, + locale: locale ?? this.locale, + user: user ?? this.user, + ); + } + + @override + int get hashCode => + context.hashCode ^ + locale.hashCode ^ + user.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is AppState && + context == other.context && + locale == other.locale && + user == other.user; + + @override + String toString() => + 'AppState(context: $context, locale: $locale), user: $user'; +} \ No newline at end of file diff --git a/lib/store/store.dart b/lib/store/store.dart new file mode 100644 index 0000000..08da714 --- /dev/null +++ b/lib/store/store.dart @@ -0,0 +1,9 @@ + +import 'package:flutter_wisetronic/store/reducer/app_reducer.dart'; +import 'package:redux/redux.dart'; +import 'state/app_state.dart'; + +final store = Store( + appReducer, + initialState: AppState.init(), +); \ No newline at end of file diff --git a/lib/utils/double_back_to_close_app.dart b/lib/utils/double_back_to_close_app.dart new file mode 100644 index 0000000..b39eee3 --- /dev/null +++ b/lib/utils/double_back_to_close_app.dart @@ -0,0 +1,98 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; + +/// Allows the user to close the app by double tapping the back-button. +/// +/// You must specify a [SnackBar], so it can be shown when the user taps the +/// back-button. Notice that the value you set for [SnackBar.duration] is going +/// to be considered to decide whether the snack-bar is currently visible or +/// not. +/// +/// Since the back-button is an Android feature, this Widget is going to be +/// nothing but the own [child] if the current platform is anything but Android. +class DoubleBackToCloseApp extends StatefulWidget { + /// The [SnackBar] shown when the user taps the back-button. + final SnackBar snackBar; + + /// The widget below this widget in the tree. + final Widget child; + + /// Creates a widget that allows the user to close the app by double tapping + /// the back-button. + const DoubleBackToCloseApp({ + Key key, + @required this.snackBar, + @required this.child, + }) : assert(snackBar != null), + assert(child != null), + super(key: key); + + @override + _DoubleBackToCloseAppState createState() => _DoubleBackToCloseAppState(); +} + +class _DoubleBackToCloseAppState extends State { + /// The last time the user tapped Android's back-button. + DateTime _lastTimeBackButtonWasTapped; + + /// Returns whether the current platform is Android. + bool get _isAndroid => Theme.of(context).platform == TargetPlatform.android; + + /// Returns whether the [DoubleBackToCloseApp.snackBar] is currently visible. + /// + /// The snack-bar is going to be considered visible if the duration of the + /// snack-bar is greater than the difference from now to the + /// [_lastTimeBackButtonWasTapped]. + /// + /// This is not quite accurate since the snack-bar could've been dismissed by + /// the user, so this algorithm needs to be improved, as described in #2. + bool get _isSnackBarVisible => + (_lastTimeBackButtonWasTapped != null) && + (widget.snackBar.duration > + DateTime.now().difference(_lastTimeBackButtonWasTapped)); + + /// Returns whether the next back navigation of this route will be handled + /// internally. + /// + /// Returns true when there's a widget that inserted an entry into the + /// local-history of the current route, in order to handle pop. This is done + /// by [Drawer], for example, so it can close on pop. + bool get _willHandlePopInternally => + ModalRoute.of(context).willHandlePopInternally; + + @override + Widget build(BuildContext context) { + _ensureThatContextContainsScaffold(); + + if (_isAndroid) { + return WillPopScope( + onWillPop: _handleWillPop, + child: widget.child, + ); + } else { + return widget.child; + } + } + + /// Handles [WillPopScope.onWillPop]. + Future _handleWillPop() async { + if (_isSnackBarVisible || _willHandlePopInternally) { + return true; + } else { + _lastTimeBackButtonWasTapped = DateTime.now(); + // Scaffold.of(context).showSnackBar(widget.snackBar); + ScaffoldMessenger.of(context).showSnackBar(widget.snackBar); + return false; + } + } + + /// Throws a [FlutterError] if this widget was not wrapped in a [Scaffold]. + void _ensureThatContextContainsScaffold() { + if (Scaffold.maybeOf(context) == null) { + throw FlutterError( + '`DoubleBackToCloseApp` must be wrapped in a `Scaffold`.', + ); + } + } +} \ No newline at end of file diff --git a/lib/utils/http_util.dart b/lib/utils/http_util.dart new file mode 100644 index 0000000..9e942e9 --- /dev/null +++ b/lib/utils/http_util.dart @@ -0,0 +1,370 @@ + + +import 'dart:async'; +import 'dart:convert'; + +import 'package:crypto/crypto.dart'; +import 'package:dio/dio.dart'; +import '../store/store.dart'; +import 'utils.dart'; +import 'package:hive/hive.dart'; +import 'package:universal_io/io.dart'; + +import '../constants.dart'; + +typedef void PostCallback(Response response); + +String generateSignature(String string, {String key}) { + if (key == null) { + key = Constants.API_SECRET; + } + Hmac mac = new Hmac(sha256, utf8.encode(key)); + Digest digest = mac.convert(utf8.encode(string + key)); + String base64Mac = base64.encode(utf8.encode("$digest")); + return base64Mac; +} + +class HttpUtil { + static String platformName = Utils.getPlatformName(); + + static final Map headers = { + 'Accept': 'application/json', +// 'Content-Type': 'application/json', + 'Http-Signature': '', +// 'Http-Group-Id': Constants.GROUP_ID, + 'Http-Business-Id': '0', + 'Http-App-Key': '', + 'Http-Contact-Authorization': '', + 'Http-Device-Type': Platform.isIOS ? 'ios' : (Platform.isAndroid ? 'android' : 'web'), + 'Http-Api-Branch': 'flutter', + 'Http-Language-Code': store.state.locale.languageCode, + }; + + static Future httpGet(String url, + { + Map queryParameters, + int businessId = 0, + Function(int, int) receiveProgress, + bool returnError = false, + Map additionalHeaders, + }) async { + Map localHeaders = json.decode(json.encode(headers)); + if (additionalHeaders != null) { + localHeaders.addAll(additionalHeaders); + } + + if (!url.startsWith('http')) { + localHeaders['Http-Signature'] = generateSignature(url); + } + + localHeaders['Http-Business-Id'] = businessId.toString(); + Box box = await Utils.getBox(); + localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: ''); + localHeaders['Http-App-Key'] = platformName; + localHeaders['Http-Device-Type'] = platformName; + String requestUrl = Constants.BASE_API_URL + url; + + if (url.startsWith('http')) { + requestUrl = url; + } + + Utils.jsonPrettyPrint(queryParameters); + + Dio dio = Dio(); + try { + Response response = await dio.get(requestUrl, + queryParameters: queryParameters, + options: Options( + headers: localHeaders + ), + onReceiveProgress: receiveProgress, + ).timeout(const Duration(seconds: 30)); + + print('HttpGet success. Request: $requestUrl, Response: ${response.statusCode}, Headers: ${response.request.headers}'); +// print(response.data); +// Utils.jsonPrettyPrint(response.data); + + int statusCode = response.statusCode; + return response.data; + } on DioError catch(e) { + print('error $e'); + if (returnError) { + return e; + } + throw e; + } + } + + static Future httpPost(String url, PostCallback callback, + { + Map queryParameters, + int businessId = 0, + bool isFormData = false, + Map additionalHeaders, + Map body, + Function(int, int) sendProgress, + Function(int, int) receiveProgress, + bool returnError = false, + }) async { + + Map localHeaders = json.decode(json.encode(headers)); + if (additionalHeaders != null) { + localHeaders.addAll(additionalHeaders); + } + if (!url.startsWith('http')) { + localHeaders['Http-Signature'] = generateSignature(url); + } + localHeaders['Http-Business-Id'] = businessId.toString(); + Box box = await Utils.getBox(); + localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: ''); + localHeaders['Http-App-Key'] = platformName; + localHeaders['Http-Device-Type'] = platformName; + + String requestUrl = Constants.BASE_API_URL + url; + if (url.startsWith('http')) { + requestUrl = url; + } + + // Don't print body will cause upload Multipart file failed + //Utils.jsonPrettyPrint(body); + + Dio dio = Dio(); + dio.interceptors.add(LogInterceptor()); + try { + Response response = await dio.post( + requestUrl, + queryParameters: queryParameters == null ? {} : queryParameters, + data: isFormData ? FormData.fromMap(body) : json.encode(body), + options: Options( + headers: localHeaders, +// contentType: isFormData ? Headers.formUrlEncodedContentType : Headers.jsonContentType, + ), + onSendProgress: sendProgress, + onReceiveProgress: receiveProgress, + ).timeout(Duration(seconds: 30)); + + print('HttpPost Success. Request: ${response.request.uri}, Response: ${response.statusCode}, Headers: ${response.request.headers}'); +// Utils.jsonPrettyPrint(response.data); + + int statusCode = response.statusCode; + if (callback != null) { + callback(response); + } + return response.data; + } on DioError catch(e) { + if (e.response != null) { + print('HttpPost failed. Request: ${e.request.uri}, Headers: ${e.response.request.headers}'); + try { + Utils.jsonPrettyPrint(e.response.data); + } catch (err) { + print(e.response.data); + } + } + if (returnError) { + return e; + } + throw e; + } + } + + static Future httpPut(String url, PostCallback callback, + { + Map queryParameters, + int businessId = 0, + Map additionalHeaders, + Map body, + Function(int, int) sendProgress, + Function(int, int) receiveProgress, + bool returnError = false, + }) async { + + Map localHeaders = json.decode(json.encode(headers)); + if (additionalHeaders != null) { + localHeaders.addAll(additionalHeaders); + } + + if (!url.startsWith('http')) { + localHeaders['Http-Signature'] = generateSignature(url); + } + + localHeaders['Http-Business-Id'] = businessId.toString(); + Box box = await Utils.getBox(); + localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: ''); + localHeaders['Http-App-Key'] = platformName; + localHeaders['Http-Device-Type'] = platformName; + + localHeaders['Content-Type'] = Headers.jsonContentType; + + String requestUrl = Constants.BASE_API_URL + url; + + if (url.startsWith('http')) { + requestUrl = url; + } + + Dio dio = Dio(); + try { + Response response = await dio.put( + requestUrl, + queryParameters: queryParameters == null ? {} : queryParameters, + data: json.encode(body), + options: Options( + headers: localHeaders, + ), + onSendProgress: sendProgress, + onReceiveProgress: receiveProgress, + ).timeout(Duration(seconds: 30)); + + print('HttpPost Success. Request: ${response.request.uri}, Response: ${response.statusCode}, Headers: ${response.request.headers}'); +// Utils.jsonPrettyPrint(response.data); + + int statusCode = response.statusCode; + if (callback != null) { + callback(response); + } + return response.data; + } on DioError catch(e) { + print('HttpPost failed. Request: ${e.request.uri}'); + if (e.response != null) { + Utils.jsonPrettyPrint(e.response.data); + } + if (returnError) { + return e; + } + throw e; + } + } + + static Future httpPatch(String url, PostCallback callback, + { + Map queryParameters, + int businessId = 0, + Map additionalHeaders, + Map body, + Function(int, int) sendProgress, + Function(int, int) receiveProgress, + bool returnError = false, + }) async { + + Map localHeaders = json.decode(json.encode(headers)); + if (additionalHeaders != null) { + localHeaders.addAll(additionalHeaders); + } + + if (!url.startsWith('http')) { + localHeaders['Http-Signature'] = generateSignature(url); + } + + localHeaders['Http-Business-Id'] = businessId.toString(); + Box box = await Utils.getBox(); + localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: ''); + localHeaders['Http-App-Key'] = platformName; + localHeaders['Http-Device-Type'] = platformName; + + localHeaders['Content-Type'] = Headers.jsonContentType; + + String requestUrl = Constants.BASE_API_URL + url; + + if (url.startsWith('http')) { + requestUrl = url; + } + + Utils.jsonPrettyPrint(body); + + Dio dio = Dio(); + try { + Response response = await dio.patch( + requestUrl, + queryParameters: queryParameters == null ? {} : queryParameters, + data: json.encode(body), + options: Options( + headers: localHeaders, + ), + onSendProgress: sendProgress, + onReceiveProgress: receiveProgress, + ).timeout(Duration(seconds: 30)); + + print('HttpPost Success. Request: ${response.request.uri}, Response: ${response.statusCode}, Headers: ${response.request.headers}'); +// Utils.jsonPrettyPrint(response.data); + + int statusCode = response.statusCode; + if (callback != null) { + callback(response); + } + return response.data; + } on DioError catch(e) { + print('HttpPost failed. Request: ${e.request.uri}'); + if (e.response != null) { + Utils.jsonPrettyPrint(e.response.data); + } + if (returnError) { + return e; + } + throw e; + } + } + + static Future httpDelete(String url, PostCallback callback, + { + Map queryParameters, + int businessId = 0, + Map additionalHeaders, + Map body, + bool returnError = false, + }) async { + + Map localHeaders = json.decode(json.encode(headers)); + if (additionalHeaders != null) { + localHeaders.addAll(additionalHeaders); + } + + if (!url.startsWith('http')) { + localHeaders['Http-Signature'] = generateSignature(url); + } + + localHeaders['Http-Business-Id'] = businessId.toString(); + Box box = await Utils.getBox(); + localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: ''); + localHeaders['Http-App-Key'] = platformName; + localHeaders['Http-Device-Type'] = platformName; + + localHeaders['Content-Type'] = Headers.jsonContentType; + + String requestUrl = Constants.BASE_API_URL + url; + + if (url.startsWith('http')) { + requestUrl = url; + } + + Utils.jsonPrettyPrint(body); + + Dio dio = Dio(); + try { + Response response = await dio.delete( + requestUrl, + queryParameters: queryParameters == null ? {} : queryParameters, + data: json.encode(body), + options: Options( + headers: localHeaders, + ), + ).timeout(Duration(seconds: 30)); + + print('HttpPost Success. Request: ${response.request.uri}, Response: ${response.statusCode}, Headers: ${response.request.headers}'); +// Utils.jsonPrettyPrint(response.data); + + int statusCode = response.statusCode; + if (callback != null) { + callback(response); + } + return response.data; + } on DioError catch(e) { + print('HttpPost failed. Request: ${e.request.uri}'); + if (e.response != null) { + Utils.jsonPrettyPrint(e.response.data); + } + if(returnError) { + return e; + } + throw e; + } + } +} \ No newline at end of file diff --git a/lib/utils/util_io.dart b/lib/utils/util_io.dart new file mode 100644 index 0000000..da45a95 --- /dev/null +++ b/lib/utils/util_io.dart @@ -0,0 +1,46 @@ + +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; +import '../routes.dart'; +import 'utils.dart'; +import 'package:hive/hive.dart'; +import 'package:path_provider/path_provider.dart'; + +class Util { + static Future getBox() async { + final dir = await getApplicationDocumentsDirectory(); + Hive.init(dir.path); + Box box = await Hive.openBox('app_data'); + return box; + } + + static Widget showImage(String imageUrl, {double width, double height, + BoxFit fit, Widget Function(BuildContext, String, dynamic) errorWidget}) { + if (imageUrl == null || imageUrl.isEmpty) { + return Container( + width: width, + height: height, + child: Text(''), + ); + } + return CachedNetworkImage( + imageUrl: imageUrl, + width: width, + height: width, + fit: fit, + placeholder: (context, url) => Utils.imageLoadingIndicator(), + errorWidget: errorWidget != null ? errorWidget : (context, url, error) { + return Image.asset( + 'assets/images/not_found.png', + width: width, + height: height, + fit: fit, + ); + }, + ); + } + + static void openWebUrl(BuildContext context, String link) { + Routes.router.navigateTo(context, '/webview/$link'); + } +} \ No newline at end of file diff --git a/lib/utils/util_web.dart b/lib/utils/util_web.dart new file mode 100644 index 0000000..a44c5d4 --- /dev/null +++ b/lib/utils/util_web.dart @@ -0,0 +1,52 @@ + +import 'package:flutter/material.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'utils.dart'; +import 'package:hive/hive.dart'; +import 'package:hive_flutter/hive_flutter.dart'; + +class Util { + + static Future getBox() async { + Hive.initFlutter(); + Box box = await Hive.openBox('wisetronic_app_data'); + return box; + } + + static Widget showImage(String imageUrl, {double width, double height, + BoxFit fit, Widget Function(BuildContext, String, dynamic) errorWidget}) { + return Image.network(imageUrl, + fit: fit, + width: width, + height: height, + cacheWidth: width != null ? width.round() : null, + cacheHeight: height != null ? height.round() : null, + loadingBuilder: (BuildContext context, Widget child, ImageChunkEvent loadingProgress) { + if (loadingProgress == null) return child; + return Center( + child: Utils.imageLoadingIndicator(), + ); + }, + errorBuilder: (BuildContext context, Object object, StackTrace stackTrace) { + if (errorWidget != null) { + return errorWidget(context, null, null); + } + return Image.asset( + 'assets/images/not_found.png', + width: width, + height: height, + fit: fit, + ); + }, + ); + } + + static void openWebUrl(BuildContext context, String link) async { + var url = 'https://${link}'; + if (await canLaunch(url)) { + await launch('$url'); + } else { + print('Could not launch $url'); + } + } +} \ No newline at end of file diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart new file mode 100644 index 0000000..1531594 --- /dev/null +++ b/lib/utils/utils.dart @@ -0,0 +1,277 @@ + +import 'dart:convert'; + +import 'package:dio/dio.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:flutter_wisetronic/generated/l10n.dart'; +import 'package:fluttertoast/fluttertoast.dart'; +import 'package:hive/hive.dart'; +import 'package:intl/intl.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:universal_io/io.dart'; +import 'util_web.dart' if (dart.library.io) 'util_io.dart'; + +import '../routes.dart'; +import 'http_util.dart'; + +typedef void OnSuccess(Response response); +typedef void OnError(dynamic error); +typedef void OnComplete(dynamic data); + +typedef void OnOk(); + +class Utils { + + static bool equalsIgnoreCase(String a, String b) => + (a == null && b == null) || + (a != null && b != null && a.toLowerCase() == b.toLowerCase()); + + static int selectionsContains(Map selections, String key, String name) { + if (selections.containsKey(key.toUpperCase())) { + for (var i = 0; i < (selections[key.toUpperCase()] as List).length; i++) { + Map item = (selections[key.toUpperCase()] as List)[i]; + if (Utils.equalsIgnoreCase(item['name'], name)) { + return i; + } + } + } + return -1; + } + + static List getSelectedAttributeValue(Map selections, String key) { + List valueArr = []; + if (selections.containsKey(key.toUpperCase())) { + for (var i = 0; i < (selections[key.toUpperCase()] as List).length; i++) { + valueArr.add((selections[key.toUpperCase()][i]['name'] as String).toLowerCase()); + } + } + return valueArr; + } + + static bool selectionsNotEmptyAt(Map selections, String key) { + if (selections.containsKey(key.toUpperCase()) && (selections[key.toUpperCase()] as List).length > 0) { + return true; + } + return false; + } + + static Map stringToJson(String string) { + if (string == null || string.isEmpty) { + return null; + } + return json.decode(string); + } + + static void jsonPrettyPrint(Map map) { + JsonEncoder encoder = new JsonEncoder.withIndent(' '); + String prettyPrint = encoder.convert(map); + debugPrint(prettyPrint); + } + + static launchURL(String url) async { + if (await canLaunch(url)) { + await launch(url); + } else { + throw 'Could not launch $url'; + } + } + + static String getPlatformName() { + String platformName = ''; + if (kIsWeb) { + platformName = 'web'; + } else if (Platform.isAndroid) { + platformName = 'android'; + } else if (Platform.isIOS) { + platformName = 'ios'; + } + return platformName; + } + + static Future getBox() async { + return Util.getBox(); + } + + static Widget imageLoadingIndicator() { + return SizedBox( + width: 30, + height: 30, + child: Container( + child: CupertinoActivityIndicator(), + color: Colors.transparent, + ), + ); + } + + static String safePhoneNumber(String phone) { + if (phone.length < 8) { + return phone; + } + String start = phone.substring(0, 3); + String end = phone.substring(phone.length - 3); + return '${start}****${end}'; + } + + static String safeString(String string) { + if (string == null || string.length == 0) { + return ''; + } + String start = string.substring(0, 1); + String end = string.substring(string.length - 1); + return '${start}****${end}'; + } + + static String smartRound(double amount, int decimalPlace) { + double a = double.parse(amount.toStringAsFixed(decimalPlace)); + double b = double.parse(amount.toStringAsFixed(0)); + if (a - b == 0) { + return amount.toStringAsFixed(0); + } + return amount.toStringAsFixed(decimalPlace); + } + + static void createOrUpdateStripePaymentMethod( + String paymentMethodId, + String cardBrand, + String paymentMethodType, + String cardCountry, + int cardExpMonth, + int cardExpYear, + String cardFunding, + String cardLast4, + ) { + HttpUtil.httpPost('v1/create-update-stripe-payment-method', (response) { + if (response.statusCode == 200) { + print('create or update customer stripe payment method success. ${response.data}'); + } + }, + body: { + 'payment_method_id': paymentMethodId, + 'card_brand': cardBrand, + 'payment_method_type': paymentMethodType, + 'card_country': cardCountry, + 'card_exp_month': cardExpMonth, + 'card_exp_year': cardExpYear, + 'card_funding': cardFunding, + 'card_last4': cardLast4, + }, + isFormData: true, + ).catchError((error) { + print('Error: ${error}'); + }); + } + + static showSubmitDialog(BuildContext context) { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + content: WillPopScope( + child: Container( + width: 300.0, + height: 150.0, + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SpinKitThreeBounce( + color: Colors.lightBlueAccent, + size: 30.0, + ), + Text( + S.of(context).submitting, + ), + ], + ), + ), + ), + onWillPop: () async { + Fluttertoast.showToast( + msg: S.of(context).submitting_please_wait, + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.CENTER, + backgroundColor: Colors.red, + textColor: Colors.white + ); + return false; + } + ), + ); + }, + ); + } + + static showLoadingDialog(BuildContext context, {String message}) { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + content: WillPopScope( + child: Container( + width: 80.0, + height: 80.0, + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SpinKitThreeBounce( + color: Colors.lightBlueAccent, + size: 30.0, + ), + Text( + message != null ? message : S.of(context).recalculating, + ), + ], + ), + ), + ), + onWillPop: () async { + Fluttertoast.showToast( + msg: S.of(context).loading_please_wait, + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.CENTER, + backgroundColor: Colors.red, + textColor: Colors.white + ); + return false; + } + ), + ); + }, + ); + } + + static getTitleFromBody(String body) { + if (body.length <= 30) { + return body; + } + return body.substring(0, 29); + } + + static void getMiniLink(String realLink, OnSuccess onSuccess, OnError onError) { + HttpUtil.httpPost('get-minilink/', (response) { + onSuccess(response); + }, + body: { + 'link': realLink + }, + isFormData: true, + ).catchError((error) { + onError(error); + }); + } +} + +class RuntimeError extends Error{ + final int code; + final String message; + RuntimeError(this.message, {this.code}); + String toString() => "Runtime Error: $message"; +} \ No newline at end of file diff --git a/lib/widgets/desktop/desktop_Index_carousel.dart b/lib/widgets/desktop/desktop_Index_carousel.dart new file mode 100644 index 0000000..b0eaaf1 --- /dev/null +++ b/lib/widgets/desktop/desktop_Index_carousel.dart @@ -0,0 +1,113 @@ + +import 'package:carousel_slider/carousel_slider.dart'; +import 'package:flutter/material.dart'; +import '../../models/gallery.dart'; +import '../../utils/util_web.dart' if (dart.library.io) '../../utils/util_io.dart'; + +class DesktopIndexCarousel extends StatefulWidget { + final List galleries; + + const DesktopIndexCarousel(this.galleries, {Key key}) : super(key: key); + + @override + State createState() { + return DesktopIndexCarouselState(); + } +} + +class DesktopIndexCarouselState extends State { + int _current = 0; + double sideSpace = 0; + double mainSpace = 1200; + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Container( + padding: EdgeInsets.only(left: 0.0, right: 0.0, top: 0.0, bottom: 0.0), + child: CarouselSlider( + items: widget.galleries.map((i) { + return Builder( + builder: (BuildContext context) { + if (MediaQuery.of(context).size.width <= 1200) { + mainSpace = MediaQuery.of(context).size.width; + sideSpace = 0; + } else { + mainSpace = 1200; + sideSpace = (MediaQuery.of(context).size.width - 1200) / 2; + } + return Row( + children: [ + Container( + width: sideSpace, + ), + Container( + width: mainSpace, + // margin: EdgeInsets.symmetric(horizontal: 5.0), + child: GestureDetector( + child: Container( + child: Util.showImage( + 'https:${i.image}', + fit: BoxFit.fitWidth, + ), + ), + onTap: () { + if (i.linkUrl != null && i.linkUrl.isNotEmpty) { + Util.openWebUrl(context, i.linkUrl); + } + }, + ), + ), + Container( + width: sideSpace, + ), + ], + ); + }, + ); + }).toList(), + options: CarouselOptions( + height: mainSpace / 2.0, + aspectRatio: 2/1, + initialPage: 0, + enableInfiniteScroll: true, + autoPlay: true, + autoPlayInterval: Duration(seconds: 5), + autoPlayCurve: Curves.fastOutSlowIn, + scrollDirection: Axis.horizontal, + viewportFraction: 1.0, + onPageChanged: (index, reason) { + setState(() { + _current = index; + }); + } + ), + ), + ), + Positioned( + bottom: 5, + right: sideSpace + 10, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: widget.galleries.map((i) { + int index = widget.galleries.indexOf(i); + return Container( + width: 8.0, + height: 8.0, + margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 2.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: _current == index + ? Color.fromRGBO(0, 0, 0, 0.9) + : Color.fromRGBO(0, 0, 0, 0.4), + ), + ); + }).toList(), + ), + ), + ], + ); + } + +} \ No newline at end of file diff --git a/lib/widgets/desktop/desktop_index_main_content_1.dart b/lib/widgets/desktop/desktop_index_main_content_1.dart new file mode 100644 index 0000000..221812f --- /dev/null +++ b/lib/widgets/desktop/desktop_index_main_content_1.dart @@ -0,0 +1,60 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/generated/l10n.dart'; + +class DesktopIndexMainContent1 extends StatefulWidget { + final String message; + const DesktopIndexMainContent1(this.message, {Key key}) : super(key: key); + + @override + State createState() { + return DesktopIndexMainContent1State(); + } +} + +class DesktopIndexMainContent1State extends State { + double sideSpace = 0; + double mainSpace = 1200; + + @override + Widget build(BuildContext context) { + if (MediaQuery.of(context).size.width <= 1200) { + mainSpace = MediaQuery.of(context).size.width; + sideSpace = 0; + } else { + mainSpace = 1200; + sideSpace = (MediaQuery.of(context).size.width - 1200) / 2; + } + + return Row( + children: [ + Container( + width: sideSpace, + ), + Container( + width: mainSpace, + margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0), + padding: EdgeInsets.symmetric(vertical: 30.0, horizontal: 30.0), + child: Container( + child: Text( + widget.message, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + ), + decoration: BoxDecoration( + color: Colors.lightGreen, + borderRadius: BorderRadius.circular(10), + ), + ), + Container( + width: sideSpace, + ), + ], + ); + } + +} \ No newline at end of file diff --git a/lib/widgets/desktop/desktop_index_main_content_2.dart b/lib/widgets/desktop/desktop_index_main_content_2.dart new file mode 100644 index 0000000..0f34d7b --- /dev/null +++ b/lib/widgets/desktop/desktop_index_main_content_2.dart @@ -0,0 +1,247 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/generated/l10n.dart'; +import '../../utils/util_web.dart' if (dart.library.io) '../../utils/util_io.dart'; + +class DesktopIndexMainContent2 extends StatefulWidget { + final Map content; + const DesktopIndexMainContent2(this.content, {Key key}) : super(key: key); + + @override + State createState() { + return DesktopIndexMainContent2State(); + } +} + +class DesktopIndexMainContent2State extends State { + double sideSpace = 0; + double mainSpace = 1200; + + @override + Widget build(BuildContext context) { + if (widget.content == null) { + return Container(); + } + if (MediaQuery.of(context).size.width <= 1200) { + mainSpace = MediaQuery.of(context).size.width; + sideSpace = 0; + } else { + mainSpace = 1200; + sideSpace = (MediaQuery.of(context).size.width - 1200) / 2; + } + return Row( + children: [ + Container( + width: sideSpace, + ), + Container( + width: mainSpace, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: mainSpace / 2, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0), + child: Text( + '${widget.content['minipos']}', + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.bold, + color: Colors.blueGrey, + ), + ), + ), + Container( + width: mainSpace / 2 - 100.0, + padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0), + child: Text( + '${widget.content['point_of_sale_system_solution']}', + style: TextStyle( + fontSize: 15.0, + color: Colors.grey, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + Container( + padding: EdgeInsets.symmetric(horizontal: 10.0), + child: Util.showImage( + 'http:${widget.content['minipos_image']['image']}', + fit: BoxFit.fitWidth + ), + ), + _buildMiniPosFeatures(mainSpace / 2), + ], + ), + ), + Container( + width: mainSpace / 2, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0), + child: Text( + '${widget.content['igoshow']}', + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.bold, + color: Colors.blueGrey, + ), + ), + ), + Container( + width: mainSpace / 2 - 100.0, + padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0), + child: Text( + '${widget.content['igoshow_solution']}', + style: TextStyle( + fontSize: 15.0, + color: Colors.grey, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + Container( + padding: EdgeInsets.symmetric(horizontal: 10.0), + child: Util.showImage( + 'http:${widget.content['igoshow_image']['image']}', + fit: BoxFit.fitWidth + ), + ), + _buildiGoShowFeatures(mainSpace / 2), + ], + ), + ), + ], + ), + ), + Container( + width: sideSpace, + ), + ], + ); + } + + Widget _buildMiniPosFeatures(double width) { + Column col = Column( + children: [], + ); + for (int i = 0; i < (widget.content['minipos_features'] as List).length; i++) { + col.children.add(Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 5.0), + child: Icon( + Icons.circle, + size: 10.0, + color: Colors.black87, + ), + ), + Container( + width: width - 40.0, + padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0), + child: Text( + '${(widget.content['minipos_features'] as List)[i]}', + style: TextStyle( + color: Colors.black54, + ), + ), + ), + ], + )); + } + col.children.add( + GestureDetector( + child: Container( + padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0), + child: Text( + S.of(context).learn_more, + style: TextStyle( + color: Colors.blue, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ); + return Container( + padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0), + child: col, + ); + } + + Widget _buildiGoShowFeatures(double width) { + Column col = Column( + children: [], + ); + for (int i = 0; i < (widget.content['igoshow_features'] as List).length; i++) { + col.children.add(Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 5.0), + child: Icon( + Icons.circle, + size: 10.0, + color: Colors.black87, + ), + ), + Container( + width: width - 40.0, + padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0), + child: Text( + '${(widget.content['igoshow_features'] as List)[i]}', + style: TextStyle( + color: Colors.black54, + ), + ), + ), + ], + )); + } + col.children.add( + GestureDetector( + child: Container( + padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0), + child: Text( + S.of(context).learn_more, + style: TextStyle( + color: Colors.blue, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ); + return Container( + padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0), + child: col, + ); + } + +} \ No newline at end of file diff --git a/lib/widgets/desktop/desktop_index_main_content_3.dart b/lib/widgets/desktop/desktop_index_main_content_3.dart new file mode 100644 index 0000000..fd2b869 --- /dev/null +++ b/lib/widgets/desktop/desktop_index_main_content_3.dart @@ -0,0 +1,179 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/generated/l10n.dart'; +import 'package:flutter_wisetronic/widgets/general/text_link.dart'; + +class DesktopIndexMainContent3 extends StatefulWidget { + final Map content; + const DesktopIndexMainContent3(this.content, {Key key}) : super(key: key); + + @override + State createState() { + return DesktopIndexMainContent3State(); + } +} + +class DesktopIndexMainContent3State extends State { + double sideSpace = 0; + double mainSpace = 1200; + + @override + Widget build(BuildContext context) { + if (widget.content == null) { + return Container(); + } + if (MediaQuery.of(context).size.width <= 1200) { + mainSpace = MediaQuery.of(context).size.width; + sideSpace = 0; + } else { + mainSpace = 1200; + sideSpace = (MediaQuery.of(context).size.width - 1200) / 2; + } + return Container( + width: MediaQuery.of(context).size.width, + margin: EdgeInsets.only(top: 20.0), + padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 20.0), + decoration: BoxDecoration( + color: Color(0xff262626), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + child: Text( + S.of(context).information, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.bold, + color: Colors.white70, + ), + ), + ), + Container( + child: Row( + children: [ + TextLink(S.of(context).service_policy, '/service_policy', paddingVertical: 5.0, paddingHorizontal: 10.0,), + TextLink(S.of(context).return_policy, '/return_policy', paddingVertical: 5.0, paddingHorizontal: 10.0,), + TextLink(S.of(context).privacy_policy, '/privacy_policy', paddingVertical: 5.0, paddingHorizontal: 10.0,), + TextLink(S.of(context).license_agreement, '/license_agreement', paddingVertical: 5.0, paddingHorizontal: 10.0,) + ], + ), + ), + Container( + margin: EdgeInsets.only(top: 12.0), + child: Text( + S.of(context).support, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.bold, + color: Colors.white70, + ), + ), + ), + Container( + child: Row( + children: [ + TextLink(S.of(context).wiki, '/wiki', paddingVertical: 5.0, paddingHorizontal: 10.0,), + TextLink(S.of(context).support_ticket, '/support_ticket', paddingVertical: 5.0, paddingHorizontal: 10.0,), + TextLink(S.of(context).contact_us, '/contact_us', paddingVertical: 5.0, paddingHorizontal: 10.0,), + TextLink(S.of(context).about_us, '/about_us', paddingVertical: 5.0, paddingHorizontal: 10.0,), + TextLink(S.of(context).renew_license, '/renew_license', paddingVertical: 5.0, paddingHorizontal: 10.0,) + ], + ), + ), + Container( + margin: EdgeInsets.only(top: 12.0), + child: Text( + S.of(context).developer_of, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.bold, + color: Colors.white70, + ), + ), + ), + Container( + child: Row( + children: [ + Container( + padding: EdgeInsets.all(10.0), + child: Icon( + IconData( + 0xe800, + fontFamily: 'company', + fontPackage: null + ), + color: Colors.white24, + size: 48.0, + ), + ), + Container( + padding: EdgeInsets.all(10.0), + child: Icon( + IconData( + 0xe801, + fontFamily: 'company', + fontPackage: null + ), + color: Colors.white24, + size: 48.0, + ), + ), + Container( + padding: EdgeInsets.all(10.0), + child: Icon( + IconData( + 0xe802, + fontFamily: 'company', + fontPackage: null + ), + color: Colors.white24, + size: 48.0, + ), + ), + Container( + padding: EdgeInsets.all(10.0), + child: Icon( + IconData( + 0xe803, + fontFamily: 'company', + fontPackage: null + ), + color: Colors.white24, + size: 48.0, + ), + ), + Container( + padding: EdgeInsets.all(10.0), + child: Icon( + IconData( + 0xe804, + fontFamily: 'company', + fontPackage: null + ), + color: Colors.white24, + size: 48.0, + ), + ), + Container( + padding: EdgeInsets.all(10.0), + child: Icon( + IconData( + 0xe805, + fontFamily: 'company', + fontPackage: null + ), + color: Colors.white24, + size: 48.0, + ), + ), + ], + ), + ), + ], + ), + ); + } + +} \ No newline at end of file diff --git a/lib/widgets/desktop/desktop_navigationbar.dart b/lib/widgets/desktop/desktop_navigationbar.dart new file mode 100644 index 0000000..68a5191 --- /dev/null +++ b/lib/widgets/desktop/desktop_navigationbar.dart @@ -0,0 +1,99 @@ + + +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/generated/l10n.dart'; +import 'package:flutter_wisetronic/widgets/general/navigationbar_logo.dart'; +import 'package:flutter_wisetronic/widgets/general/text_link.dart'; + +class DesktopNavigationBar extends StatefulWidget { + const DesktopNavigationBar({Key key}) : super(key: key); + + @override + State createState() { + return DesktopNavigationBarState(); + } + +} + +class DesktopNavigationBarState extends State { + + @override + Widget build(BuildContext context) { + String currentRoute = ModalRoute.of(context).settings.name; + return Stack( + children: [ + Container( + color: Colors.blue, + height: 80.0, + ), + Container( + height: 80.0, + padding: EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 5.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + NavigationBarLogo(), + Container( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox(width: 20.0,), + TextLink( + S.of(context).home, + '/', + color: Colors.white, + selected: currentRoute == '/', + ), + SizedBox(width: 15.0,), + TextLink( + S.of(context).download, + '/download', + color: Colors.white, + selected: currentRoute == '/download', + ), + SizedBox(width: 15.0,), + TextLink( + S.of(context).tutorials, + '/tutorials', + color: Colors.white, + selected: currentRoute == '/tutorials', + ), + SizedBox(width: 15.0,), + TextLink( + S.of(context).support, + '/support', + color: Colors.white, + selected: currentRoute == '/support', + ), + SizedBox(width: 15.0,), + TextLink( + S.of(context).shop, + '/shop', + color: Colors.white, + selected: currentRoute == '/shop', + ), + SizedBox(width: 15.0,), + TextLink( + S.of(context).blog, + '/blog', + color: Colors.white, + selected: currentRoute == '/blog', + ), + SizedBox(width: 15.0,), + TextLink( + S.of(context).login, + '/login', + color: Colors.white, + selected: currentRoute == '/login', + ), + ], + ), + ), + ], + ), + ), + ], + ); + } + +} \ No newline at end of file diff --git a/lib/widgets/general/bottom_nav.dart b/lib/widgets/general/bottom_nav.dart new file mode 100644 index 0000000..e698eb4 --- /dev/null +++ b/lib/widgets/general/bottom_nav.dart @@ -0,0 +1,51 @@ + +import 'package:flutter/material.dart'; + +class BottomNav extends StatefulWidget { + const BottomNav({Key key}) : super(key: key); + + @override + State createState() { + return BottomNavState(); + } + +} + +class BottomNavState extends State { + + @override + Widget build(BuildContext context) { + return Container( + width: MediaQuery.of(context).size.width, + height: 50.0, + padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0), + decoration: BoxDecoration( + color: Color(0xff232323), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Container( + child: Text( + '© 2007-${DateTime.now().year} wisetronic.com. All Rights Reserved.', + style: TextStyle( + fontSize: 10.0, + color: Colors.white60, + ), + ), + ), + Container( + child: Text( + 'All logos shown are registered trademark, copyrighted and belong to their respective owners.', + style: TextStyle( + fontSize: 10.0, + color: Colors.white60, + ), + ), + ), + ], + ), + ); + } + +} \ No newline at end of file diff --git a/lib/widgets/general/download_item.dart b/lib/widgets/general/download_item.dart new file mode 100644 index 0000000..a232f11 --- /dev/null +++ b/lib/widgets/general/download_item.dart @@ -0,0 +1,90 @@ + +import 'package:flutter/material.dart'; +import 'package:universal_io/io.dart'; +import '../../utils/util_web.dart' if (dart.library.io) '../../utils/util_io.dart'; + +class DownloadItem extends StatefulWidget { + final dynamic desc; + final double width; + const DownloadItem(this.desc, {Key key, this.width}) : super(key: key); + + @override + State createState() { + return DownloadItemState(); + } + +} + +class DownloadItemState extends State { + + @override + Widget build(BuildContext context) { + + return Container( + padding: EdgeInsets.only(top: 10.0, bottom: 10.0, left: 10.0, right: 10.0), + child: Column( + children: [ + Container( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + child: Row( + children: [ + Container( + child: Util.showImage( + 'https:${widget.desc['app_icon']}', + width: 32.0, + height: 32.0, + fit: BoxFit.fill, + ), + ), + Container( + child: Column( + children: [ + Text( + '${widget.desc['name']}', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 15.0, + color: Colors.black87, + ), + ), + Text( + '${widget.desc['version']}', + style: TextStyle( + fontSize: 12.0, + color: Colors.black38, + ), + ), + ], + ), + ), + ], + ), + ), + Container( + child: getDownloadButton(), + ), + ], + ), + ), + Container( + child: Text( + '${widget.desc['description']}', + style: TextStyle( + color: Colors.black54, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ); + } + + Widget getDownloadButton() { + + return null; + } +} \ No newline at end of file diff --git a/lib/widgets/general/index_carousel.dart b/lib/widgets/general/index_carousel.dart new file mode 100644 index 0000000..7d40ea8 --- /dev/null +++ b/lib/widgets/general/index_carousel.dart @@ -0,0 +1,21 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/models/gallery.dart'; +import '../desktop/desktop_Index_carousel.dart'; +import '../mobile/mobile_index_carousel.dart'; +import 'package:responsive_builder/responsive_builder.dart'; + +class IndexCarousel extends StatelessWidget { + final List galleries; + const IndexCarousel(this.galleries, {Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return ScreenTypeLayout( + mobile: MobileIndexCarousel(galleries), + tablet: DesktopIndexCarousel(galleries), + desktop: DesktopIndexCarousel(galleries), + ); + } + +} \ No newline at end of file diff --git a/lib/widgets/general/index_main_content_1.dart b/lib/widgets/general/index_main_content_1.dart new file mode 100644 index 0000000..e9d0ff9 --- /dev/null +++ b/lib/widgets/general/index_main_content_1.dart @@ -0,0 +1,20 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/widgets/desktop/desktop_index_main_content_1.dart'; +import 'package:flutter_wisetronic/widgets/mobile/mobile_index_main_content_1.dart'; +import 'package:responsive_builder/responsive_builder.dart'; + +class IndexMainContent1 extends StatelessWidget { + final String message; + const IndexMainContent1(this.message, {Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return ScreenTypeLayout( + mobile: MobileIndexMainContent1(message), + tablet: DesktopIndexMainContent1(message), + desktop: DesktopIndexMainContent1(message), + ); + } + +} \ No newline at end of file diff --git a/lib/widgets/general/index_main_content_2.dart b/lib/widgets/general/index_main_content_2.dart new file mode 100644 index 0000000..842ed4c --- /dev/null +++ b/lib/widgets/general/index_main_content_2.dart @@ -0,0 +1,20 @@ + +import 'package:flutter/material.dart'; +import '../desktop/desktop_index_main_content_2.dart'; +import '../mobile/mobile_index_main_content_2.dart'; +import 'package:responsive_builder/responsive_builder.dart'; + +class IndexMainContent2 extends StatelessWidget { + final Map content; + const IndexMainContent2(this.content, {Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return ScreenTypeLayout( + mobile: MobileIndexMainContent2(content), + tablet: DesktopIndexMainContent2(content), + desktop: DesktopIndexMainContent2(content), + ); + } + +} \ No newline at end of file diff --git a/lib/widgets/general/index_main_content_3.dart b/lib/widgets/general/index_main_content_3.dart new file mode 100644 index 0000000..41906ab --- /dev/null +++ b/lib/widgets/general/index_main_content_3.dart @@ -0,0 +1,20 @@ + +import 'package:flutter/material.dart'; +import '../desktop/desktop_index_main_content_3.dart'; +import '../mobile/mobile_index_main_content_3.dart'; +import 'package:responsive_builder/responsive_builder.dart'; + +class IndexMainContent3 extends StatelessWidget { + final Map content; + const IndexMainContent3(this.content, {Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return ScreenTypeLayout( + mobile: MobileIndexMainContent3(content), + tablet: DesktopIndexMainContent3(content), + desktop: DesktopIndexMainContent3(content), + ); + } + +} \ No newline at end of file diff --git a/lib/widgets/general/navigationbar.dart b/lib/widgets/general/navigationbar.dart new file mode 100644 index 0000000..d1c67cc --- /dev/null +++ b/lib/widgets/general/navigationbar.dart @@ -0,0 +1,37 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/widgets/desktop/desktop_navigationbar.dart'; +import 'package:flutter_wisetronic/widgets/mobile/mobile_navigationbar.dart'; +import 'package:responsive_builder/responsive_builder.dart'; + +class NavigationBar extends StatefulWidget implements PreferredSizeWidget { + final Key key; + final PreferredSizeWidget bottom; + + NavigationBar({Key key, PreferredSizeWidget bottom}) + : key = key, + preferredSize = Size.fromHeight(kToolbarHeight + (bottom?.preferredSize?.height ?? 0.0)), + bottom = bottom; + + @override + final Size preferredSize; + + @override + State createState() { + return NavigationBarState(); + } + +} + +class NavigationBarState extends State { + + @override + Widget build(BuildContext context) { + return ScreenTypeLayout( + mobile: MobileNavigationBar(), + tablet: DesktopNavigationBar(), + desktop: DesktopNavigationBar(), + ); + } + +} \ No newline at end of file diff --git a/lib/widgets/general/navigationbar_logo.dart b/lib/widgets/general/navigationbar_logo.dart new file mode 100644 index 0000000..c76f73b --- /dev/null +++ b/lib/widgets/general/navigationbar_logo.dart @@ -0,0 +1,25 @@ + +import 'package:flutter/material.dart'; + +class NavigationBarLogo extends StatelessWidget { + const NavigationBarLogo({Key key}) : super(key: key); + + static const IconData logoData = IconData( + 0xe800, + fontFamily: 'wisetronic', + fontPackage: null + ); + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 48, + width: 178, + child: Icon( + logoData, + color: Colors.white, + size: 48.0, + ), + ); + } +} \ No newline at end of file diff --git a/lib/widgets/general/text_link.dart b/lib/widgets/general/text_link.dart new file mode 100644 index 0000000..b40971c --- /dev/null +++ b/lib/widgets/general/text_link.dart @@ -0,0 +1,58 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class TextLink extends StatelessWidget { + final String title; + final String url; + final Color color; + final double paddingHorizontal; + final double paddingVertical; + final FontWeight fontWeight; + final bool selected; + TextLink(this.title, this.url, { + this.color, + this.paddingHorizontal, + this.paddingVertical, + this.fontWeight, + this.selected + }); + + @override + Widget build(BuildContext context) { + return MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + child: Container( + padding: EdgeInsets.symmetric( + vertical: paddingVertical ?? 0.0, + horizontal: paddingHorizontal ?? 0.0 + ), + child: Text( + title, + style: TextStyle( + color: color ?? Colors.blue, + fontWeight: fontWeight ?? FontWeight.normal, + ), + ), + decoration: BoxDecoration( + border: (selected != null && selected) ? Border( + bottom: BorderSide( + color: color ?? Colors.blue, + width: 3.0, + ) + ) : null, + ), + ), + onTap: () async { + if (await canLaunch(url)) { + await launch(url); + } else { + throw 'Could not launch $url'; + } + }, + ), + ); + } +} \ No newline at end of file diff --git a/lib/widgets/mobile/mobile_index_carousel.dart b/lib/widgets/mobile/mobile_index_carousel.dart new file mode 100644 index 0000000..c506484 --- /dev/null +++ b/lib/widgets/mobile/mobile_index_carousel.dart @@ -0,0 +1,94 @@ + +import 'package:carousel_slider/carousel_slider.dart'; +import 'package:flutter/material.dart'; +import '../../models/gallery.dart'; +import '../../utils/util_web.dart' if (dart.library.io) '../../utils/util_io.dart'; + +class MobileIndexCarousel extends StatefulWidget { + final List galleries; + + const MobileIndexCarousel(this.galleries, {Key key}) : super(key: key); + + @override + State createState() { + return MobileIndexCarouselState(); + } +} + +class MobileIndexCarouselState extends State { + int _current = 0; + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Container( + padding: EdgeInsets.only(left: 0.0, right: 0.0, top: 0.0, bottom: 0.0), + child: CarouselSlider( + items: widget.galleries.map((i) { + return Builder( + builder: (BuildContext context) { + return Container( + width: MediaQuery.of(context).size.width, + // margin: EdgeInsets.symmetric(horizontal: 5.0), + child: GestureDetector( + child: Container( + child: Util.showImage( + 'https:${i.image}', + fit: BoxFit.fitWidth, + ), + ), + onTap: () { + if (i.linkUrl != null && i.linkUrl.isNotEmpty) { + Util.openWebUrl(context, i.linkUrl); + } + }, + ), + ); + }, + ); + }).toList(), + options: CarouselOptions( + height: MediaQuery.of(context).size.width / 2.0, + aspectRatio: 2/1, + initialPage: 0, + enableInfiniteScroll: true, + autoPlay: true, + autoPlayInterval: Duration(seconds: 5), + autoPlayCurve: Curves.fastOutSlowIn, + scrollDirection: Axis.horizontal, + viewportFraction: 1.0, + onPageChanged: (index, reason) { + setState(() { + _current = index; + }); + } + ), + ), + ), + Positioned( + bottom: 5, + right: 10, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: widget.galleries.map((i) { + int index = widget.galleries.indexOf(i); + return Container( + width: 8.0, + height: 8.0, + margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 2.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + color: _current == index + ? Color.fromRGBO(0, 0, 0, 0.9) + : Color.fromRGBO(0, 0, 0, 0.4), + ), + ); + }).toList(), + ), + ), + ], + ); + } + +} \ No newline at end of file diff --git a/lib/widgets/mobile/mobile_index_main_content_1.dart b/lib/widgets/mobile/mobile_index_main_content_1.dart new file mode 100644 index 0000000..0f11fb7 --- /dev/null +++ b/lib/widgets/mobile/mobile_index_main_content_1.dart @@ -0,0 +1,40 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/generated/l10n.dart'; + +class MobileIndexMainContent1 extends StatefulWidget { + final String message; + + const MobileIndexMainContent1(this.message, {Key key}) : super(key: key); + + @override + State createState() { + return MobileIndexMainContent1State(); + } +} + +class MobileIndexMainContent1State extends State { + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0), + padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 20.0), + child: Container( + child: Text( + widget.message, + style: TextStyle( + fontSize: 15.0, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + ), + decoration: BoxDecoration( + color: Colors.lightGreen, + borderRadius: BorderRadius.circular(10), + ), + ); + } + +} \ No newline at end of file diff --git a/lib/widgets/mobile/mobile_index_main_content_2.dart b/lib/widgets/mobile/mobile_index_main_content_2.dart new file mode 100644 index 0000000..3f36a20 --- /dev/null +++ b/lib/widgets/mobile/mobile_index_main_content_2.dart @@ -0,0 +1,119 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/generated/l10n.dart'; +import '../../utils/util_web.dart' if (dart.library.io) '../../utils/util_io.dart'; + +class MobileIndexMainContent2 extends StatefulWidget { + final Map content; + + const MobileIndexMainContent2(this.content, {Key key}) : super(key: key); + + @override + State createState() { + return MobileIndexMainContent2State(); + } +} + +class MobileIndexMainContent2State extends State { + + @override + Widget build(BuildContext context) { + if (widget.content == null) { + return Container(); + } + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0), + child: Text( + '${widget.content['minipos']}', + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.bold, + color: Colors.blueGrey, + ), + ), + ), + Container( + padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0), + child: Text( + '${widget.content['point_of_sale_system_solution']}', + style: TextStyle( + fontSize: 15.0, + color: Colors.grey, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + Container( + padding: EdgeInsets.symmetric(horizontal: 10.0), + child: Util.showImage( + 'http:${widget.content['minipos_image']['image']}', + fit: BoxFit.fitWidth + ), + ), + _buildMiniPosFeatures(), + ], + ); + } + + Widget _buildMiniPosFeatures() { + Column col = Column( + children: [], + ); + for (int i = 0; i < (widget.content['minipos_features'] as List).length; i++) { + col.children.add(Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 5.0), + child: Icon( + Icons.circle, + size: 10.0, + color: Colors.black87, + ), + ), + Container( + width: MediaQuery.of(context).size.width - 40.0, + padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0), + child: Text( + '${(widget.content['minipos_features'] as List)[i]}', + style: TextStyle( + color: Colors.black54, + ), + ), + ), + ], + )); + } + col.children.add( + GestureDetector( + child: Container( + padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0), + child: Text( + S.of(context).learn_more, + style: TextStyle( + color: Colors.blue, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ); + return Container( + padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0), + child: col, + ); + } + +} \ No newline at end of file diff --git a/lib/widgets/mobile/mobile_index_main_content_3.dart b/lib/widgets/mobile/mobile_index_main_content_3.dart new file mode 100644 index 0000000..25a8695 --- /dev/null +++ b/lib/widgets/mobile/mobile_index_main_content_3.dart @@ -0,0 +1,122 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/generated/l10n.dart'; +import '../../utils/util_web.dart' if (dart.library.io) '../../utils/util_io.dart'; + +class MobileIndexMainContent3 extends StatefulWidget { + final Map content; + + const MobileIndexMainContent3(this.content, {Key key}) : super(key: key); + + @override + State createState() { + return MobileIndexMainContent3State(); + } +} + +class MobileIndexMainContent3State extends State { + + @override + Widget build(BuildContext context) { + if (widget.content == null) { + return Container(); + } + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0), + child: Text( + '${widget.content['igoshow']}', + style: TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.bold, + color: Colors.blueGrey, + ), + ), + ), + Container( + padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0), + child: Text( + '${widget.content['igoshow_solution']}', + style: TextStyle( + fontSize: 15.0, + color: Colors.grey, + ), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + Container( + padding: EdgeInsets.symmetric(horizontal: 10.0), + child: Util.showImage( + 'http:${widget.content['igoshow_image']['image']}', + fit: BoxFit.fitWidth + ), + ), + _buildiGoShowFeatures(), + Container( + height: 20.0, + ), + ], + ); + } + + Widget _buildiGoShowFeatures() { + Column col = Column( + children: [], + ); + for (int i = 0; i < (widget.content['igoshow_features'] as List).length; i++) { + col.children.add(Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 5.0), + child: Icon( + Icons.circle, + size: 10.0, + color: Colors.black87, + ), + ), + Container( + width: MediaQuery.of(context).size.width - 40.0, + padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0), + child: Text( + '${(widget.content['igoshow_features'] as List)[i]}', + style: TextStyle( + color: Colors.black54, + ), + ), + ), + ], + )); + } + col.children.add( + GestureDetector( + child: Container( + padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0), + child: Text( + S.of(context).learn_more, + style: TextStyle( + color: Colors.blue, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ); + return Container( + padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0), + child: col, + ); + } + +} \ No newline at end of file diff --git a/lib/widgets/mobile/mobile_navigation_drawer.dart b/lib/widgets/mobile/mobile_navigation_drawer.dart new file mode 100644 index 0000000..4e34596 --- /dev/null +++ b/lib/widgets/mobile/mobile_navigation_drawer.dart @@ -0,0 +1,233 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/generated/l10n.dart'; +import 'package:flutter_wisetronic/widgets/general/text_link.dart'; +import 'package:flutter_wisetronic/widgets/mobile/mobile_navigation_drawer_header.dart'; + +class MobileNavigationDrawer extends StatefulWidget { + const MobileNavigationDrawer({Key key}) : super(key: key); + + @override + State createState() { + return MobileNavigationDrawerState(); + } + +} + +class MobileNavigationDrawerState extends State { + @override + Widget build(BuildContext context) { + String currentRoute = ModalRoute.of(context).settings.name; + + return Container( + width: 300.0, + height: MediaQuery.of(context).size.height, + decoration: BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow(color: Colors.black12, blurRadius: 16.0), + ], + ), + child: SingleChildScrollView( + child: Column( + children: [ + MobileNavigationDrawerHeader(), + TextLink( + S.of(context).home, + '/', + paddingVertical: 10.0, + paddingHorizontal: 15.0, + selected: currentRoute == '/', + ), + TextLink( + S.of(context).download, + '/download', + paddingVertical: 10.0, + paddingHorizontal: 15.0, + selected: currentRoute == '/download', + ), + TextLink( + S.of(context).tutorials, + '/tutorials', + paddingVertical: 10.0, + paddingHorizontal: 15.0, + selected: currentRoute == '/tutorials', + ), + TextLink( + S.of(context).support, + '/support', + paddingVertical: 10.0, + paddingHorizontal: 15.0, + selected: currentRoute == '/support', + ), + TextLink( + S.of(context).shop, + '/shop', + paddingVertical: 10.0, + paddingHorizontal: 15.0, + selected: currentRoute == '/shop', + ), + TextLink( + S.of(context).blog, + '/blog', + paddingVertical: 10.0, + paddingHorizontal: 15.0, + selected: currentRoute == '/blog', + ), + TextLink( + S.of(context).login, + '/login', + paddingVertical: 10.0, + paddingHorizontal: 15.0, + selected: currentRoute == '/login', + ), + Container( + margin: EdgeInsets.only(top: 20.0), + height: 0.5, + color: Colors.green, + ), + Container( + margin: EdgeInsets.only(top: 20.0, bottom: 10.0), + child: Text( + S.of(context).information, + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black54, + fontSize: 16.0, + ), + ), + ), + TextLink( + S.of(context).service_policy, + '/service_policy', + paddingVertical: 5.0, + paddingHorizontal: 10.0, + ), + TextLink( + S.of(context).return_policy, + '/return_policy', + paddingVertical: 5.0, + paddingHorizontal: 10.0, + ), + TextLink( + S.of(context).privacy_policy, + '/privacy_policy', + paddingVertical: 5.0, + paddingHorizontal: 10.0, + ), + TextLink( + S.of(context).license_agreement, + '/license_agreement', + paddingVertical: 5.0, + paddingHorizontal: 10.0, + ), + Container( + margin: EdgeInsets.only(top: 20.0, bottom: 10.0), + child: Text( + S.of(context).support, + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black54, + fontSize: 16.0, + ), + ), + ), + TextLink(S.of(context).wiki, '/wiki', paddingVertical: 5.0, paddingHorizontal: 10.0,), + TextLink(S.of(context).support_ticket, '/support_ticket', paddingVertical: 5.0, paddingHorizontal: 10.0,), + TextLink(S.of(context).contact_us, '/contact_us', paddingVertical: 5.0, paddingHorizontal: 10.0,), + TextLink(S.of(context).about_us, '/about_us', paddingVertical: 5.0, paddingHorizontal: 10.0,), + TextLink(S.of(context).renew_license, '/renew_license', paddingVertical: 5.0, paddingHorizontal: 10.0,), + Container( + margin: EdgeInsets.only(top: 20.0, bottom: 10.0), + child: Text( + S.of(context).developer_of, + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.black54, + fontSize: 16.0, + ), + ), + ), + Wrap( + children: [ + Container( + padding: EdgeInsets.all(10.0), + child: Icon( + IconData( + 0xe800, + fontFamily: 'company', + fontPackage: null + ), + color: Colors.black26, + size: 48.0, + ), + ), + Container( + padding: EdgeInsets.all(10.0), + child: Icon( + IconData( + 0xe801, + fontFamily: 'company', + fontPackage: null + ), + color: Colors.black26, + size: 48.0, + ), + ), + Container( + padding: EdgeInsets.all(10.0), + child: Icon( + IconData( + 0xe802, + fontFamily: 'company', + fontPackage: null + ), + color: Colors.black26, + size: 48.0, + ), + ), + Container( + padding: EdgeInsets.all(10.0), + child: Icon( + IconData( + 0xe803, + fontFamily: 'company', + fontPackage: null + ), + color: Colors.black26, + size: 48.0, + ), + ), + Container( + padding: EdgeInsets.all(10.0), + child: Icon( + IconData( + 0xe804, + fontFamily: 'company', + fontPackage: null + ), + color: Colors.black26, + size: 48.0, + ), + ), + Container( + padding: EdgeInsets.all(10.0), + child: Icon( + IconData( + 0xe805, + fontFamily: 'company', + fontPackage: null + ), + color: Colors.black26, + size: 48.0, + ), + ), + ], + ), + ], + ), + ), + ); + } + +} \ No newline at end of file diff --git a/lib/widgets/mobile/mobile_navigation_drawer_header.dart b/lib/widgets/mobile/mobile_navigation_drawer_header.dart new file mode 100644 index 0000000..f59e44e --- /dev/null +++ b/lib/widgets/mobile/mobile_navigation_drawer_header.dart @@ -0,0 +1,30 @@ + + +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/generated/l10n.dart'; + +class MobileNavigationDrawerHeader extends StatelessWidget { + + @override + Widget build(BuildContext context) { + return Container( + height: 40.0, + padding: EdgeInsets.only(top: 10.0), + color: Colors.green, + alignment: Alignment.center, + child: Column( + children: [ + Text( + S.of(context).navigation, + style: TextStyle( + fontSize: 18.0, + fontWeight: FontWeight.w800, + color: Colors.white, + ), + ) + ], + ), + ); + } + +} \ No newline at end of file diff --git a/lib/widgets/mobile/mobile_navigationbar.dart b/lib/widgets/mobile/mobile_navigationbar.dart new file mode 100644 index 0000000..123bb5c --- /dev/null +++ b/lib/widgets/mobile/mobile_navigationbar.dart @@ -0,0 +1,74 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/events/eventbus.dart'; +import 'package:flutter_wisetronic/events/events.dart'; +import 'package:flutter_wisetronic/widgets/general/navigationbar_logo.dart'; + +class MobileNavigationBar extends StatefulWidget { + const MobileNavigationBar({Key key}) : super(key: key); + + @override + State createState() { + return MobileNavigationBarState(); + } + +} + +class MobileNavigationBarState extends State { + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.only(left: 10.0, right: 10.0), + height: 80.0, + color: Colors.blue, + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconButton( + icon: Icon(Icons.menu), + onPressed: () { + eventBus.fire(OpenDrawer()); + }, + ), + Container( + child: NavigationBarLogo(), + padding: EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 5.0), + ), + Container() + ], + ), + ); + // return Stack( + // children: [ + // Container( + // height: 80.0, + // color: Colors.blue, + // ), + // Container( + // padding: EdgeInsets.only(left: 10.0, right: 10.0), + // height: 80.0, + // child: Row( + // mainAxisSize: MainAxisSize.max, + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // IconButton( + // icon: Icon(Icons.menu), + // onPressed: () { + // + // }, + // ), + // Container( + // child: NavigationBarLogo(), + // padding: EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 5.0), + // ), + // Container() + // ], + // ), + // ), + // ], + // ); + } + +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 932b246..00c8da5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -189,7 +189,7 @@ packages: name: file url: "https://pub.dartlang.org" source: hosted - version: "5.2.1" + version: "6.0.0-nullsafety.4" flappy_search_bar: dependency: "direct main" description: @@ -285,7 +285,7 @@ packages: source: hosted version: "0.3.2" flutter_svg: - dependency: transitive + dependency: "direct main" description: name: flutter_svg url: "https://pub.dartlang.org" @@ -363,7 +363,7 @@ packages: name: intl url: "https://pub.dartlang.org" source: hosted - version: "0.16.1" + version: "0.17.0-nullsafety.2" js: dependency: transitive description: @@ -449,7 +449,7 @@ packages: source: hosted version: "0.1.4" path_provider: - dependency: transitive + dependency: "direct main" description: name: path_provider url: "https://pub.dartlang.org" @@ -503,7 +503,7 @@ packages: name: platform url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "3.0.0-nullsafety.4" plugin_platform_interface: dependency: transitive description: @@ -517,7 +517,7 @@ packages: name: process url: "https://pub.dartlang.org" source: hosted - version: "3.0.13" + version: "4.0.0-nullsafety.4" pull_to_refresh: dependency: "direct main" description: @@ -649,6 +649,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0-nullsafety.5" + universal_io: + dependency: "direct main" + description: + name: universal_io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" url_launcher: dependency: "direct main" description: @@ -789,6 +796,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.2.1" + zone_local: + dependency: transitive + description: + name: zone_local + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.2" sdks: dart: ">=2.12.0-29.10.beta <3.0.0" flutter: ">=1.24.0-6.0.pre <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 41c7aff..3056d78 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -55,6 +55,9 @@ dependencies: package_info: ^0.4.3+2 catcher: ^0.3.22 share: ^0.6.5+4 + flutter_svg: ^0.19.2+1 + universal_io: ^1.0.1 + path_provider: ^1.6.24 dev_dependencies: flutter_test: @@ -72,7 +75,8 @@ flutter: uses-material-design: true # To add assets to your application, add an assets section, like this: - # assets: + assets: + - assets/images/ # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg @@ -87,6 +91,13 @@ flutter: # "family" key with the font family name, and a "fonts" key with a # list giving the asset and other descriptors for the font. For # example: + fonts: + - family: wisetronic + fonts: + - asset: fonts/wisetronic.ttf + - family: company + fonts: + - asset: fonts/company.ttf # fonts: # - family: Schyler # fonts: