From f504e213a0eae1ed2d98cb2a779a2b4109aafbbd Mon Sep 17 00:00:00 2001 From: peima Date: Thu, 10 Mar 2022 00:47:26 -0500 Subject: [PATCH] initial commit to gitea --- .../main/res/mipmap-hdpi/launcher_icon.png | Bin 0 -> 1987 bytes .../main/res/mipmap-mdpi/launcher_icon.png | Bin 0 -> 1343 bytes .../main/res/mipmap-xhdpi/launcher_icon.png | Bin 0 -> 2706 bytes .../main/res/mipmap-xxhdpi/launcher_icon.png | Bin 0 -> 3914 bytes .../main/res/mipmap-xxxhdpi/launcher_icon.png | Bin 0 -> 5492 bytes lib/constants.dart | 9 +- lib/events/events.dart | 21 + lib/generated/intl/messages_en.dart | 114 +-- lib/generated/intl/messages_zh_CN.dart | 114 +-- lib/generated/l10n.dart | 148 +++- lib/l10n/intl_en.arb | 18 +- lib/l10n/intl_zh_CN.arb | 18 +- lib/main.dart | 36 +- lib/models/group.dart | 22 + lib/models/product.dart | 36 +- lib/pages/buy_service.dart | 9 +- lib/pages/change_mobile_or_email.dart | 2 +- lib/pages/change_password.dart | 2 +- lib/pages/create_online_store_1.dart | 48 ++ lib/pages/download.dart | 2 +- lib/pages/forgot_password.dart | 2 +- lib/pages/home.dart | 2 +- lib/pages/igoshow_learn_more.dart | 2 +- lib/pages/login.dart | 2 +- lib/pages/me.dart | 2 +- lib/pages/minipos_learn_more.dart | 2 +- lib/pages/new_ticket.dart | 2 +- lib/pages/new_user.dart | 2 +- lib/pages/product_search.dart | 26 + lib/pages/reset_password.dart | 2 +- lib/pages/set_password.dart | 2 +- lib/pages/shop.dart | 177 +--- lib/pages/store_product_search.dart | 4 +- lib/pages/tutorials.dart | 66 -- lib/pages/user_profile.dart | 2 +- lib/pages/view_blog.dart | 2 +- lib/pages/view_ticket.dart | 2 +- lib/routes.dart | 24 +- lib/utils/http_util.dart | 12 +- lib/utils/iframe_web.dart | 39 - lib/utils/util_web.dart | 2 +- lib/utils/utils.dart | 154 +++- .../desktop/create_online_store_1.dart | 464 +++++++++++ lib/widgets/desktop/desktop_appbar_menu.dart | 21 +- lib/widgets/desktop/desktop_blog.dart | 3 +- lib/widgets/desktop/desktop_buy_service.dart | 14 +- lib/widgets/desktop/desktop_checkout.dart | 3 +- lib/widgets/desktop/desktop_contact_us.dart | 2 +- lib/widgets/desktop/desktop_coupons.dart | 2 +- lib/widgets/desktop/desktop_edit_address.dart | 2 +- .../desktop/desktop_index_main_content_3.dart | 6 +- lib/widgets/desktop/desktop_my_addresses.dart | 2 +- lib/widgets/desktop/desktop_my_cards.dart | 2 +- lib/widgets/desktop/desktop_my_support.dart | 2 +- .../desktop/desktop_navigationbar.dart | 160 +--- lib/widgets/desktop/desktop_new_address.dart | 2 +- lib/widgets/desktop/desktop_new_comment.dart | 2 +- lib/widgets/desktop/desktop_order_detail.dart | 2 +- lib/widgets/desktop/desktop_orders.dart | 2 +- lib/widgets/desktop/desktop_pay_now.dart | 2 +- lib/widgets/desktop/desktop_plain_page.dart | 2 +- .../desktop/desktop_product_detail_page.dart | 2 +- .../desktop/desktop_renew_license.dart | 2 +- .../desktop/desktop_renew_minioffice.dart | 2 +- lib/widgets/desktop/desktop_search_place.dart | 2 +- lib/widgets/desktop/desktop_set_password.dart | 2 +- .../desktop/desktop_stripe_pay_web.dart | 2 +- lib/widgets/desktop/desktop_tutorials.dart | 127 --- lib/widgets/desktop/desktop_view_blog.dart | 8 +- lib/widgets/desktop/product_item.dart | 280 +++++++ lib/widgets/desktop/product_search.dart | 181 ++++ lib/widgets/desktop/shop.dart | 297 +++++++ ...shop.dart => shop_backup_dec_19_2021.dart} | 772 +++++++++++------- lib/widgets/desktop/shop_bulletin.dart | 70 ++ lib/widgets/desktop/shop_products.dart | 431 ++++++++++ lib/widgets/desktop/shop_promote.dart | 185 +++++ lib/widgets/desktop/shopping_cart_widget.dart | 79 ++ lib/widgets/general/breadcrumbs.dart | 12 +- lib/widgets/general/navigationbar.dart | 10 +- .../payment_verification_code_dialog.dart | 12 +- lib/widgets/general/product_item.dart | 27 - lib/widgets/general/text_link.dart | 56 +- lib/widgets/mobile/create_online_store_1.dart | 411 ++++++++++ lib/widgets/mobile/mobile_buy_service.dart | 12 + lib/widgets/mobile/mobile_checkout.dart | 1 + .../mobile/mobile_navigation_drawer.dart | 1 + lib/widgets/mobile/mobile_tutorials.dart | 92 --- lib/widgets/mobile/mobile_view_blog.dart | 8 +- lib/widgets/mobile/product_item.dart | 261 ++++++ lib/widgets/mobile/product_search.dart | 152 ++++ .../mobile/{mobile_shop.dart => shop.dart} | 598 ++++++-------- pubspec.lock | 12 +- web/index.html | 2 +- 93 files changed, 4394 insertions(+), 1539 deletions(-) create mode 100644 android/app/src/main/res/mipmap-hdpi/launcher_icon.png create mode 100644 android/app/src/main/res/mipmap-mdpi/launcher_icon.png create mode 100644 android/app/src/main/res/mipmap-xhdpi/launcher_icon.png create mode 100644 android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png create mode 100644 android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png create mode 100644 lib/models/group.dart create mode 100644 lib/pages/create_online_store_1.dart create mode 100644 lib/pages/product_search.dart delete mode 100644 lib/pages/tutorials.dart delete mode 100644 lib/utils/iframe_web.dart create mode 100644 lib/widgets/desktop/create_online_store_1.dart delete mode 100644 lib/widgets/desktop/desktop_tutorials.dart create mode 100644 lib/widgets/desktop/product_item.dart create mode 100644 lib/widgets/desktop/product_search.dart create mode 100644 lib/widgets/desktop/shop.dart rename lib/widgets/desktop/{desktop_shop.dart => shop_backup_dec_19_2021.dart} (79%) create mode 100644 lib/widgets/desktop/shop_bulletin.dart create mode 100644 lib/widgets/desktop/shop_products.dart create mode 100644 lib/widgets/desktop/shop_promote.dart create mode 100644 lib/widgets/desktop/shopping_cart_widget.dart delete mode 100644 lib/widgets/general/product_item.dart create mode 100644 lib/widgets/mobile/create_online_store_1.dart delete mode 100644 lib/widgets/mobile/mobile_tutorials.dart create mode 100644 lib/widgets/mobile/product_item.dart create mode 100644 lib/widgets/mobile/product_search.dart rename lib/widgets/mobile/{mobile_shop.dart => shop.dart} (79%) diff --git a/android/app/src/main/res/mipmap-hdpi/launcher_icon.png b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..006e7aa477a439fd5b7088700d200dc483ceb140 GIT binary patch literal 1987 zcmV;!2R!(RP)4*~9LIenaS}InoU2C?JG7-GEomIb>7ib#5U2uy3aU^mfmFc*Z}c7UM{tNYctYZM zC=XPKA^}2`XqwvVD@~flO=7Pdr#Wn|?|YdkUD!H%&TJH?@<)mik9U5%``ww}{N}ea z(Wx2;qTB8ZsCOCyiO>*8goZ#OGz1cXQ=qd4yB%%KIs>ZFP%KN%M3Vuo?=BqbJ=v_& z=uvIoS=gAOa-~dddAFh2G;T55Q0+o)2iERn3Y9#&j8mXbUmyPDm6!V7LOs#1_g8LQ z{QUMiwdKY(UCVFR&;F^^s9R8NU;TRW&F`kjpKHtC9Ur{(@n(1Q7WHcmxC@afnygkI$%1+RX#S@$@x&E;#x|0xXQU(P$-Ti5I}7MHxi{*{$dv% zA5uV|e$!}eS!%g>HqboKqkg{P-gY*XaX27g0|*Heh;YM6q^8=^V$hNUO@A*LbAuAsd|+cdn#i07cm z1aD*D6=?2pDwxif*A04IH|mK&%wl5%a#)oU$kf)n`#`T@-~4Ji0*3vgAhtq|%ppRJ zfmfg^{bc9^eyICZ)DweN^Tbi_?`iMrYH#UBwZmr{3WVKtX;sA;jC0075W&f+hm3o0 z1hNhO8?%5e0fkb;K{Jf(Gmd_LkGyHe3=l){?EFTixM^<3ASjSGf)`OA>@ge#L7WbB z1FW0if)U?t#j_0@wBS7o3IxJ$EJv-=YFa@McUVaW%`n>EX=`uRHXZIWj^NlKg8U8| zA}G-GG8HJ4D^!b4Yec;OFy$Ci(m^xq?$8gtF|zjzwu24{hcki#l`1stB`MFukog?y z1zffdTvXaYKS8ZhUpr;}5YGrr3k~rQ(TpMp!Cg24oj=rbNu{uZW_WFQ_uDx2mlOH< zNaERyLoK2L5h3nLoK!Swy!?+KY8964sioMI*fF94dBWHcb=@+#uyI%H7*T6ui% zTo5}>l0dL2esoTWTvz=70z^r^RgyrHiyNYSb*JHyI66xbXl^AH#LZFH8&dOKk_38^ zqh5}?PVetUPQlg{G|iiXu0`^@dDjv}JTC$T)-n&6RInJ51#$*s&rQGxW(Sh*MS2V3 zd2h56@kWFvsB9z)1as8cVma2%N9~>%GM|@qRrLa`qCMdHbY{In$>CXmb`5TZjyVUrVz3P$`z}XnP}2G(r-E` zx9&DW69{XbkhUVgzPyD3!Ss{jFB&&8g>W#IU6Wf6O&}0#T|0$RQ3A%)sjVAqta<%%@Hld_I{^jiuC=~a>1ppegx(U?=8+I}dv`(iIHW{2t z=<`Qpfs*-hA+Vah|6<>+P1}=D05|d9Q%0Fo3V~w}Yg4ZigzicS#9k{1{+?6HQKt*# z^|_T)2(>WbU2J)o}rEfxig97R&W|vcoIM;?PkOxdKFWdXy$1qU^ zbFfVUm4WB>MJUgN72OZP`ehsstx`asoBrsnz7G9osP%KjN|NtY@E3o~f90^6kt6nd zOR>LE>oQ;q*8goZ#O`~#|( VYx(PMdHDbU002ovPDHLkV1m~qs7L?+ literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-mdpi/launcher_icon.png b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2626cd9a702315720be220d34537a399ffa519f7 GIT binary patch literal 1343 zcmV-F1;F}=P)at;?`sgpyW!N`-=mLxwf4k7_jB{Jj(LdhZx0TC{bl2D zxz={rx&}VKHL?itjUE;MT)MaOeXZRR#jU)joP6r@^U`!5Krs~^Xr)?JMJ7u>v_)a@5(@@_)Jlhas1A+DZ z<4uO;N(NHbr8Ll_y=RIbG#Wv8+V(oFGteNO?Kh2^45YEZuqU|fao9Xi-{whfAW-3W zE|NM9xreNCN&}gV`m5LbP0p=@Ld>IFjI-x=6w1nQ{uuLv*r|*+mf|#;fKm;l* zUk>l(B9a6!{4tt>5Wqlo9!vnuz85tKQ1qwpx@=xd;Dv$ivCa-%H^e8B%7q!0XY2dK z2>3sJ6&8fYVRirLOZ+_Tu!8q+4K<$`r_BrXq2gJpxleQjpaZ%cPnUjX7#>6oGp;AA zh7uS~-XEv^&3$JGtnTL`EYF{iTCGuOK=qH!kh~f#CzVM4?%_^cz4vPhg2Yz)~fY>JAma(IGJ0Ovr(+fol5HqA@JZJzg}QiM$Sf&Krl&D z3mRA3f>HxWol22FAeI9cyV?y3AnO$gprbU*^8%~Y66y=Vf`(@Wp-Q%R2m}D9pkh$@ z6Slm4Scr^WGry=dfCOENrVC8EmCKM91QtEwLrQj_S;dLm3ITi(9^{xutq^#4RM^aw zt0g5n5P?8~_Rr5cK2{q9E`y*|h%eq6QR@n>Pk{(fBJ~&u&>jv%j|$NiecMMM5T`?e zAaDdh=v2fY1QT>{k1ih;88(X^@D>%mSOtJ44Mc!0RSVH{aSK<|paG!dO~o_igD1fx zv;J2`dv8O15qPwP+D8BbZDvXhf%+}5vYYX#A+Vb+Za*$o@(^1v0VR3M~aNfpnpg`(Y*iouy0Pt7OY^0<(3H->tRr?`TW+c9zDTF;77Lmk*f0 z7^?Km{L=jeHTL!R;-}D;t@_I0zx7M~WyGZ?@E4I3OWXcNsPO;*002ovPDHLkV1hq1 Bc$okI literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ff161bbe207c30fbc552cc1ca03a38422f4472dd GIT binary patch literal 2706 zcmV;D3T^d?P)f zK4@a%lb6Jp_~6^bcw(Z-k(SaH7#QHt($aG2Dedl!w!7V}YZbvx*}L7B-)aZiPeNL{ z_g=r1{oQM=-}f(cXMg_pFH}3{5AQAh>f4K^_aN<3R53sBlfMl`QcQ;Lj32-C z#`k{t&g`#Y?NZdw{<`*~Up(Lb9oI2l0a6Uh?uHV3pS;tz2$`Ab;XZ3;dz&JgFBJLC zc{Dlj7=5TA?NXG2nlbd<|L1nt!FR^2q2CH`m!g)v5f|UFs#TEFPrIN6=uo!x&W>u| zT=qn_xsDI^sJbWgJr5ymUSKxp%+&;#8||M1H(I2!?qFn{?{HNCTnDu4-NjMxJk1$& zRz3k1#`N>(VeJ4nikLO_&+;8ZrLql`PBXO4y>Rjconjfj<5dN42V-l{8Nyghx_R{R zN1kIA5;idpN3^^p%QCLLhe~G;v`u%Q`aP^(0{l^Qagjy!rxG$#3#I`p-?7Cp{Su_D za?le#gPI?TtNB?l4id5J^hbH?e@s;YP7>L~K{UN%)TyT+Gc`5bJBN!rYKRM!$B+P^ zZB9AeDy9CxUF|rkTD@27j+3$L3eeI8I8PvAhZaE9jv8WP|2^a#Y?c3R8tm2$^>s}` z+Nxx6TxaDHV2O+X1?0%MtDR6&0GlUf|LQ}-cj5AM4tnCOl>*Eg^wHo|bwYVYvefe)Q1}(T3Qi)|$ zcg5ATnDodyQhVzZGzN2r3% z4yAtjj&=gI1A7<0eQIowhybhpsC)r1$d`3N3!rRMXzq{ny}9CxzQq5d9H3;^MUC#I*F&-cR>}S0{(00FQ81`WJkQ}3LEwZGU_X3znqZiN zUX=*Bzh*#nA-UxyyUB{mImAPyuvm zm0@B~bBiq$i+YV}3^MIn%ozI2SOC-qAmaLhRza8*-zgU0o6@tyiDGF&XUQ-);77Ix zT#5Ov&V0M~DOJjO#CRgAcrzHh;fk}nFSA8_R00BB3|2Uc5M?Uj} zv}|#M>fkw4WX~Ye6v9A{%JlWwk+(>sEhGkXfvDo=Jczo!IDH3HfZnclBl_bVpeKl8 z#-M#lAl>4!mp~PS!M-gL;2YxeR22nP=LWdUH0VelCX!gVX==q`qK(3Wje3qIE z+rIFpA0tYDjUzH4iJOF-qyR4ulYuja4XIVi+v2j-JlI6k{}@pM;MoMIA+|rB9Q=y7 zY&8o-7F9vK6Ti3+-3h@iR!abGj^i0mD3Prhf-Xn20AlO7W@0T66WvCN7T|w%9C&E@ zCg7AXZX#NMolx>Pdd38FYL!v!wKpACK)jnSDG;@?AGJT79%>0tL0w8f$xtBbKmtJb zh_5xNZ2n|7ln@kxE=O7k5D{)|7Vs1l{v{{;NE5(AuTZUq_!Vq8TrUAh0(ehT(bHsh zf1syxT*~z~5it?aawLxi;mGKdsiBqt=M+~Dq>UI#763;^kpOQ?z5XTjEl(<02e%WfOdX*a`4M?(z(t! zeDdbZ%AS~tSI;!70BI&4-U!Bha?+43fE*X>y0d;5cU9T;ND#6G!1G1rrg2??c=%)s zuyGjQWs8M`Qqk5cH?8YNt({PWAX@+?Unp#y#9R;V=sqhqt?Nduy?}%OvO2`JN86iC z0Mz$NBMxUT0Q(FcT9%1Xv5wA7yfE zq^m=zhe%H_MT$ve^WomE_K~{UrAqyu*GGUHTf~DBtBd3MClKig#TPx>**Q*ZKb;apbUZ7+Wph=SU84C7=P**4G1ZcWFXYv6!b6in?t?ZkIR*hzqbxZ-)|rvt0f} z-BG{L^r}DVK8j_M2XuPNs8bW!?wAW3pw|Z`0Nw!2f^%L0P2Ze-t?9I$OewhK)-B)3n}ZsssSnh^2xW+jW|O$0{kTi z6%@&<>-eURP1^AauRFFZA#wKKf-~yoDDUrRV%h?FVH?G+A$Exm9 z4#D>h^nA9sz~KXz5WCvb{_~Kz?T4DdeWo~w2vC|Y^N2*s zrFxjR*ZZM2Y$Ic}v>;`T>zy}pAyWbX=F9Mbye!_4DAY;XMD0(K#OtVBgnIcz1VG*O zO;R3-!$=bI-VppOqo zrO$`MPjBGAdfSys>xIq@rX@gwX$jC^S^_kfmH-W=B|w8|3D98v3o34g-ip=*Jpcdz M07*qoM6N<$g2!bWGynhq literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..e68e48986cbd715df660dbbba9586bd65d1f7412 GIT binary patch literal 3914 zcmaKvX*3jo7RQ-p7{)S)v4pX!EMtp=#+I=!p|VRfSt8k)G>U|nCS})H%Q8l?GZJOX zGIoQIC9?1P^1N^F)BAAmJ@=gdx%ZskIrpCPe{E)>$IQsfNJB%ztdG*MIIp<>2AJ+V z&)=G^rlDbF)7R0o45D4hFf_9r=6OyEdch2)j?iL*$G(4WgL=M-b1}sS;Emk+bmdnb z%mm;yR4r+l}hb%3Vfj1@BshM59|dP3fgXkt%SZe-S|_wShD6 zADW>VjqdAbgFX#Bx1O)fC?B3THG2!+bn!^1=fcZ0z=JnXloMD8*9g^uV})KK0oq_J zFbWD_U=jkdb8CS`5ikE&UxCAQ+`ea?5hNW#q` zs!0X1q-Gs=>a#F~F5N}5we^~LwI;rzV6qDJmNcM&g0Xi8$^^!Of#e<$rLjUTltVOA zlOdo%D&&HKL3k|j&ad6yJJ$x3BYY0(t!{U&RDAL%<`g3qPn$RYu-GJ9N4jGh+guU- ztkSibj(1z0C|Y^AclA__X1a35+DxrkP5w5+2%J7Mbgx|VC=rs&QL=~#b++0;=RD%N zR{6P2*`}Mo@Id;iS9oDz@$uLo(O79LkV;H_#mZ$@Kw724o)X<{LzNbFA`u8a>x{3D zINH7$07L9UQ3I0oqv(}GzvD4lCBDGHnQmUzg|a(=&9PUoB~>=PE&)AyBVfPDukzcg z#^pRu@D2H?0!jdT@5;Bp(Qc7^yKQ^3k99jrLi1j)b#!*G3RI+du(y#38a4MLbIk26 zLUMlYM!ZZnyflTjOsdla*n^t==$C@ZXg8U>egty3R}G6oJAc$~WRTzEvm+EnwR0|% zyIFa+K=>bem&NN!SG>=I$&OsPGOxwwL9H|tqkz(z3}V#;d;Mx|y+e+{#ZiiWMCvZa z%egn_!06}u#m#A9*QcQpV*$!zT_RAk{muUQ$H#LG%1cU8dfG~d#l3S74_;TrNl2Pq z6DOE1&v#!t@R=O{rLJ=QP|Q6md;efqPpR({^3UBc8SJ5LPqt$f06VgSJd%iJnyAV0 zm#y8d%2??VH*-9>j+fx{Wx6b(JX(BGQ~A9CAT5?_#qFG5v7BuWPq-gp%iEs2P2xEt zvxQ5ln3$4RYGUwOhWWrjraJ`9OlN5ZMa{3svYW?Hho*I_9Dhd}6&Xv{jMqC=8JdEO znT_|qsPY!CnDiKoaet?ueZV$v&zmBH_I*~4+M6(fPYLwbE2P}nzdVv&u z`z%{2%~`Syc(2FO4z2HCdc!DC+kd5?uL**37E5uM;5Hu$+$&%Gz4bYKM9ZvIn@LCAnZ|D0{_;N=DOXi*ZpH#(;`#J1;D zv27q#s0TqrzI+^gRE@;h<+K{DV*gQ1_ddzDC9>Wo_z`RBzAP>mOyk9ilLywr>WF(e zphcB>o;!xVFKDkOamj4!6SDF!*d{4gPxLF5bsdw zLNw>FjeG6Q+Ih@)YMpTzK#uRuE-Xp?udlt8^lq(~BihA|IzBP@mGl^!|AA9}ZY+W% zPi{pR%pc@y2_Q!NO_qz?U6!Qy9wwa=OaCiaSoB56o zGh91u0d7XNPKnVu=G}^SdHG_<^Y2wkYk|6bNI^qwaZ@i^*Rko(b}_fjq$>)JP-dY^ zpc3cMGy9qzs~&Qb!ew!HbDK_wY+mumz)jruxu2>s4b%H-*kRQ^)2?(C5v9o6iwge6 zZr=cy^zPbzbvU$kd$axvXMPk&xJnU8_{gIkPs=!2H@F+0D8aBziwN79I)5zu^Kqvh zNMJMI-@Tu=(uPaY!|89(5$gy0*RMz>s75juw}`_y{r&0WHMQYYi6~D)F2gUqF8}g! zOKFHxFCI&=hjc2sYw&PMa=-a`+%cpg+P9E23mPSSLEsGDc3BEb13MJr#+y{0$DE&I z3Tob7z&BeTb%V057bg%EgM3GOtYbrXqgRxcgF}+|)LAlwma)PwdT}U2^y_jYpJO+0 ztyhJG6U+6!t4ptA2$fN>%=>1BVPxyuBMt@~?)AuqXU#UUzzz<&`YaOq(yLUYqY-^W zNVEBwp-n4C>5GdDe5tXWeJWf^*oIVQ^MCB1Wg(@^>Cv0o$z1LLj5^=ubLuZKUC=z5 z|8^r?FxKIs_BFEWZ`^@+tO0_RynNp1n;VuNEWW|@mZ?xyJg!SvBWl79ff_r_Qc`hQ{SscYrZL2DhA`2JCOf|BSHK zv%v{i*eC7E6+jY;MVRwNl4!Ydu|FlypCLM^58pTdDJ)!r{wd(u&8SzaYQvq=6u?Qb zv6OB@7RKxvAcYWLJ|)?YRk~-&zhH-8Ll2NT8zJ{fF)=?kK%+bv zy~=0o=AKH$%TnS)HQNQT;9SpCXq#H8!PR629cwcAjkUVDPoj>L6;qsQC(t)!+e!mQ zX%(dMLTg0JhR4 z6l7P}IF6mWt^x+$Mwy?ofRYltPPLt6peb5f!qST<5t^?~f5|tW zV!=4nJ2e#e2hWEp1k02#CE4+Rd3a8&{RJ2;Z2(P|S3!TDOE#9o+)L4k+9P`SX1Y z*292R(bO1kpHUk>C#t0lr;OEi2R7;BSOYgz*jfdmO=F>=9OyM8IPdfmna6;dFlRjK zU7v99j_2*mtS*^%r|%Tu(~t_kdcoyP2^HD7Z-%ckzr$rWP+ENYQ(|DH+PwhMpV&s@ zb4oT74R_O&0mk&%n-6ar2A+R}4-WwwhOlZzo%|1Q3Ttp?KUl^Qy}v}IB*CEpk~XNe ztz~cLON}-39VDGpsg^@ecPhi=YSSH|05$i!2`im-CkD@l52_gxdDFJUFZ*}VziMB3 z-e}`lSXs8svm7*l+|s<_K6M3}VuQadF5353b|w||W431S$)+@uYsql!;-(fn`n`v2 zj};v7NC-!t;sF1qrC};CDLz>j<}6G}_~K%5VU3e;3_1*m?EEn?i*X>T2#R~tNW499 zhPg@cqSm_=Y9OBph)@MofZ z?+iO;1kiGqCb#t}#g~VC>D`QKrZSKm)exYxD0GY(YH4F>)^jw@JHnUzCQjfq@)sZP z7srY;8+g@6WBwnWKCo!yY0hw}XFg~2xG(nK(cz!Tnv;%o){;@<3>0e+^%?jOZpt`DxR}wgM?`zOTdMBmuwoikZlvUpZ$63VlKv(y;tT8Nno!L@reH)G`x9 z0;LN?_lMY%jil6rWgnSSZCHzcihEo&tV7)I0R2-^uKcVKt;Z<|`0j&%O;RBrE^?;- zR0(HcFZ14cEf9^X751{g`e z*35v5Sa89^&NLG^^oG~kyW^@n!XpxDtARd%CKc(1X{oR0?v|v?bNpco654C+4A4~- z?zze;XA(Dh!8zjwpN#3>>WJPEu7d06N-ehbhu^*XF^PFL6ktS3cd=zD48P0hc~>sC zd8J3~C7YA#n!IfmSU~rpJXRc<;)~BqVyRmRy(@P~qM;7{>yL$IZEOTY&i3 z6D1DS%(PW_k9;86ro@gbQ2XR#`Qjdk#R@L}w7P%tB~KIEz^to`<4a3kA^#*}i&~Wf zsi4J#GD}Dq@^9fsNmth-GRs%{$^_TAT4)ylY<3eA zcs}xh3ga!8RDq7D;G?N0OqZ5uT$?Te$Y<^A-p}@WHf}m+go`wM%?vHd3Al5%})?2Yero&kyIGAI^Q8bMJY*p7DAmm>TQT(_Eqf0D#`mK-Zi+6aO19D)Q5O z)*A`{Y^sL3T9!eetvoxl-M7cMCYJ3L4sP_r0`2M`Y#LB9?VzOfN2EU4VMMbd?VOY^-MhLV(R3x?4;$>s! z8ekupqVOFZQ==haa5>CQLqzX+`&8G|_lpV^BoCW~z6!t)Cu9#KSNs5DE$KOM#a_(- zk5w-vsqB&zp#KF6LRQ4m63rC;hgaS~YV5au<(?(+cUh}&TK=26Xg}H1JZ(DZDlf(7 zbllJT*!A~P`yITwvw&`*=fzJ=&7oiX)?X5rq`S@oEu2mnS!rlw&FxQLoA|i-LfP(L zxdA*>=NsGR_sHIm=KSgXEXSnEfA(!79;(zPOzf_<5#-yyyYKXLpYx@1lY_6_U7w22 zxaf;Gl3iX@q(Cp9L1HG~Kc;UEh!8~QU0HuwLDcG&*Ua(8^&|BwF5UfesmXg@kYC!0d2N2}=`t~7m!gDhY+Lp~7Ix&|!t0+P7cP!&6wSsWRHbc;{ zP0LKq>C7liY&6dVH^;KKh#jDh_>s~k8GemE>y3&$6UO-CSIGko$miuprH~prK59hH zL?=Tj1RLw3s5~>sj(MQoc{R`u{&ZoDC!&=p)<(;cu3Wz>V-AsubVd&sGn(ktZe9+`>H8eeBN`^-3p!=Vn+}LR<2v7_CYU68wL;i+L@efBf(!UH z#q@FARaqW+jn15U=&RV{^mlDbR`f9morL3o+2I%fHEFi{?Eb!P3M1s6mU~<36vw%_BF;-Se+gTdh^|N_0qOw#t3?YgNeU`r6JYwQQ)#!0dJ($4$=SB3H_Cj_ptkQqLoLdp)B5grzI1Hci{{+07$Nt!Rq>VUTOwwuBksBB}*frnZ%>Fq3@2LwDD2qhTWJ6(ML(UZ?@{f@olxT__z{8$9j1;`wP_kXecauyNq3l4H^6j>TU z3$!4=Pwg=?Va_W>>^7u(>}c+-(d}->7DR~cso8-ol_`sGF5r#g`zH^)ZAD1zCB3%HY|vvZgftUq zfZpnm<~8{MnGC&%JAYnBJ4haM-u1ZH_bX5>`_gbt#&2+ndvH2xu%n1N?8;S@v3@?Z z%E%cn8iv`vC$2JxZvYj_dDh!+$x(nbkem3!hTg7zJ+SPc_P!pQAxD$G`i0?FO3*18DTd)gd z7j&@QUq7XHxI!cxm}grk!d7K48l5 z!;>_-==)e;SCd9F!rARLgvL#|z&pRZ8IadNDm>O*_b_|-H?hcJmQ`3dDI55YQ&#Q;hnon3HC@gv}+j=I7AvqXp;)i)ztCJ#so zr;8hGh-ZWCLiA>gDAMMgQ(%Emi}JFTu8xiVeOpXu*}Z@3xlXw~)ncTX~irntXWMf%+HqVbod(Tm~||0kZHv7A&>xDGy9yb&ezlSHIVJj{GAHy!-? z^;<1AsAk{f)MMyZgD*|B@|3rclg)Zl#^`mAR2aZgY3emr<#Vsn>y@^>EuDj_`rDi6 z+3{*f&HVb3D#en-XfRx<;He^R6UixdbdaQjqOlP1FDeY`@N=Yt+=U={!hrI&OS9(Zq68xEhCTjM>89me{ zxLD~g{{nYE87`4ATDGpD z8}dw{!7vK5c7((gYmn)j0a=q+5mv8^^O+KnsSoFj(=a`}5HO&O-`X~;+8U|fGar6t zx*ccHR={VX-3eK{5jf!0?nVM*-JJEVf$f170DC4AJ5=gdracrTmBO;jH%?oC5wJ*Z zh4s}{_m(dXtB8UggVf9jF!?(2_I&oT?)QK^N?#D^uk#_Q$7_4%n0h1Zp;yuq`uzrv zR9Yao_R@<*FjmZcBHg^6YWx<48PHRvHQsWyX{KAeMPepxCC-mn;#W+yJ~2NHHrs(b z2kfGRC?R+c;KMoc*Am`s#kDP%`XIap1_XDq*Us~=pU~T%F4c_IL$?51kT;nsi!AH` z^VT0h{8iJ+6j&izU?Fy;xLP|@e2cO&QOe?2~J=dV*712fi@ucc}g|+ z`vwz+9HdgZ;*}|oIHe*8F}9#vy6x09LP^SSd;cbse%uAa2DHnHGm!$Z+v&Z0($>AU zRe)9v4WjCmcaKhP$j=&BVgQgBX@fg}SqzIjgdq&WCpZ@R8dNL6m5{(sZ7uDuTOvhz za_f}y6{G1Z!Kf7_c+%0+IeXya3pJ;HdGejN0XNQ%!Azt(%}2w|6uCAy#583M^ij}T zgt2T%rYSx!k_Y4{kz^5*1Px~$Mr4B909x*ZsVE^g2!1>&WPzu(w&hXH^G|(JsH+W4 zJ9v*3x;aUw#d)Q;2U*b%e>S1=soDT0Td^m!L}h&Mvvc-=&ne7A?k4q4zbAcF%B-%8 zi(M#f1EBqdMjSN*Pj?^9b{?D=^PS}(P8UfHcXm|B_S2O}uWRdBr`tY*Gb6ITX<{D; z-?lyT5S6o^)iM4Fg;XvSps8Cs~{14Zj`(4bvr}hac&3L9&q1De9cDcBeQA> zYnmc*VqETAs+c$vS|X+NvKfsPIYKL0btwn7`Fk#KuP6;Z1vn6507M8S z$bsreaa50Q2MEI$?3%XyP3E(UbPm!M50j(9ZM=awJQU~@-~tDOLTk5vokw<+p9^;B zTz7BQE?>v0B!zO7m@{zzE{sC#lCe@!xS^o+L}qS~6eKoSsafjR(js zK{I34?o*Re*mV_lhTC_u0Ym(M*Dj?YcjOE5;`u~&9NNzTQaT8RQlVpTIp!*WS#!*@ zft7WUgg^Qo22eAcA}Fg{hbFWkEt!(voKEOm<&zmnFsx?P-@7EeWa%m@6Zm1dJ zANx=BIuuS*kQeS{U>zw%l?N^>@T&I{_Z;?E2$z1$QehBt!c~CwP-}Pz8*489{AB0t z_HGfvP*kh9d=7*%9I$m@7Aqy^yAfz5ikT6K=po_CzAdLaR)#sTDv}Gdj?`b3g|ANp zx>HgX@ujQ8(~;EVrE8WnDTA;m@qB;I0A5Ce4^cGZ{P`g}t0YAx;%O{S=j?H#-Bqo(fZzNvc%9R9Z}H0!^={k3TfKJD2oqDxC3{JIc$z*%F01xi;Bd59 zt0-F{$I;u$fBYt)fzw~JpO?|g{zryx}*?djXkYGZtQ9>sWeCbz}_i*I+>c_`m z4cxxB z8K>?j+`*c0(duXy3$U{w5teVF%+V!*-ay;kPowv4q9{IZE z+~sB-)ykac#&sO6sU)x_M(p&x877!`Z!nEQI~mjSfa_NUFG$F9m=FCRm7$o^lD6hu zOL~k|Up+oR$>2i~6MW#_M>LLh`pobuQK=cMjh83XyZ`C?+O5G+L5btB!gp3x(}RSZ zS=wJ>%bz2`qN-I`EaETR(m3)essl*B$4pihGL#D;jR(`8f~#N9#;!i>i%Q~>o@>Z2 z;~-=7)n7(i>RqxucC7pPtQrRmn!(8bjZeAUVf)IDMi;a}$<(3mUhgcD_Sbf-mn|fO z)=e~O;;daM%~8hxo(Q%th7d5mOqr4@Mhsl4#&JTF%;k zi+`D(tS5!SCBn6Xl7xoA3hb|7D3!Ox0O#Z(N)gj#mRSyVL$HO3ZAqovfJA)7AqM1U(o%^eX#D4i$RtBgt zmP-hUBY&|k<~k1RwIh=?6TuwbdeH#vSAvME7e2HyQNk&wIk zU#Tv*nK)3lJn&Px%T$GDA6+FxSi8_6z%k+Kox2LIo3P$(oOtehYMtboe($pGiyRno z*2%K5Oh@g{|NYdPT(19Rhj-RFjJW>RQsQbBVkTDGEt zkKqFa-;0nJ{|R@*QqtCTdUCNn0Z!yYd)G9EPw(N+em5QQQSU;H`lB!HYPxLbB#MIG zoyOI0UvuB~iO^Nal1t44IBHr2(W7(@1qFD4AKHTm;H<|KxU-)g7SG{u9O(2+FCd-yV zu*&L%({BI2t*Ff1rLMDW>UB;pwiO5on-TLrHWdH=p5s4FdH3rkhjTN1 data; + MoreCategoryProducts(this.data); +} + +class CategoryChangeEvent { + int categoryId; + CategoryChangeEvent(this.categoryId); } \ No newline at end of file diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart index d937362..21b38e2 100644 --- a/lib/generated/intl/messages_en.dart +++ b/lib/generated/intl/messages_en.dart @@ -35,53 +35,57 @@ class MessageLookup extends MessageLookupByLibrary { static m7(discount) => "-\$${discount}"; - static m8(oss) => "Download at ${oss}"; + static m8(domain) => "${domain} (available)"; - static m9(expirationDate) => "Expires on ${expirationDate}"; + static m9(domain) => "${domain} (unavailable)"; - static m10(mon, yer) => "Exp: ${mon}/${yer}"; + static m10(oss) => "Download at ${oss}"; - static m11(name, rate) => "${name}(${rate}%)"; + static m11(expirationDate) => "Expires on ${expirationDate}"; - static m12(num) => "${num} follow-ups"; + static m12(mon, yer) => "Exp: ${mon}/${yer}"; - static m13(second) => "Retry after ${second}s"; + static m13(name, rate) => "${name}(${rate}%)"; - static m14(hours) => "${Intl.plural(hours, one: '1 hr', other: '${hours} hrs')}"; + static m14(num) => "${num} follow-ups"; - static m15(minamount) => "\$${minamount}+"; + static m15(second) => "Retry after ${second}s"; - static m16(shipfee) => "Delivery \$${shipfee}+"; + static m16(hours) => "${Intl.plural(hours, one: '1 hr', other: '${hours} hrs')}"; - static m17(minutes) => "${Intl.plural(minutes, one: '1 min', other: '${minutes} mins')}"; + static m17(minamount) => "\$${minamount}+"; - static m18(minprice) => "${minprice} more"; + static m18(shipfee) => "Delivery \$${shipfee}+"; - static m19(amount) => "Pay \$${amount} now"; + static m19(minutes) => "${Intl.plural(minutes, one: '1 min', other: '${minutes} mins')}"; - static m20(method) => "Pay with ${method}"; + static m20(minprice) => "${minprice} more"; - static m21(mobile) => "Payment verification code has been sent to your mobile phone ${mobile}. Please enter the verification code below."; + static m21(amount) => "Pay \$${amount} now"; - static m22(discount) => "${discount}%off"; + static m22(method) => "Pay with ${method}"; - static m23(amount, discount) => "-\$${amount}(${discount}%off)"; + static m23(p1, p2) => "Payment verification code has been sent to your ${p1} ${p2}. Please enter the verification code below."; - static m24(optionName) => "Please choice ${optionName}."; + static m24(discount) => "${discount}%off"; - static m25(sold_qty) => " ${sold_qty} sold/mo"; + static m25(amount, discount) => "-\$${amount}(${discount}%off)"; - static m26(subtotal) => "Subtotal: ${subtotal}"; + static m26(optionName) => "Please choice ${optionName}."; - static m27(num) => "Table#: ${num}"; + static m27(sold_qty) => " ${sold_qty} sold/mo"; - static m28(num) => "Ticket #${num}"; + static m28(subtotal) => "Subtotal: ${subtotal}"; - static m29(time) => "Today ${time}"; + static m29(num) => "Table#: ${num}"; - static m30(time) => "Tomorrow ${time}"; + static m30(num) => "Ticket #${num}"; - static m31(weight) => "Weight: ${weight}"; + static m31(time) => "Today ${time}"; + + static m32(time) => "Tomorrow ${time}"; + + static m33(weight) => "Weight: ${weight}"; final messages = _notInlinedMessages(_notInlinedMessages); static _notInlinedMessages(_) => { @@ -130,6 +134,7 @@ class MessageLookup extends MessageLookupByLibrary { "change_nickname" : MessageLookupByLibrary.simpleMessage("Change nickname"), "change_password" : MessageLookupByLibrary.simpleMessage("Change password"), "change_password_desc" : MessageLookupByLibrary.simpleMessage("Please enter the old password and your desired new password."), + "check_domain_name" : MessageLookupByLibrary.simpleMessage("Check availability"), "check_option_is_optional" : MessageLookupByLibrary.simpleMessage("Optional. You can tap Next without selection."), "check_option_is_required" : MessageLookupByLibrary.simpleMessage("Option is required. Select at lease an option then tap Next."), "check_option_select_token" : m3, @@ -152,6 +157,7 @@ class MessageLookup extends MessageLookupByLibrary { "contact_us" : MessageLookupByLibrary.simpleMessage("Contact us"), "copy" : MessageLookupByLibrary.simpleMessage("Copy"), "coupons" : MessageLookupByLibrary.simpleMessage("Coupons"), + "create_a_online_store" : MessageLookupByLibrary.simpleMessage("Open an online store"), "credit_card" : MessageLookupByLibrary.simpleMessage("Credit card"), "credit_coupon" : MessageLookupByLibrary.simpleMessage("Credit/Coupon"), "credit_debit_card" : MessageLookupByLibrary.simpleMessage("Credit or debit card"), @@ -174,9 +180,13 @@ class MessageLookup extends MessageLookupByLibrary { "discount_amount_token" : m7, "document_langage" : MessageLookupByLibrary.simpleMessage("Document language"), "document_type" : MessageLookupByLibrary.simpleMessage("Document type"), + "domain_available_token" : m8, + "domain_name" : MessageLookupByLibrary.simpleMessage("Domain name"), + "domain_unavailable_token" : m9, + "domains_separated_comma" : MessageLookupByLibrary.simpleMessage("Domains separated by comma"), "dont_use" : MessageLookupByLibrary.simpleMessage("Do not redeem"), "download" : MessageLookupByLibrary.simpleMessage("Download"), - "download_with_token" : m8, + "download_with_token" : m10, "downloads" : MessageLookupByLibrary.simpleMessage("Downloads"), "edit_address" : MessageLookupByLibrary.simpleMessage("Edit address"), "email" : MessageLookupByLibrary.simpleMessage("Email"), @@ -190,22 +200,24 @@ class MessageLookup extends MessageLookupByLibrary { "english" : MessageLookupByLibrary.simpleMessage("English"), "enter_coupon_code" : MessageLookupByLibrary.simpleMessage("Enter coupon code"), "enter_delivery_address" : MessageLookupByLibrary.simpleMessage("Enter delivery address"), + "enter_desired_domain" : MessageLookupByLibrary.simpleMessage("Your desired domain name"), + "enter_keyword" : MessageLookupByLibrary.simpleMessage("Enter keyword"), "enter_mobile_or_email" : MessageLookupByLibrary.simpleMessage("Enter mobile or email"), "enter_new_nickname" : MessageLookupByLibrary.simpleMessage("Enter new nickname"), "enter_product_keyword" : MessageLookupByLibrary.simpleMessage("Enter product keyword"), "error" : MessageLookupByLibrary.simpleMessage("Error"), "error_read_file" : MessageLookupByLibrary.simpleMessage("Error occurred while reading the file."), "expiration_date" : MessageLookupByLibrary.simpleMessage("Expiration date"), - "expiration_date_token" : m9, - "expire_token" : m10, + "expiration_date_token" : m11, + "expire_token" : m12, "expired_at" : MessageLookupByLibrary.simpleMessage("Expired at"), - "extra_fee_token" : m11, + "extra_fee_token" : m13, "fax" : MessageLookupByLibrary.simpleMessage("Fax"), "feature_not_available_web" : MessageLookupByLibrary.simpleMessage("This feature is not available on the web. Please install the App version."), "featured_product" : MessageLookupByLibrary.simpleMessage("Featured"), "finish" : MessageLookupByLibrary.simpleMessage("Finish"), "follow_ups" : MessageLookupByLibrary.simpleMessage("Follow ups"), - "followups_token" : m12, + "followups_token" : m14, "forgot_password" : MessageLookupByLibrary.simpleMessage("Forgot password"), "forgot_password_description" : MessageLookupByLibrary.simpleMessage("Enter the Email or mobile number you used when registering, and then click the \'Get code\' button to get the validation code."), "forgot_password_question" : MessageLookupByLibrary.simpleMessage("Forgot password?"), @@ -217,7 +229,7 @@ class MessageLookup extends MessageLookupByLibrary { "general_coupon" : MessageLookupByLibrary.simpleMessage("General coupon"), "get_code" : MessageLookupByLibrary.simpleMessage("Get code"), "get_code_again" : MessageLookupByLibrary.simpleMessage("Get code again"), - "get_code_token" : m13, + "get_code_token" : m15, "get_coupon" : MessageLookupByLibrary.simpleMessage("Get coupon"), "get_picture" : MessageLookupByLibrary.simpleMessage("Get picture"), "get_picture_from" : MessageLookupByLibrary.simpleMessage("Get picture from..."), @@ -226,7 +238,7 @@ class MessageLookup extends MessageLookupByLibrary { "group_number_can_be_found" : MessageLookupByLibrary.simpleMessage("Group number can be found..."), "home" : MessageLookupByLibrary.simpleMessage("Home"), "hot_sale" : MessageLookupByLibrary.simpleMessage("Hot sale"), - "hour_token" : m14, + "hour_token" : m16, "igoshow" : MessageLookupByLibrary.simpleMessage("iGoShow"), "includes" : MessageLookupByLibrary.simpleMessage("Includes"), "information" : MessageLookupByLibrary.simpleMessage("Information"), @@ -245,10 +257,11 @@ class MessageLookup extends MessageLookupByLibrary { "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."), "me" : MessageLookupByLibrary.simpleMessage("Me"), - "min_order_amount_token" : m15, - "min_shipping_fee" : m16, + "min_order_amount_token" : m17, + "min_shipping_fee" : m18, "minipos" : MessageLookupByLibrary.simpleMessage("MiniPOS"), - "minute_token" : m17, + "minute_token" : m19, + "mobile" : MessageLookupByLibrary.simpleMessage("mobile"), "mobile_email_username" : MessageLookupByLibrary.simpleMessage("Mobile, Email or MiniOffice username"), "mobile_is_required" : MessageLookupByLibrary.simpleMessage("Mobile is required"), "mobile_number" : MessageLookupByLibrary.simpleMessage("Mobile number"), @@ -293,6 +306,7 @@ class MessageLookup extends MessageLookupByLibrary { "ok" : MessageLookupByLibrary.simpleMessage("OK"), "old_password" : MessageLookupByLibrary.simpleMessage("Old password"), "online_payment" : MessageLookupByLibrary.simpleMessage("Online payment"), + "open_online_store" : MessageLookupByLibrary.simpleMessage("Open an online store"), "optional_information" : MessageLookupByLibrary.simpleMessage("Optional Info."), "order_acceipt" : MessageLookupByLibrary.simpleMessage("Accept"), "order_again" : MessageLookupByLibrary.simpleMessage("Order again"), @@ -302,7 +316,7 @@ class MessageLookup extends MessageLookupByLibrary { "order_detail" : MessageLookupByLibrary.simpleMessage("Order detail"), "order_fulfillment" : MessageLookupByLibrary.simpleMessage("Order fulfillment"), "order_info" : MessageLookupByLibrary.simpleMessage("Order info."), - "order_more" : m18, + "order_more" : m20, "order_number" : MessageLookupByLibrary.simpleMessage("Order No."), "order_number_copied_to_clipboard" : MessageLookupByLibrary.simpleMessage("Order number copied to clipboard"), "order_processing" : MessageLookupByLibrary.simpleMessage("Processing"), @@ -317,30 +331,31 @@ class MessageLookup extends MessageLookupByLibrary { "password_is_required" : MessageLookupByLibrary.simpleMessage("Password is required."), "pay" : MessageLookupByLibrary.simpleMessage("Pay"), "pay_after_meal" : MessageLookupByLibrary.simpleMessage("Pay after meal"), - "pay_amount_token" : m19, + "pay_amount_token" : m21, "pay_later" : MessageLookupByLibrary.simpleMessage("Pay later"), "pay_now" : MessageLookupByLibrary.simpleMessage("Pay now"), "pay_on_deliery" : MessageLookupByLibrary.simpleMessage("Pay on delivery"), "pay_on_deliery_pickup" : MessageLookupByLibrary.simpleMessage("Pay on delivery or pickup"), "pay_with" : MessageLookupByLibrary.simpleMessage("Pay with"), "pay_with_existing_cards" : MessageLookupByLibrary.simpleMessage("Pay with existing cards"), - "pay_with_token" : m20, + "pay_with_token" : m22, "payment_amount" : MessageLookupByLibrary.simpleMessage("Payment amount"), "payment_method" : MessageLookupByLibrary.simpleMessage("Payment method"), "payment_method_not_set" : MessageLookupByLibrary.simpleMessage("No payment method specified. Please pay on delivery or pickup."), "payment_status" : MessageLookupByLibrary.simpleMessage("Payment status"), "payment_verification" : MessageLookupByLibrary.simpleMessage("Payment verification"), - "payment_verification_sent" : m21, + "payment_verification_sent" : m23, "paypal" : MessageLookupByLibrary.simpleMessage("Paypal"), "pending" : MessageLookupByLibrary.simpleMessage("Pending"), "percent_discount" : MessageLookupByLibrary.simpleMessage("%OFF"), - "percentage_discount_token" : m22, - "percentage_discount_token2" : m23, + "percentage_discount_token" : m24, + "percentage_discount_token2" : m25, "pick_a_coupon" : MessageLookupByLibrary.simpleMessage("Pick a coupon"), "pickup" : MessageLookupByLibrary.simpleMessage("Pickup"), "pickup_address" : MessageLookupByLibrary.simpleMessage("Pickup address"), "pickup_at" : MessageLookupByLibrary.simpleMessage("Please pickup at"), "pickup_discount" : MessageLookupByLibrary.simpleMessage("Pickup discount"), + "place_order_now" : MessageLookupByLibrary.simpleMessage("Place order now"), "please_enter_coupon_code" : MessageLookupByLibrary.simpleMessage("Please enter a coupon code."), "please_enter_group_number" : MessageLookupByLibrary.simpleMessage("Please enter your group number."), "please_login" : MessageLookupByLibrary.simpleMessage("Please login"), @@ -364,7 +379,7 @@ class MessageLookup extends MessageLookupByLibrary { "quick_input" : MessageLookupByLibrary.simpleMessage("Quick input"), "radio_option_is_optional" : MessageLookupByLibrary.simpleMessage("Optional. You can tap Next without selection."), "radio_option_is_required" : MessageLookupByLibrary.simpleMessage("Option is required. Select an option then tap Next."), - "radio_option_select_token" : m24, + "radio_option_select_token" : m26, "recalculating" : MessageLookupByLibrary.simpleMessage("Recalculating..."), "red_coupon" : MessageLookupByLibrary.simpleMessage("Coupon"), "redeem_coupon" : MessageLookupByLibrary.simpleMessage("Redeem"), @@ -372,6 +387,7 @@ class MessageLookup extends MessageLookupByLibrary { "registration" : MessageLookupByLibrary.simpleMessage("Registration"), "release_to_load_more" : MessageLookupByLibrary.simpleMessage("Release to load more"), "renew_license" : MessageLookupByLibrary.simpleMessage("Renew license"), + "renew_service_now" : MessageLookupByLibrary.simpleMessage("Renew service now"), "renewal_fee" : MessageLookupByLibrary.simpleMessage("Renewal fee"), "reply" : MessageLookupByLibrary.simpleMessage("Reply"), "reset_password" : MessageLookupByLibrary.simpleMessage("Reset password"), @@ -384,12 +400,14 @@ class MessageLookup extends MessageLookupByLibrary { "saturday" : MessageLookupByLibrary.simpleMessage("Saturday"), "save" : MessageLookupByLibrary.simpleMessage("Save"), "schedule_delivery" : MessageLookupByLibrary.simpleMessage("Schedule delivery"), + "search" : MessageLookupByLibrary.simpleMessage("Search"), "search_place" : MessageLookupByLibrary.simpleMessage("Search place"), "search_product" : MessageLookupByLibrary.simpleMessage("Search product"), "search_products" : MessageLookupByLibrary.simpleMessage("Search products"), "select" : MessageLookupByLibrary.simpleMessage("Select"), "select_a_payment_method" : MessageLookupByLibrary.simpleMessage("Select a payment method"), "select_a_plan" : MessageLookupByLibrary.simpleMessage("Select a plan"), + "select_a_store" : MessageLookupByLibrary.simpleMessage("Select a store"), "select_canada_post_shipping_rate" : MessageLookupByLibrary.simpleMessage("Please select Canada Post shipping rate."), "select_delivery_time" : MessageLookupByLibrary.simpleMessage("Select delivery time"), "select_document_lanuage" : MessageLookupByLibrary.simpleMessage("Select a language"), @@ -404,7 +422,7 @@ class MessageLookup extends MessageLookupByLibrary { "shop" : MessageLookupByLibrary.simpleMessage("Shop"), "show_less" : MessageLookupByLibrary.simpleMessage("Show less"), "show_more" : MessageLookupByLibrary.simpleMessage("Show more"), - "sold_per_month_token" : m25, + "sold_per_month_token" : m27, "specification" : MessageLookupByLibrary.simpleMessage("Specification"), "store" : MessageLookupByLibrary.simpleMessage("Store"), "store_closed" : MessageLookupByLibrary.simpleMessage("Store closed"), @@ -420,13 +438,13 @@ class MessageLookup extends MessageLookupByLibrary { "submitting" : MessageLookupByLibrary.simpleMessage("Submitting..."), "submitting_please_wait" : MessageLookupByLibrary.simpleMessage("Submitting, please wait..."), "subtotal" : MessageLookupByLibrary.simpleMessage("Subtotal"), - "subtotal_token" : m26, + "subtotal_token" : m28, "success" : MessageLookupByLibrary.simpleMessage("Success"), "sun" : MessageLookupByLibrary.simpleMessage("Sun"), "sunday" : MessageLookupByLibrary.simpleMessage("Sunday"), "support" : MessageLookupByLibrary.simpleMessage("Support"), "support_ticket" : MessageLookupByLibrary.simpleMessage("Support ticket"), - "table_token" : m27, + "table_token" : m29, "tap_back_again_to_exit" : MessageLookupByLibrary.simpleMessage("Tap back again to exit"), "tax" : MessageLookupByLibrary.simpleMessage("Tax"), "thank_you_for_your_comment" : MessageLookupByLibrary.simpleMessage("Thank you for your comment."), @@ -439,12 +457,12 @@ class MessageLookup extends MessageLookupByLibrary { "thu" : MessageLookupByLibrary.simpleMessage("Thu"), "thursday" : MessageLookupByLibrary.simpleMessage("Thursday"), "ticket_created_success" : MessageLookupByLibrary.simpleMessage("Ticket has been created successfully."), - "ticket_number_token" : m28, + "ticket_number_token" : m30, "today" : MessageLookupByLibrary.simpleMessage("Today"), - "today_with_time" : m29, + "today_with_time" : m31, "toll_free" : MessageLookupByLibrary.simpleMessage("Toll free: "), "tomorrow" : MessageLookupByLibrary.simpleMessage("Tomorrow"), - "tomorrow_with_time" : m30, + "tomorrow_with_time" : m32, "total" : MessageLookupByLibrary.simpleMessage("Total"), "tue" : MessageLookupByLibrary.simpleMessage("Tue"), "tuesday" : MessageLookupByLibrary.simpleMessage("Tuesday"), @@ -469,7 +487,7 @@ class MessageLookup extends MessageLookupByLibrary { "wechatpay" : MessageLookupByLibrary.simpleMessage("Wechat pay"), "wed" : MessageLookupByLibrary.simpleMessage("Wed"), "wednesday" : MessageLookupByLibrary.simpleMessage("Wednesday"), - "weight_token" : m31, + "weight_token" : m33, "wiki" : MessageLookupByLibrary.simpleMessage("Wiki"), "wrong_payment_verification_code" : MessageLookupByLibrary.simpleMessage("Wrong payment verification code. Please check and enter again."), "yes" : MessageLookupByLibrary.simpleMessage("Yes"), diff --git a/lib/generated/intl/messages_zh_CN.dart b/lib/generated/intl/messages_zh_CN.dart index b9e1e94..8561754 100644 --- a/lib/generated/intl/messages_zh_CN.dart +++ b/lib/generated/intl/messages_zh_CN.dart @@ -35,53 +35,57 @@ class MessageLookup extends MessageLookupByLibrary { static m7(discount) => "-\$${discount}"; - static m8(oss) => "在${oss}下载"; + static m8(domain) => "${domain} (可用)"; - static m9(expirationDate) => "${expirationDate}到期"; + static m9(domain) => "${domain} (不可用)"; - static m10(mon, yer) => "到期:${mon}/${yer}"; + static m10(oss) => "在${oss}下载"; - static m11(name, rate) => "${name}(${rate}%)"; + static m11(expirationDate) => "${expirationDate}到期"; - static m12(num) => "${num}条回复"; + static m12(mon, yer) => "到期:${mon}/${yer}"; - static m13(second) => "${second}秒后重试"; + static m13(name, rate) => "${name}(${rate}%)"; - static m14(hours) => "${Intl.plural(hours, one: '1小时', other: '${hours}小时')}"; + static m14(num) => "${num}条回复"; - static m15(minamount) => "\$${minamount}起送"; + static m15(second) => "${second}秒后重试"; - static m16(shipfee) => "配送费\$${shipfee}起"; + static m16(hours) => "${Intl.plural(hours, one: '1小时', other: '${hours}小时')}"; - static m17(minutes) => "${Intl.plural(minutes, one: '1分钟', other: '${minutes}分钟')}"; + static m17(minamount) => "\$${minamount}起送"; - static m18(minprice) => "还差${minprice}起送"; + static m18(shipfee) => "配送费\$${shipfee}起"; - static m19(amount) => "马上付款 \$${amount}"; + static m19(minutes) => "${Intl.plural(minutes, one: '1分钟', other: '${minutes}分钟')}"; - static m20(method) => "使用${method}付款"; + static m20(minprice) => "还差${minprice}起送"; - static m21(mobile) => "付款码已经发送到您的手机${mobile}。请在下面输入付款码。"; + static m21(amount) => "马上付款 \$${amount}"; - static m22(discount) => "${discount}%折扣"; + static m22(method) => "使用${method}付款"; - static m23(amount, discount) => "-\$${amount}(${discount}%折扣)"; + static m23(p1, p2) => "付款码已经发送到您的${p1}${p2}。请在下面输入付款码。"; - static m24(optionName) => "请选择${optionName}"; + static m24(discount) => "${discount}%折扣"; - static m25(sold_qty) => " 月售${sold_qty}单"; + static m25(amount, discount) => "-\$${amount}(${discount}%折扣)"; - static m26(subtotal) => "小计:${subtotal}"; + static m26(optionName) => "请选择${optionName}"; - static m27(num) => "桌号:${num}"; + static m27(sold_qty) => " 月售${sold_qty}单"; - static m28(num) => "票号 #${num}"; + static m28(subtotal) => "小计:${subtotal}"; - static m29(time) => "今天${time}"; + static m29(num) => "桌号:${num}"; - static m30(time) => "明天${time}"; + static m30(num) => "票号 #${num}"; - static m31(weight) => "重量:${weight}"; + static m31(time) => "今天${time}"; + + static m32(time) => "明天${time}"; + + static m33(weight) => "重量:${weight}"; final messages = _notInlinedMessages(_notInlinedMessages); static _notInlinedMessages(_) => { @@ -129,6 +133,7 @@ class MessageLookup extends MessageLookupByLibrary { "change_nickname" : MessageLookupByLibrary.simpleMessage("修改昵称"), "change_password" : MessageLookupByLibrary.simpleMessage("修改密码"), "change_password_desc" : MessageLookupByLibrary.simpleMessage("请输入旧密码和希望的新密码。"), + "check_domain_name" : MessageLookupByLibrary.simpleMessage("检查是否可用"), "check_option_is_optional" : MessageLookupByLibrary.simpleMessage("可选选项。如果不选择可以直接点下一步。"), "check_option_is_required" : MessageLookupByLibrary.simpleMessage("选项必选。选择至少一项再点击下一步。"), "check_option_select_token" : m3, @@ -150,6 +155,7 @@ class MessageLookup extends MessageLookupByLibrary { "contact_us" : MessageLookupByLibrary.simpleMessage("联系我们"), "copy" : MessageLookupByLibrary.simpleMessage("复制"), "coupons" : MessageLookupByLibrary.simpleMessage("优惠券"), + "create_a_online_store" : MessageLookupByLibrary.simpleMessage("开网店"), "credit_card" : MessageLookupByLibrary.simpleMessage("信用卡"), "credit_coupon" : MessageLookupByLibrary.simpleMessage("红包/抵用券"), "credit_debit_card" : MessageLookupByLibrary.simpleMessage("信用卡或银行卡"), @@ -172,9 +178,13 @@ class MessageLookup extends MessageLookupByLibrary { "discount_amount_token" : m7, "document_langage" : MessageLookupByLibrary.simpleMessage("文档语言"), "document_type" : MessageLookupByLibrary.simpleMessage("文件类型"), + "domain_available_token" : m8, + "domain_name" : MessageLookupByLibrary.simpleMessage("域名"), + "domain_unavailable_token" : m9, + "domains_separated_comma" : MessageLookupByLibrary.simpleMessage("逗号分开多个域名"), "dont_use" : MessageLookupByLibrary.simpleMessage("不使用"), "download" : MessageLookupByLibrary.simpleMessage("下载"), - "download_with_token" : m8, + "download_with_token" : m10, "downloads" : MessageLookupByLibrary.simpleMessage("下载"), "edit_address" : MessageLookupByLibrary.simpleMessage("修改地址"), "email" : MessageLookupByLibrary.simpleMessage("电子邮箱"), @@ -188,22 +198,24 @@ class MessageLookup extends MessageLookupByLibrary { "english" : MessageLookupByLibrary.simpleMessage("英文"), "enter_coupon_code" : MessageLookupByLibrary.simpleMessage("输入红包号码"), "enter_delivery_address" : MessageLookupByLibrary.simpleMessage("输入送货地址"), + "enter_desired_domain" : MessageLookupByLibrary.simpleMessage("您想要的域名"), + "enter_keyword" : MessageLookupByLibrary.simpleMessage("输入关键字"), "enter_mobile_or_email" : MessageLookupByLibrary.simpleMessage("输入手机号码或电子邮箱地址"), "enter_new_nickname" : MessageLookupByLibrary.simpleMessage("输入新昵称"), "enter_product_keyword" : MessageLookupByLibrary.simpleMessage("输入产品关键字"), "error" : MessageLookupByLibrary.simpleMessage("错误"), "error_read_file" : MessageLookupByLibrary.simpleMessage("读取文件过程中出错。"), "expiration_date" : MessageLookupByLibrary.simpleMessage("到期日期"), - "expiration_date_token" : m9, - "expire_token" : m10, + "expiration_date_token" : m11, + "expire_token" : m12, "expired_at" : MessageLookupByLibrary.simpleMessage("到期日期"), - "extra_fee_token" : m11, + "extra_fee_token" : m13, "fax" : MessageLookupByLibrary.simpleMessage("传真"), "feature_not_available_web" : MessageLookupByLibrary.simpleMessage("该功能在网页版上不能用。请下载App版本。"), "featured_product" : MessageLookupByLibrary.simpleMessage("特色产品"), "finish" : MessageLookupByLibrary.simpleMessage("完成"), "follow_ups" : MessageLookupByLibrary.simpleMessage("跟进"), - "followups_token" : m12, + "followups_token" : m14, "forgot_password" : MessageLookupByLibrary.simpleMessage("忘记密码"), "forgot_password_description" : MessageLookupByLibrary.simpleMessage("输入您注册时用的Email或手机号码,然后点击‘获取验证码’ 按钮。"), "forgot_password_question" : MessageLookupByLibrary.simpleMessage("忘记密码?"), @@ -215,7 +227,7 @@ class MessageLookup extends MessageLookupByLibrary { "general_coupon" : MessageLookupByLibrary.simpleMessage("通用优惠券"), "get_code" : MessageLookupByLibrary.simpleMessage("获取验证码"), "get_code_again" : MessageLookupByLibrary.simpleMessage("重新获取验证码"), - "get_code_token" : m13, + "get_code_token" : m15, "get_coupon" : MessageLookupByLibrary.simpleMessage("获取红包"), "get_picture" : MessageLookupByLibrary.simpleMessage("获取图片"), "get_picture_from" : MessageLookupByLibrary.simpleMessage("从...获取图片"), @@ -224,7 +236,7 @@ class MessageLookup extends MessageLookupByLibrary { "group_number_can_be_found" : MessageLookupByLibrary.simpleMessage("按如下图找到集团号码..."), "home" : MessageLookupByLibrary.simpleMessage("首页"), "hot_sale" : MessageLookupByLibrary.simpleMessage("热卖"), - "hour_token" : m14, + "hour_token" : m16, "igoshow" : MessageLookupByLibrary.simpleMessage("iGoShow"), "includes" : MessageLookupByLibrary.simpleMessage("包含"), "information" : MessageLookupByLibrary.simpleMessage("信息"), @@ -243,10 +255,11 @@ class MessageLookup extends MessageLookupByLibrary { "logout" : MessageLookupByLibrary.simpleMessage("登出"), "main_content_1" : MessageLookupByLibrary.simpleMessage("自从1999年来,我们一直致力于开发完整的强大的销售系统,帮助了上千小企业平滑的处理销售业务。当前我们有两个主要的产品。"), "me" : MessageLookupByLibrary.simpleMessage("我的"), - "min_order_amount_token" : m15, - "min_shipping_fee" : m16, + "min_order_amount_token" : m17, + "min_shipping_fee" : m18, "minipos" : MessageLookupByLibrary.simpleMessage("MiniPOS"), - "minute_token" : m17, + "minute_token" : m19, + "mobile" : MessageLookupByLibrary.simpleMessage("手机"), "mobile_email_username" : MessageLookupByLibrary.simpleMessage("手机号码,Email或MiniOffice用户名"), "mobile_is_required" : MessageLookupByLibrary.simpleMessage("手机号码必填"), "mobile_number" : MessageLookupByLibrary.simpleMessage("手机号码"), @@ -290,6 +303,7 @@ class MessageLookup extends MessageLookupByLibrary { "ok" : MessageLookupByLibrary.simpleMessage("确定"), "old_password" : MessageLookupByLibrary.simpleMessage("旧密码"), "online_payment" : MessageLookupByLibrary.simpleMessage("在线付款"), + "open_online_store" : MessageLookupByLibrary.simpleMessage("开网店"), "optional_information" : MessageLookupByLibrary.simpleMessage("可选填信息"), "order_acceipt" : MessageLookupByLibrary.simpleMessage("已接单"), "order_again" : MessageLookupByLibrary.simpleMessage("再来一单"), @@ -299,7 +313,7 @@ class MessageLookup extends MessageLookupByLibrary { "order_detail" : MessageLookupByLibrary.simpleMessage("订单详情"), "order_fulfillment" : MessageLookupByLibrary.simpleMessage("订单完成度"), "order_info" : MessageLookupByLibrary.simpleMessage("订单信息"), - "order_more" : m18, + "order_more" : m20, "order_number" : MessageLookupByLibrary.simpleMessage("订单号码"), "order_number_copied_to_clipboard" : MessageLookupByLibrary.simpleMessage("订单号码复制到剪切板"), "order_processing" : MessageLookupByLibrary.simpleMessage("准备中"), @@ -314,30 +328,31 @@ class MessageLookup extends MessageLookupByLibrary { "password_is_required" : MessageLookupByLibrary.simpleMessage("密码必填。"), "pay" : MessageLookupByLibrary.simpleMessage("付款"), "pay_after_meal" : MessageLookupByLibrary.simpleMessage("餐后付款"), - "pay_amount_token" : m19, + "pay_amount_token" : m21, "pay_later" : MessageLookupByLibrary.simpleMessage("稍后付款"), "pay_now" : MessageLookupByLibrary.simpleMessage("去支付"), "pay_on_deliery" : MessageLookupByLibrary.simpleMessage("到货付款"), "pay_on_deliery_pickup" : MessageLookupByLibrary.simpleMessage("自提或到货付款"), "pay_with" : MessageLookupByLibrary.simpleMessage("使用"), "pay_with_existing_cards" : MessageLookupByLibrary.simpleMessage("用现有的卡付款"), - "pay_with_token" : m20, + "pay_with_token" : m22, "payment_amount" : MessageLookupByLibrary.simpleMessage("付款金额"), "payment_method" : MessageLookupByLibrary.simpleMessage("付款方式"), "payment_method_not_set" : MessageLookupByLibrary.simpleMessage("没有指定付款方式,请货到付款或自提付款。"), "payment_status" : MessageLookupByLibrary.simpleMessage("付款状态"), "payment_verification" : MessageLookupByLibrary.simpleMessage("付款验证"), - "payment_verification_sent" : m21, + "payment_verification_sent" : m23, "paypal" : MessageLookupByLibrary.simpleMessage("Paypal"), "pending" : MessageLookupByLibrary.simpleMessage("待接单"), "percent_discount" : MessageLookupByLibrary.simpleMessage("%折扣"), - "percentage_discount_token" : m22, - "percentage_discount_token2" : m23, + "percentage_discount_token" : m24, + "percentage_discount_token2" : m25, "pick_a_coupon" : MessageLookupByLibrary.simpleMessage("使用红包"), "pickup" : MessageLookupByLibrary.simpleMessage("到店自提"), "pickup_address" : MessageLookupByLibrary.simpleMessage("自提地址"), "pickup_at" : MessageLookupByLibrary.simpleMessage("自提地址"), "pickup_discount" : MessageLookupByLibrary.simpleMessage("自提折扣"), + "place_order_now" : MessageLookupByLibrary.simpleMessage("马上下单"), "please_enter_coupon_code" : MessageLookupByLibrary.simpleMessage("请输入红包号码。"), "please_enter_group_number" : MessageLookupByLibrary.simpleMessage("请输入您的集团号码。"), "please_login" : MessageLookupByLibrary.simpleMessage("请登陆"), @@ -361,7 +376,7 @@ class MessageLookup extends MessageLookupByLibrary { "quick_input" : MessageLookupByLibrary.simpleMessage("快速输入"), "radio_option_is_optional" : MessageLookupByLibrary.simpleMessage("可选选项。如果不选择可以直接点下一步。"), "radio_option_is_required" : MessageLookupByLibrary.simpleMessage("选项必选。选择一个选项后点下一步。"), - "radio_option_select_token" : m24, + "radio_option_select_token" : m26, "recalculating" : MessageLookupByLibrary.simpleMessage("运算中..."), "red_coupon" : MessageLookupByLibrary.simpleMessage("红包"), "redeem_coupon" : MessageLookupByLibrary.simpleMessage("去使用"), @@ -369,6 +384,7 @@ class MessageLookup extends MessageLookupByLibrary { "registration" : MessageLookupByLibrary.simpleMessage("注册"), "release_to_load_more" : MessageLookupByLibrary.simpleMessage("松开载入"), "renew_license" : MessageLookupByLibrary.simpleMessage("证书续期"), + "renew_service_now" : MessageLookupByLibrary.simpleMessage("马上续期"), "renewal_fee" : MessageLookupByLibrary.simpleMessage("续订费用"), "reply" : MessageLookupByLibrary.simpleMessage("回复"), "reset_password" : MessageLookupByLibrary.simpleMessage("重置密码"), @@ -381,12 +397,14 @@ class MessageLookup extends MessageLookupByLibrary { "saturday" : MessageLookupByLibrary.simpleMessage("星期六"), "save" : MessageLookupByLibrary.simpleMessage("保存"), "schedule_delivery" : MessageLookupByLibrary.simpleMessage("预约送货时间"), + "search" : MessageLookupByLibrary.simpleMessage("搜索"), "search_place" : MessageLookupByLibrary.simpleMessage("搜索地址"), "search_product" : MessageLookupByLibrary.simpleMessage("搜索产品"), "search_products" : MessageLookupByLibrary.simpleMessage("搜索产品"), "select" : MessageLookupByLibrary.simpleMessage("选取"), "select_a_payment_method" : MessageLookupByLibrary.simpleMessage("选择付款方式"), "select_a_plan" : MessageLookupByLibrary.simpleMessage("选择一个计划"), + "select_a_store" : MessageLookupByLibrary.simpleMessage("选择一个店子"), "select_canada_post_shipping_rate" : MessageLookupByLibrary.simpleMessage("请选择加拿大邮政运费。"), "select_delivery_time" : MessageLookupByLibrary.simpleMessage("选择配送时间"), "select_document_lanuage" : MessageLookupByLibrary.simpleMessage("选择一种语言"), @@ -401,7 +419,7 @@ class MessageLookup extends MessageLookupByLibrary { "shop" : MessageLookupByLibrary.simpleMessage("线上购买"), "show_less" : MessageLookupByLibrary.simpleMessage("显示更少"), "show_more" : MessageLookupByLibrary.simpleMessage("显示更多"), - "sold_per_month_token" : m25, + "sold_per_month_token" : m27, "specification" : MessageLookupByLibrary.simpleMessage("规格"), "store" : MessageLookupByLibrary.simpleMessage("店家"), "store_closed" : MessageLookupByLibrary.simpleMessage("商店已关"), @@ -417,13 +435,13 @@ class MessageLookup extends MessageLookupByLibrary { "submitting" : MessageLookupByLibrary.simpleMessage("提交中..."), "submitting_please_wait" : MessageLookupByLibrary.simpleMessage("提交中,清稍候..."), "subtotal" : MessageLookupByLibrary.simpleMessage("小计"), - "subtotal_token" : m26, + "subtotal_token" : m28, "success" : MessageLookupByLibrary.simpleMessage("成功"), "sun" : MessageLookupByLibrary.simpleMessage("周日"), "sunday" : MessageLookupByLibrary.simpleMessage("星期日"), "support" : MessageLookupByLibrary.simpleMessage("技术支持"), "support_ticket" : MessageLookupByLibrary.simpleMessage("客户提问"), - "table_token" : m27, + "table_token" : m29, "tap_back_again_to_exit" : MessageLookupByLibrary.simpleMessage("再次点击返回退出"), "tax" : MessageLookupByLibrary.simpleMessage("税费"), "thank_you_for_your_comment" : MessageLookupByLibrary.simpleMessage("谢谢您的评价。"), @@ -435,12 +453,12 @@ class MessageLookup extends MessageLookupByLibrary { "thu" : MessageLookupByLibrary.simpleMessage("周四"), "thursday" : MessageLookupByLibrary.simpleMessage("星期四"), "ticket_created_success" : MessageLookupByLibrary.simpleMessage("支持票成功创建。"), - "ticket_number_token" : m28, + "ticket_number_token" : m30, "today" : MessageLookupByLibrary.simpleMessage("今天"), - "today_with_time" : m29, + "today_with_time" : m31, "toll_free" : MessageLookupByLibrary.simpleMessage("无费号码:"), "tomorrow" : MessageLookupByLibrary.simpleMessage("明天"), - "tomorrow_with_time" : m30, + "tomorrow_with_time" : m32, "total" : MessageLookupByLibrary.simpleMessage("总计"), "tue" : MessageLookupByLibrary.simpleMessage("周二"), "tuesday" : MessageLookupByLibrary.simpleMessage("星期二"), @@ -465,7 +483,7 @@ class MessageLookup extends MessageLookupByLibrary { "wechatpay" : MessageLookupByLibrary.simpleMessage("微信支付"), "wed" : MessageLookupByLibrary.simpleMessage("周三"), "wednesday" : MessageLookupByLibrary.simpleMessage("星期三"), - "weight_token" : m31, + "weight_token" : m33, "wiki" : MessageLookupByLibrary.simpleMessage("维基"), "wrong_payment_verification_code" : MessageLookupByLibrary.simpleMessage("错误的付款码,请查证后再输入。"), "yes" : MessageLookupByLibrary.simpleMessage("是的"), diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index f328a0b..83eef80 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -3439,13 +3439,13 @@ class S { ); } - /// `Payment verification code has been sent to your mobile phone {mobile}. Please enter the verification code below.` - String payment_verification_sent(Object mobile) { + /// `Payment verification code has been sent to your {p1} {p2}. Please enter the verification code below.` + String payment_verification_sent(Object p1, Object p2) { return Intl.message( - 'Payment verification code has been sent to your mobile phone $mobile. Please enter the verification code below.', + 'Payment verification code has been sent to your $p1 $p2. Please enter the verification code below.', name: 'payment_verification_sent', desc: '', - args: [mobile], + args: [p1, p2], ); } @@ -3978,6 +3978,146 @@ class S { args: [], ); } + + /// `Enter keyword` + String get enter_keyword { + return Intl.message( + 'Enter keyword', + name: 'enter_keyword', + desc: '', + args: [], + ); + } + + /// `Search` + String get search { + return Intl.message( + 'Search', + name: 'search', + desc: '', + args: [], + ); + } + + /// `Open an online store` + String get create_a_online_store { + return Intl.message( + 'Open an online store', + name: 'create_a_online_store', + desc: '', + args: [], + ); + } + + /// `Open an online store` + String get open_online_store { + return Intl.message( + 'Open an online store', + name: 'open_online_store', + desc: '', + args: [], + ); + } + + /// `Select a store` + String get select_a_store { + return Intl.message( + 'Select a store', + name: 'select_a_store', + desc: '', + args: [], + ); + } + + /// `Domain name` + String get domain_name { + return Intl.message( + 'Domain name', + name: 'domain_name', + desc: '', + args: [], + ); + } + + /// `Your desired domain name` + String get enter_desired_domain { + return Intl.message( + 'Your desired domain name', + name: 'enter_desired_domain', + desc: '', + args: [], + ); + } + + /// `Check availability` + String get check_domain_name { + return Intl.message( + 'Check availability', + name: 'check_domain_name', + desc: '', + args: [], + ); + } + + /// `Domains separated by comma` + String get domains_separated_comma { + return Intl.message( + 'Domains separated by comma', + name: 'domains_separated_comma', + desc: '', + args: [], + ); + } + + /// `{domain} (available)` + String domain_available_token(Object domain) { + return Intl.message( + '$domain (available)', + name: 'domain_available_token', + desc: '', + args: [domain], + ); + } + + /// `{domain} (unavailable)` + String domain_unavailable_token(Object domain) { + return Intl.message( + '$domain (unavailable)', + name: 'domain_unavailable_token', + desc: '', + args: [domain], + ); + } + + /// `Place order now` + String get place_order_now { + return Intl.message( + 'Place order now', + name: 'place_order_now', + desc: '', + args: [], + ); + } + + /// `mobile` + String get mobile { + return Intl.message( + 'mobile', + name: 'mobile', + desc: '', + args: [], + ); + } + + /// `Renew service now` + String get renew_service_now { + return Intl.message( + 'Renew service now', + name: 'renew_service_now', + desc: '', + args: [], + ); + } } class AppLocalizationDelegate extends LocalizationsDelegate { diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index d21b2ac..661219e 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -339,7 +339,7 @@ "confirmation": "Confirmation", "are_you_sure_to_remove_the_card": "Are you srue you want to remove the credit card?", "payment_verification": "Payment verification", - "payment_verification_sent": "Payment verification code has been sent to your mobile phone {mobile}. Please enter the verification code below.", + "payment_verification_sent": "Payment verification code has been sent to your {p1} {p2}. Please enter the verification code below.", "wrong_payment_verification_code": "Wrong payment verification code. Please check and enter again.", "pay_with": "Pay with", "pay_with_token": "Pay with {method}", @@ -392,5 +392,19 @@ "your_group": "Your group", "current_plan": "Current plan", "select_a_plan": "Select a plan", - "price": "Price" + "price": "Price", + "enter_keyword": "Enter keyword", + "search": "Search", + "create_a_online_store": "Open an online store", + "open_online_store": "Open an online store", + "select_a_store": "Select a store", + "domain_name": "Domain name", + "enter_desired_domain": "Your desired domain name", + "check_domain_name": "Check availability", + "domains_separated_comma": "Domains separated by comma", + "domain_available_token": "{domain} (available)", + "domain_unavailable_token": "{domain} (unavailable)", + "place_order_now": "Place order now", + "mobile": "mobile", + "renew_service_now": "Renew service now" } \ No newline at end of file diff --git a/lib/l10n/intl_zh_CN.arb b/lib/l10n/intl_zh_CN.arb index 597bcee..57018c3 100644 --- a/lib/l10n/intl_zh_CN.arb +++ b/lib/l10n/intl_zh_CN.arb @@ -334,7 +334,7 @@ "confirmation": "请确定", "are_you_sure_to_remove_the_card": "您确定要移除该信用卡吗?", "payment_verification": "付款验证", - "payment_verification_sent": "付款码已经发送到您的手机{mobile}。请在下面输入付款码。", + "payment_verification_sent": "付款码已经发送到您的{p1}{p2}。请在下面输入付款码。", "wrong_payment_verification_code": "错误的付款码,请查证后再输入。", "pay_with": "使用", "pay_with_token": "使用{method}付款", @@ -388,5 +388,19 @@ "current_plan": "当前计划", "select_a_plan": "选择一个计划", "price": "价格", - "no_ticket_yet": "还没有支持票。 如果您有任何疑问/问题,请点击上方的加号图标以创建支持票。" + "no_ticket_yet": "还没有支持票。 如果您有任何疑问/问题,请点击上方的加号图标以创建支持票。", + "enter_keyword": "输入关键字", + "search": "搜索", + "create_a_online_store": "开网店", + "open_online_store": "开网店", + "select_a_store": "选择一个店子", + "domain_name": "域名", + "enter_desired_domain": "您想要的域名", + "check_domain_name": "检查是否可用", + "domains_separated_comma": "逗号分开多个域名", + "domain_available_token": "{domain} (可用)", + "domain_unavailable_token": "{domain} (不可用)", + "place_order_now": "马上下单", + "mobile": "手机", + "renew_service_now": "马上续期" } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index b31778f..5cf6d93 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -10,6 +10,7 @@ import 'package:flutter_wisetronic/pages/buy_service.dart'; import 'package:geolocator/geolocator.dart' as geolocator; import 'package:url_strategy/url_strategy.dart'; import 'models/located_address.dart'; +import 'pages/create_online_store_1.dart'; import 'pages/me.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:splashscreen/splashscreen.dart'; @@ -28,6 +29,7 @@ import 'store/store.dart'; import 'utils/configure_nonweb.dart' if (dart.library.html) 'utils/configure_web.dart'; import 'utils/http_util.dart'; import 'utils/util_io.dart' if (dart.library.html) 'utils/util_web.dart'; +import 'utils/utils.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); @@ -42,6 +44,7 @@ class MyApp extends StatelessWidget { MyApp() { Routes.configure(); + Utils().init(); Util().init(); // getCurrentPosition(); } @@ -142,16 +145,42 @@ class MyApp extends StatelessWidget { builder: (BuildContext context) => Me() ); } + if (pathElements[1] == 'service-policy') { + return MaterialPageRoute( + builder: (BuildContext context) => + PlainPage( + 'service-policy', + businessId: 310, + ), + ); + } if (pathElements[1] == 'privacy-policy') { return MaterialPageRoute( builder: (BuildContext context) => PlainPage( 'privacy-policy', - // businessId: Constants.BUSINESS_ID, businessId: 310, ), ); } + if (pathElements[1] == 'return-policy') { + return MaterialPageRoute( + builder: (BuildContext context) => + PlainPage( + 'return-policy', + businessId: 310, + ), + ); + } + if (pathElements[1] == 'end-user-license-agreement') { + return MaterialPageRoute( + builder: (BuildContext context) => + PlainPage( + 'end-user-license-agreement', + businessId: 310, + ), + ); + } if (pathElements[1] == 'renew-minioffice') { return MaterialPageRoute(builder: (BuildContext context) => RenewMiniOffice(int.parse(pathElements[2])) @@ -162,6 +191,11 @@ class MyApp extends StatelessWidget { BuyService(int.parse(pathElements[2]), pathElements[3]) ); } + if (pathElements[1] == 'contact-stores') { + return MaterialPageRoute(builder: (BuildContext context) => + CreateOnlineStore1() + ); + } return MaterialPageRoute( builder: (BuildContext context) => Home(title: Constants.APP_TITLE,), diff --git a/lib/models/group.dart b/lib/models/group.dart new file mode 100644 index 0000000..22be707 --- /dev/null +++ b/lib/models/group.dart @@ -0,0 +1,22 @@ + + +import 'dart:convert'; + +class Group { + int id; + String name; + + Group.fromJson(Map json) : + id = json['id'], + name = json['name']; + + Map toJson() => { + 'id': id, + 'name': name + }; + + @override + String toString() { + return json.encode(this); + } +} \ No newline at end of file diff --git a/lib/models/product.dart b/lib/models/product.dart index f143476..e7ca4d8 100644 --- a/lib/models/product.dart +++ b/lib/models/product.dart @@ -14,6 +14,7 @@ class Product { String description; String detailDescription; String imagePath; + String secondImagePath; double monthSales; int rate; double leftNum; @@ -30,26 +31,28 @@ class Product { this.price = price; this.description = description; this.imagePath = imagePath; + this.secondImagePath = secondImagePath; this.productAttributes = productAttributes; } Product.fromJson(Map json) - : id = json['id'], - businessId = json['business_id'], - categoryId = json['category_id'], - name = json['name'], - price = double.parse(json['price'].toString()), - regularPrice = double.parse(json['regular_price'].toString()), - description = json['description'], - detailDescription = json['detail_description'], - imagePath = json['image_path'], - monthSales = json['month_sales'] != null ? double.parse(json['month_sales'].toString()) : 0.0, - rate = json['rate'], - leftNum = json['left_num'] != null ? double.parse(json['left_num'].toString()) : 0.0, - productAttributes = json['productattributes'] != null ? (json['productattributes'] as List).map((i) => ProductAttribute.fromJson(i)).toList() : [], - nonInventory = json['non_inventory'], - extraData = json['extra_data'], - subproducts = json['subproducts'] != null ? (json['subproducts'] as List).map((e) => Subproduct.fromJson(e)).toList() : []; + : id = json['id'], + businessId = json['business_id'], + categoryId = json['category_id'], + name = json['name'], + price = double.parse(json['price'].toString()), + regularPrice = double.parse(json['regular_price'].toString()), + description = json['description'], + detailDescription = json['detail_description'], + imagePath = json['image_path'], + secondImagePath = json['second_image_path'], + monthSales = json['month_sales'] != null ? double.parse(json['month_sales'].toString()) : 0.0, + rate = json['rate'], + leftNum = json['left_num'] != null ? double.parse(json['left_num'].toString()) : 0.0, + productAttributes = json['productattributes'] != null ? (json['productattributes'] as List).map((i) => ProductAttribute.fromJson(i)).toList() : [], + nonInventory = json['non_inventory'], + extraData = json['extra_data'], + subproducts = json['subproducts'] != null ? (json['subproducts'] as List).map((e) => Subproduct.fromJson(e)).toList() : []; Map toJson() => { 'id': id, @@ -61,6 +64,7 @@ class Product { 'description': description, 'detail_description': detailDescription, 'image_path': imagePath, + 'second_image_path': secondImagePath, 'month_sales': monthSales, 'rate': rate, 'left_num': leftNum, diff --git a/lib/pages/buy_service.dart b/lib/pages/buy_service.dart index 25f1f9b..3205867 100644 --- a/lib/pages/buy_service.dart +++ b/lib/pages/buy_service.dart @@ -19,8 +19,10 @@ import '../widgets/mobile/mobile_renew_license.dart'; class BuyService extends StatefulWidget { final int gid; final String serviceName; + final String domain; + final int sid; - const BuyService(this.gid, this.serviceName, {Key key}) : + const BuyService(this.gid, this.serviceName, {Key key, this.domain, this.sid = 0}) : super(key: key); @override @@ -66,8 +68,13 @@ class BuyServiceState extends State { HttpUtil.httpGet( 'v1/get-buy-service-info/${widget.serviceName}/${widget.gid}', businessId: Constants.BUSINESS_ID, + queryParameters: { + 'store_id': '${widget.sid}', + } ).then((value) { data = value; + data['domain'] = widget.domain; + print('data: $data'); setState(() {}); }).onError((error, stackTrace) { Utils.showMessageDialog(context, error); diff --git a/lib/pages/change_mobile_or_email.dart b/lib/pages/change_mobile_or_email.dart index ea85924..63ec9c7 100644 --- a/lib/pages/change_mobile_or_email.dart +++ b/lib/pages/change_mobile_or_email.dart @@ -22,7 +22,7 @@ class ChangeMobileOrEmail extends StatelessWidget { return ResponsiveBuilder( builder: (context, sizingInformation) => Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: isMobile ? S.of(context).change_mobile : S.of(context).change_email, back: true, breadCrumbs: [ diff --git a/lib/pages/change_password.dart b/lib/pages/change_password.dart index 6fca5b3..df4f8a3 100644 --- a/lib/pages/change_password.dart +++ b/lib/pages/change_password.dart @@ -20,7 +20,7 @@ class ChangePassword extends StatelessWidget { builder: (context, sizingInformation) => Scaffold( key: _scaffoldKey, - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).change_password, back: true, breadCrumbs: [ diff --git a/lib/pages/create_online_store_1.dart b/lib/pages/create_online_store_1.dart new file mode 100644 index 0000000..f4f600f --- /dev/null +++ b/lib/pages/create_online_store_1.dart @@ -0,0 +1,48 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/store/actions.dart'; +import 'package:flutter_wisetronic/store/store.dart'; +import 'package:responsive_builder/responsive_builder.dart'; + +import '../constants.dart'; +import '../routes.dart'; +import '../widgets/desktop/create_online_store_1.dart' as desktop; +import '../widgets/mobile/create_online_store_1.dart' as mobile; + +class CreateOnlineStore1 extends StatefulWidget { + + const CreateOnlineStore1({Key key}) : + super(key: key); + + @override + State createState() => CreateOnlineStore1State(); +} + +class CreateOnlineStore1State extends State { + + @override + Widget build(BuildContext context) { + + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + if (store.state.user == null) { + store.dispatch(UpdateRedirectRoute('/contact-stores')); + Routes.router.navigateTo(context, '/login', replace: true); + return; + } + }); + + return ResponsiveBuilder( + builder: (context, sizingInformation) => + ScreenTypeLayout( + mobile: mobile.CreateOnlineStore1(Constants.BUSINESS_ID), + tablet: desktop.CreateOnlineStore1(Constants.BUSINESS_ID), + desktop: desktop.CreateOnlineStore1(Constants.BUSINESS_ID), + ), + ); + } + + @override + void initState() { + super.initState(); + } +} \ No newline at end of file diff --git a/lib/pages/download.dart b/lib/pages/download.dart index 2ed2128..e72f259 100644 --- a/lib/pages/download.dart +++ b/lib/pages/download.dart @@ -50,7 +50,7 @@ class DownloadState extends State { builder: (context, sizingInformation) => Scaffold( key: _scaffoldKey, - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).download, back: true, breadCrumbs: [BreadCrumb(S.of(context).downloads, null)], diff --git a/lib/pages/forgot_password.dart b/lib/pages/forgot_password.dart index 0140f73..7542cc1 100644 --- a/lib/pages/forgot_password.dart +++ b/lib/pages/forgot_password.dart @@ -19,7 +19,7 @@ class ForgotPassword extends StatelessWidget { return ResponsiveBuilder( builder: (context, sizingInformation) => Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).forgot_password, back: true, breadCrumbs: [ diff --git a/lib/pages/home.dart b/lib/pages/home.dart index 3cd5e61..fa4c2b9 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -70,7 +70,7 @@ class HomeState extends State { builder: (context, sizingInformation) => Scaffold( key: _scaffoldKey, - appBar: NavigationBar(), + appBar: MiniNavigationBar(), drawer: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? MobileNavigationDrawer() : null, body: DoubleBackToCloseAppWrapper( child: ScreenTypeLayout( diff --git a/lib/pages/igoshow_learn_more.dart b/lib/pages/igoshow_learn_more.dart index c6d2a26..8be0e9b 100644 --- a/lib/pages/igoshow_learn_more.dart +++ b/lib/pages/igoshow_learn_more.dart @@ -46,7 +46,7 @@ class IGoShowLearnMoreState extends State { builder: (context, sizingInformation) => Scaffold( key: _scaffoldKey, - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).igoshow, back: true, breadCrumbs: [ diff --git a/lib/pages/login.dart b/lib/pages/login.dart index 1f4e5f7..6b18ab7 100644 --- a/lib/pages/login.dart +++ b/lib/pages/login.dart @@ -41,7 +41,7 @@ class LoginState extends State { builder: (context, sizingInformation) => Scaffold( key: _scaffoldKey, - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).login, back: true, breadCrumbs: [ diff --git a/lib/pages/me.dart b/lib/pages/me.dart index da065dd..39c8a7a 100644 --- a/lib/pages/me.dart +++ b/lib/pages/me.dart @@ -42,7 +42,7 @@ class MeState extends State { builder: (context, sizingInformation) => Scaffold( key: _scaffoldKey, - appBar: sizingInformation.isMobile? null : NavigationBar( + appBar: sizingInformation.isMobile? null : MiniNavigationBar( title: S.of(context).me, back: true, breadCrumbs: [ diff --git a/lib/pages/minipos_learn_more.dart b/lib/pages/minipos_learn_more.dart index 536a100..a6d886a 100644 --- a/lib/pages/minipos_learn_more.dart +++ b/lib/pages/minipos_learn_more.dart @@ -47,7 +47,7 @@ class MiniPosLearnMoreState extends State { builder: (context, sizingInformation) => Scaffold( key: _scaffoldKey, - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).minipos, back: true, breadCrumbs: [ diff --git a/lib/pages/new_ticket.dart b/lib/pages/new_ticket.dart index ca5fb96..064d4c8 100644 --- a/lib/pages/new_ticket.dart +++ b/lib/pages/new_ticket.dart @@ -43,7 +43,7 @@ class NewTicketState extends State { builder: (context, sizingInformation) => Scaffold( key: _scaffoldKey, - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).new_ticket, back: true, breadCrumbs: [ diff --git a/lib/pages/new_user.dart b/lib/pages/new_user.dart index b11a2e3..dae15d2 100644 --- a/lib/pages/new_user.dart +++ b/lib/pages/new_user.dart @@ -19,7 +19,7 @@ class NewUser extends StatelessWidget { return ResponsiveBuilder( builder: (context, sizingInformation) => Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).registration, back: true, breadCrumbs: [ diff --git a/lib/pages/product_search.dart b/lib/pages/product_search.dart new file mode 100644 index 0000000..408c4b0 --- /dev/null +++ b/lib/pages/product_search.dart @@ -0,0 +1,26 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_wisetronic/models/business.dart'; +import 'package:responsive_builder/responsive_builder.dart'; + +import '../widgets/desktop/product_search.dart' as desktop; +import '../widgets/mobile/product_search.dart' as mobile; + +class ProductSearch extends StatelessWidget { + final Business business; + + const ProductSearch(this.business, {Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return ResponsiveBuilder( + builder: (context, sizingInformation) => + ScreenTypeLayout( + mobile: mobile.ProductSearch(business), + tablet: desktop.ProductSearch(business), + desktop: desktop.ProductSearch(business), + ), + ); + } + +} \ No newline at end of file diff --git a/lib/pages/reset_password.dart b/lib/pages/reset_password.dart index b9b1113..6ae09b7 100644 --- a/lib/pages/reset_password.dart +++ b/lib/pages/reset_password.dart @@ -21,7 +21,7 @@ class ResetPassword extends StatelessWidget { return ResponsiveBuilder( builder: (context, sizingInformation) => Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).reset_password, back: true, breadCrumbs: [ diff --git a/lib/pages/set_password.dart b/lib/pages/set_password.dart index 2a56823..1d30b5d 100644 --- a/lib/pages/set_password.dart +++ b/lib/pages/set_password.dart @@ -21,7 +21,7 @@ class SetPassword extends StatelessWidget { return ResponsiveBuilder( builder: (context, sizingInformation) => Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).set_password, back: true, breadCrumbs: [ diff --git a/lib/pages/shop.dart b/lib/pages/shop.dart index bc82894..fc8751b 100644 --- a/lib/pages/shop.dart +++ b/lib/pages/shop.dart @@ -1,55 +1,44 @@ -import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:flutter_wisetronic/events/eventbus.dart'; -import 'package:flutter_wisetronic/events/events.dart'; -import 'package:flutter_wisetronic/generated/l10n.dart'; -import 'package:flutter_wisetronic/models/cart_info.dart'; -import 'package:flutter_wisetronic/models/cart_line_item.dart'; -import 'package:flutter_wisetronic/models/product.dart'; -import 'package:flutter_wisetronic/utils/utils.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:responsive_builder/responsive_builder.dart'; -import '../constants.dart'; -import '../store/actions.dart'; -import '../store/store.dart'; -import '../widgets/desktop/desktop_shop.dart'; -import '../widgets/mobile/mobile_shop.dart'; +import '../../utils/utils.dart'; +import '../widgets/desktop/shop.dart' as desktop; +import '../widgets/mobile/shop.dart' as mobile; class Shop extends StatefulWidget { final int businessId; - const Shop({this.businessId = Constants.BUSINESS_ID, Key key}) : - super(key: key); + const Shop({this.businessId, Key key}) : super(key: key); @override State createState() => ShopState(); } class ShopState extends State { - StreamSubscription onProductWillAddToCartSubscription; - StreamSubscription onProductWillRemoveFromCartSubscription; - @override Widget build(BuildContext context) { - store.dispatch(UpdateContext(context)); + int _businessId = + widget.businessId == null ? Utils.getBusinessId() : widget.businessId; return ResponsiveBuilder( - builder: (context, sizingInformation) => - ScreenTypeLayout( - mobile: MobileShop(businessId: widget.businessId,), - tablet: DesktopShop(businessId: widget.businessId,), - desktop: DesktopShop(businessId: widget.businessId,), - ), + builder: (context, sizingInformation) => ScreenTypeLayout( + mobile: mobile.Shop( + businessId: _businessId, + ), + tablet: desktop.Shop( + businessId: _businessId, + ), + desktop: desktop.Shop( + businessId: _businessId, + ), + ), ); } @override void dispose() { - onProductWillAddToCartSubscription?.cancel(); - onProductWillRemoveFromCartSubscription?.cancel(); super.dispose(); print("shop parent dispose"); } @@ -57,137 +46,5 @@ class ShopState extends State { @override void initState() { super.initState(); - - onProductWillAddToCartSubscription = - eventBus.on().listen((event) { - if (mounted) { - - CartInfo cartInfo = - Utils.getCartInfoByBusiness(store.state.cartInfos, event.business); - - if (cartInfo == null || cartInfo.productList.length == 0) { - cartInfo = CartInfo(); - cartInfo.id = 0; - cartInfo.amountPaid = 0.0; - cartInfo.businessInfo = event.business; - cartInfo.extraFeeList = []; - cartInfo.discountList = []; - CartLineItem lineItem = Utils.newCartLineItem( - id: 0, - price: event.price, - product: event.product, - name: event.product.name, - description: event.description, - quantity: 1.0); - cartInfo.productList = [lineItem]; - Utils.addSubproductToCard(cartInfo, lineItem); - store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList( - store.state.cartInfos, cartInfo))); - eventBus.fire(new OnCartInfoUpdated()); - } else { - if (event.product.productAttributes.length > 0) { - CartLineItem lineItem = Utils.newCartLineItem( - id: 0, - price: event.price, - product: event.product, - name: event.product.name, - description: event.description, - quantity: 1.0); - cartInfo.productList.add(lineItem); - Utils.addSubproductToCard(cartInfo, lineItem); - store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList( - store.state.cartInfos, cartInfo))); - eventBus.fire(new OnCartInfoUpdated()); - } else { - int found = -1; - for (var i = 0; i < cartInfo.productList.length; i++) { - if (event.product.id == cartInfo.productList[i].product.id) { - found = i; - break; - } - } - if (found == -1) { - CartLineItem lineItem = Utils.newCartLineItem( - id: 0, - price: event.price, - product: event.product, - name: event.product.name, - description: event.description, - quantity: 1.0); - cartInfo.productList.add(lineItem); - Utils.addSubproductToCard(cartInfo, lineItem); - store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList( - store.state.cartInfos, cartInfo))); - eventBus.fire(new OnCartInfoUpdated()); - } else { - if (cartInfo.productList[found].quantity + 1.0 > - event.product.leftNum) { - Fluttertoast.showToast( - msg: S.of(context).product_insufficient, - toastLength: Toast.LENGTH_SHORT, - gravity: ToastGravity.CENTER, - backgroundColor: Colors.red, - textColor: Colors.white); - } else { - cartInfo.productList[found].quantity += 1; - Utils.addSubproductQty(cartInfo, cartInfo.productList[found]); - store.dispatch(new UpdateCartInfo( - Utils.addCartInfoToCartInfoList( - store.state.cartInfos, cartInfo))); - eventBus.fire(new OnCartInfoUpdated()); - } - } - } - } - } - }); - onProductWillRemoveFromCartSubscription = - eventBus.on().listen((event) { - if (mounted) { - CartInfo cartInfo = - Utils.getCartInfoByBusiness(store.state.cartInfos, event.business); - if (cartInfo != null) { - if (cartInfo.productList.length > 0) { - if (event.productListIndex != -1) { - if (cartInfo.productList[event.productListIndex].quantity <= 1) { - String uuid = cartInfo.productList[event.productListIndex].uuid; - cartInfo.productList.removeAt(event.productListIndex); - Utils.removeSubproduct(cartInfo, uuid); - } else { - cartInfo.productList[event.productListIndex].quantity -= 1; - Utils.addSubproductQty(cartInfo, cartInfo.productList[event.productListIndex], remove: true); - } - } else { - int productListIndex = -1; - for (var i = 0; i < cartInfo.productList.length; i++) { - if (cartInfo.productList[i].product.id == event.product.id) { - productListIndex = i; - break; - } - } - if (productListIndex != -1) { - if (cartInfo.productList[productListIndex].quantity <= 1) { - String uuid = cartInfo.productList[productListIndex].uuid; - cartInfo.productList.removeAt(productListIndex); - Utils.removeSubproduct(cartInfo, uuid); - } else { - cartInfo.productList[productListIndex].quantity -= 1; - Utils.addSubproductQty(cartInfo, cartInfo.productList[productListIndex], remove: true); - } - } - } - } - - if (cartInfo.productList.length <= 0) { - store.dispatch(UpdateCartInfo(Utils.removeCartInfoFromCartInfoList( - store.state.cartInfos, cartInfo))); - } else { - store.dispatch(UpdateCartInfo(Utils.addCartInfoToCartInfoList( - store.state.cartInfos, cartInfo))); - } - eventBus.fire(new OnCartInfoUpdated()); - } - } - }); } } \ No newline at end of file diff --git a/lib/pages/store_product_search.dart b/lib/pages/store_product_search.dart index 2749668..434bcdb 100644 --- a/lib/pages/store_product_search.dart +++ b/lib/pages/store_product_search.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:flutter_wisetronic/widgets/desktop/desktop_store_product_search.dart'; import 'package:responsive_builder/responsive_builder.dart'; import '../constants.dart'; import '../generated/l10n.dart'; import '../models/business.dart'; +import '../widgets/desktop/desktop_store_product_search.dart'; import '../widgets/general/bottom_nav.dart'; import '../widgets/general/breadcrumbs.dart'; import '../widgets/general/navigationbar.dart'; @@ -22,7 +22,7 @@ class StoreProductSearch extends StatelessWidget { return ResponsiveBuilder( builder: (context, sizingInformation) => Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).search_product, back: true, breadCrumbs: [ diff --git a/lib/pages/tutorials.dart b/lib/pages/tutorials.dart deleted file mode 100644 index d72ff80..0000000 --- a/lib/pages/tutorials.dart +++ /dev/null @@ -1,66 +0,0 @@ - -import 'package:flutter/material.dart'; -import 'package:responsive_builder/responsive_builder.dart'; - -import '../constants.dart'; -import '../events/eventbus.dart'; -import '../events/events.dart'; -import '../generated/l10n.dart'; -import '../widgets/desktop/desktop_tutorials.dart'; -import '../widgets/general/bottom_nav.dart'; -import '../widgets/general/breadcrumbs.dart'; -import '../widgets/general/navigationbar.dart'; -import '../widgets/mobile/MobileBottomNav.dart'; -import '../widgets/mobile/mobile_navigation_drawer.dart'; -import '../widgets/mobile/mobile_tutorials.dart'; - -class Tutorials extends StatefulWidget { - const Tutorials({Key key}) : super(key: key); - - @override - State createState() { - return TutorialsState(); - } - -} - -class TutorialsState extends State { - final _scaffoldKey = GlobalKey(); - - @override - Widget build(BuildContext context) { - return ResponsiveBuilder( - builder: (context, sizingInformation) => - Scaffold( - key: _scaffoldKey, - appBar: NavigationBar( - title: S.of(context).tutorials, - back: true, - breadCrumbs: [BreadCrumb(S.of(context).tutorials, null)], - breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT, - ), - drawer: null, - body: ScreenTypeLayout( - mobile: MobileTutorials(), - tablet: DesktopTutorials(), - desktop: DesktopTutorials(), - ), - bottomNavigationBar: ScreenTypeLayout( - mobile: MobileBottomNav(currentIndex: 0,), - tablet: BottomNav(), - desktop: BottomNav(), - ), - ), - ); - } - - @override - void initState() { - super.initState(); - eventBus.on().listen((event) { - if (mounted) { - _scaffoldKey.currentState.openDrawer(); - } - }); - } -} \ No newline at end of file diff --git a/lib/pages/user_profile.dart b/lib/pages/user_profile.dart index 5c2eb02..a642db7 100644 --- a/lib/pages/user_profile.dart +++ b/lib/pages/user_profile.dart @@ -20,7 +20,7 @@ class UserProfile extends StatelessWidget { return ResponsiveBuilder( builder: (context, sizingInformation) => Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).profile, back: true, breadCrumbs: [ diff --git a/lib/pages/view_blog.dart b/lib/pages/view_blog.dart index 762c30d..1727713 100644 --- a/lib/pages/view_blog.dart +++ b/lib/pages/view_blog.dart @@ -42,7 +42,7 @@ class ViewBlogState extends State { builder: (context, sizingInformation) => Scaffold( key: _scaffoldKey, - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).view_blog, back: true, breadCrumbs: [ diff --git a/lib/pages/view_ticket.dart b/lib/pages/view_ticket.dart index b89a5e7..9f5c935 100644 --- a/lib/pages/view_ticket.dart +++ b/lib/pages/view_ticket.dart @@ -42,7 +42,7 @@ class ViewTicketState extends State { builder: (context, sizingInformation) => Scaffold( key: _scaffoldKey, - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).view_ticket, back: true, breadCrumbs: [ diff --git a/lib/routes.dart b/lib/routes.dart index a5a32d0..0efb875 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -1,19 +1,16 @@ import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_wisetronic/pages/buy_service.dart'; -import 'package:flutter_wisetronic/pages/contact_us.dart'; -import 'package:flutter_wisetronic/pages/plain_page.dart'; -import 'package:flutter_wisetronic/pages/renew_license.dart'; -import 'package:flutter_wisetronic/pages/renew_minioffice.dart'; -import 'package:flutter_wisetronic/store/store.dart'; import 'constants.dart'; import 'pages/blog.dart'; +import 'pages/buy_service.dart'; import 'pages/change_mobile_or_email.dart'; import 'pages/change_password.dart'; import 'pages/checkout.dart'; +import 'pages/contact_us.dart'; import 'pages/coupons.dart'; +import 'pages/create_online_store_1.dart'; import 'pages/download.dart'; import 'pages/forgot_password.dart'; import 'pages/home.dart'; @@ -30,11 +27,13 @@ import 'pages/new_user.dart'; import 'pages/order_detail.dart'; import 'pages/orders.dart'; import 'pages/pay_now.dart'; +import 'pages/plain_page.dart'; +import 'pages/renew_license.dart'; +import 'pages/renew_minioffice.dart'; import 'pages/reset_password.dart'; import 'pages/search_place.dart'; import 'pages/set_password.dart'; import 'pages/shop.dart'; -import 'pages/tutorials.dart'; import 'pages/user_profile.dart'; import 'pages/view_blog.dart'; import 'pages/view_ticket.dart'; @@ -68,12 +67,6 @@ class Routes { }), transitionType: TransitionType.inFromRight ); - router.define('/tutorials', handler: new Handler( - handlerFunc: (BuildContext context, Map> params) { - return Tutorials(); - }), - transitionType: TransitionType.inFromRight - ); router.define('/login', handler: new Handler( handlerFunc: (BuildContext context, Map> params) { return Login(); @@ -279,5 +272,10 @@ class Routes { return BuyService(int.parse(params['gid'][0]), params['servicename'][0]); } )); + router.define('/contact-stores', handler: new Handler( + handlerFunc: (BuildContext context, Map> params) { + return CreateOnlineStore1(); + } + )); } } \ No newline at end of file diff --git a/lib/utils/http_util.dart b/lib/utils/http_util.dart index 6fe26ad..bbd669c 100644 --- a/lib/utils/http_util.dart +++ b/lib/utils/http_util.dart @@ -58,7 +58,7 @@ class HttpUtil { localHeaders['Http-Signature'] = generateSignature(url); } - localHeaders['Http-Business-Id'] = businessId.toString(); + localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.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; @@ -81,7 +81,7 @@ class HttpUtil { onReceiveProgress: receiveProgress, ).timeout(const Duration(seconds: 30)); -// print(response.data); + // print('response data: ${response.data}'); // Utils.jsonPrettyPrint(response.data); int statusCode = response.statusCode; @@ -115,7 +115,7 @@ class HttpUtil { if (!url.startsWith('http')) { localHeaders['Http-Signature'] = generateSignature(url); } - localHeaders['Http-Business-Id'] = businessId.toString(); + localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.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; @@ -189,7 +189,7 @@ class HttpUtil { localHeaders['Http-Signature'] = generateSignature(url); } - localHeaders['Http-Business-Id'] = businessId.toString(); + localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.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; @@ -254,7 +254,7 @@ class HttpUtil { localHeaders['Http-Signature'] = generateSignature(url); } - localHeaders['Http-Business-Id'] = businessId.toString(); + localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.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; @@ -319,7 +319,7 @@ class HttpUtil { localHeaders['Http-Signature'] = generateSignature(url); } - localHeaders['Http-Business-Id'] = businessId.toString(); + localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.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; diff --git a/lib/utils/iframe_web.dart b/lib/utils/iframe_web.dart deleted file mode 100644 index 50f3f04..0000000 --- a/lib/utils/iframe_web.dart +++ /dev/null @@ -1,39 +0,0 @@ - -import 'dart:html'; - -import 'dart:ui' as ui; -import 'package:flutter/material.dart'; - -class IFrameWeb extends StatefulWidget { - final String width; - final String height; - final String src; - - const IFrameWeb({this.width, this.height, this.src}); - - @override - State createState() { - return IFrameWebState(); - } -} - -class IFrameWebState extends State { - final IFrameElement _iframeElement = IFrameElement(); - - @override - Widget build(BuildContext context) { - _iframeElement.height = widget.height; - _iframeElement.width = widget.width; - _iframeElement.src = widget.src; - _iframeElement.style.border = 'none'; - ui.platformViewRegistry.registerViewFactory( - 'iframeElement', - (int viewId) => _iframeElement, - ); - return HtmlElementView( - key: UniqueKey(), - viewType: 'iframeElement', - ); - } - -} \ No newline at end of file diff --git a/lib/utils/util_web.dart b/lib/utils/util_web.dart index aedf7ca..4f62cf1 100644 --- a/lib/utils/util_web.dart +++ b/lib/utils/util_web.dart @@ -57,7 +57,7 @@ class Util { ); }, errorBuilder: (BuildContext context, Object object, StackTrace stackTrace) { - print(stackTrace); + print('StackTrace: $stackTrace'); if (errorWidget != null) { return errorWidget(context, null, null); } diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index e1acd34..44dda2f 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'package:dio/dio.dart'; @@ -36,6 +37,142 @@ typedef void OnOk(); typedef void OnLoadImageError(); class Utils { + static StreamSubscription onProductWillAddToCartSubscription; + static StreamSubscription onProductWillRemoveFromCartSubscription; + + init() async { + onProductWillAddToCartSubscription = + eventBus.on().listen((event) { + CartInfo cartInfo = + getCartInfoByBusiness(store.state.cartInfos, event.business); + + if (cartInfo == null || cartInfo.productList.length == 0) { + cartInfo = CartInfo(); + cartInfo.id = 0; + cartInfo.amountPaid = 0.0; + cartInfo.businessInfo = event.business; + cartInfo.extraFeeList = []; + cartInfo.discountList = []; + CartLineItem lineItem = newCartLineItem( + id: 0, + price: event.price, + product: event.product, + name: event.product.name, + description: event.description, + quantity: 1.0); + cartInfo.productList = [lineItem]; + addSubproductToCard(cartInfo, lineItem); + store.dispatch(new UpdateCartInfo(addCartInfoToCartInfoList( + store.state.cartInfos, cartInfo))); + eventBus.fire(new OnCartInfoUpdated()); + print('#1'); + } else { + if (event.product.productAttributes.length > 0) { + CartLineItem lineItem = newCartLineItem( + id: 0, + price: event.price, + product: event.product, + name: event.product.name, + description: event.description, + quantity: 1.0); + cartInfo.productList.add(lineItem); + addSubproductToCard(cartInfo, lineItem); + store.dispatch(new UpdateCartInfo(addCartInfoToCartInfoList( + store.state.cartInfos, cartInfo))); + print('#2'); + eventBus.fire(new OnCartInfoUpdated()); + } else { + int found = -1; + for (var i = 0; i < cartInfo.productList.length; i++) { + if (event.product.id == cartInfo.productList[i].product.id) { + found = i; + break; + } + } + if (found == -1) { + CartLineItem lineItem = newCartLineItem( + id: 0, + price: event.price, + product: event.product, + name: event.product.name, + description: event.description, + quantity: 1.0); + cartInfo.productList.add(lineItem); + addSubproductToCard(cartInfo, lineItem); + store.dispatch(new UpdateCartInfo(addCartInfoToCartInfoList( + store.state.cartInfos, cartInfo))); + print('#3'); + eventBus.fire(new OnCartInfoUpdated()); + } else { + if (cartInfo.productList[found].quantity + 1.0 > + event.product.leftNum) { + // Fluttertoast.showToast( + // msg: S.of(context).product_insufficient, + // toastLength: Toast.LENGTH_SHORT, + // gravity: ToastGravity.CENTER, + // backgroundColor: Colors.red, + // textColor: Colors.white); + } else { + cartInfo.productList[found].quantity += 1; + addSubproductQty(cartInfo, cartInfo.productList[found]); + store.dispatch(new UpdateCartInfo( + addCartInfoToCartInfoList( + store.state.cartInfos, cartInfo))); + print('#4'); + eventBus.fire(new OnCartInfoUpdated()); + } + } + } + } + }); + onProductWillRemoveFromCartSubscription = + eventBus.on().listen((event) { + CartInfo cartInfo = + getCartInfoByBusiness(store.state.cartInfos, event.business); + if (cartInfo != null) { + if (cartInfo.productList.length > 0) { + if (event.productListIndex != -1) { + if (cartInfo.productList[event.productListIndex].quantity <= 1) { + String uuid = cartInfo.productList[event.productListIndex].uuid; + cartInfo.productList.removeAt(event.productListIndex); + removeSubproduct(cartInfo, uuid); + } else { + cartInfo.productList[event.productListIndex].quantity -= 1; + addSubproductQty(cartInfo, cartInfo.productList[event.productListIndex], remove: true); + } + } else { + int productListIndex = -1; + for (var i = 0; i < cartInfo.productList.length; i++) { + if (cartInfo.productList[i].product.id == event.product.id) { + productListIndex = i; + break; + } + } + if (productListIndex != -1) { + if (cartInfo.productList[productListIndex].quantity <= 1) { + String uuid = cartInfo.productList[productListIndex].uuid; + cartInfo.productList.removeAt(productListIndex); + removeSubproduct(cartInfo, uuid); + } else { + cartInfo.productList[productListIndex].quantity -= 1; + addSubproductQty(cartInfo, cartInfo.productList[productListIndex], remove: true); + } + } + } + } + + if (cartInfo.productList.length <= 0) { + store.dispatch(UpdateCartInfo(removeCartInfoFromCartInfoList( + store.state.cartInfos, cartInfo))); + } else { + store.dispatch(UpdateCartInfo(addCartInfoToCartInfoList( + store.state.cartInfos, cartInfo))); + } + eventBus.fire(new OnCartInfoUpdated()); + } + }); + } + static bool equalsIgnoreCase(String a, String b) => (a == null && b == null) || (a != null && b != null && a.toLowerCase() == b.toLowerCase()); @@ -373,6 +510,8 @@ class Utils { message = error.response.data.toString(); } } + } else if (error is String) { + message = '$error'; } else if (error.message != null) { message = error.message; } else { @@ -642,7 +781,8 @@ class Utils { } static void loadProducts(int businessId, int categoryId, int page, bool more, - OnComplete onComplete, OnError onError) { + OnComplete onComplete, OnError onError, {int featuredCount=4, int hotSaleCount=4, String keyword=''}) { + print('feature $featuredCount'); HttpUtil.httpGet( more ? 'v1/service-category-products-more' : 'v1/service-category-products', businessId: businessId, @@ -650,9 +790,12 @@ class Utils { // 'lat': store.state.position.latitude.toString(), // 'lng': store.state.position.longitude.toString(), 'category_id': categoryId, - 'preview': 'no', + 'preview': Constants.isPreview, 'page': page, 'num_per_page': Constants.ORDERS_PER_PAGE, + 'featured_count': featuredCount, + 'hot_sale_count': hotSaleCount, + 'keyword': Uri.encodeComponent(keyword), }, ).then((value) { if (onComplete != null) { @@ -667,6 +810,9 @@ class Utils { static String timestampToString(BuildContext context, int timestamp, {bool withTime=false}) { DateTime date = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000); + if (timestamp == 0) { + return ''; + } return datetimeFormat(context, date, withTime: withTime); } @@ -966,6 +1112,10 @@ class Utils { child: row, ); } + + static int getBusinessId() { + return Constants.BUSINESS_ID; + } } class RuntimeError extends Error { diff --git a/lib/widgets/desktop/create_online_store_1.dart b/lib/widgets/desktop/create_online_store_1.dart new file mode 100644 index 0000000..9703301 --- /dev/null +++ b/lib/widgets/desktop/create_online_store_1.dart @@ -0,0 +1,464 @@ + +import 'package:flutter/material.dart'; + +import '../../constants.dart'; +import '../../generated/l10n.dart'; +import '../../models/group.dart'; +import '../../pages/buy_service.dart'; +import '../../routes.dart'; +import '../../utils/http_util.dart'; +import '../../utils/utils.dart'; +import '../../widgets/general/bottom_nav.dart'; +import '../../widgets/general/breadcrumbs.dart'; +import '../../widgets/general/navigationbar.dart'; + +class CreateOnlineStore1 extends StatefulWidget { + final int businessId; + + const CreateOnlineStore1(this.businessId, {Key key}) : super(key: key); + + @override + State createState() { + return CreateOnlineStore1State(); + } + +} + +class CreateOnlineStore1State extends State { + double sideSpace = 0; + double mainSpace = 1200; + + TextEditingController groupNumberController = TextEditingController(); + + TextEditingController domainController = TextEditingController(); + + bool canSubmit = false; + + List stores = []; + Map service; + dynamic selectedStore; + + Group group; + + String selectedDomain; + List domainResult = []; + + @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; + } + + Row row = Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [], + ); + + row.children.add( + Expanded( + child: Container( + padding: EdgeInsets.only( + left: 16.0, right: 16.0, top: 20, bottom: 20), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.only(bottom: 4.0), + child: Text( + S.of(context).open_online_store, + style: TextStyle( + fontSize: 28, + ), + ), + ), + Container( + padding: EdgeInsets.only(top: 4, bottom: 4), + child: Text( + S.of(context) + .select_a_store, + style: TextStyle( + color: Colors.black45, + ), + ), + ), + Container( + padding: EdgeInsets.only(top: 4), + child: DropdownButton( + items: stores.map((e) => DropdownMenuItem( + value: e, + child: Text(e['name']), + )).toList(), + isExpanded: false, + hint: Text(S.of(context).select_a_store), + onChanged: (newValue) { + print('newValue $newValue'); + setState(() { + selectedStore = newValue; + }); + }, + value: selectedStore, + ), + ), + ], + ), + decoration: BoxDecoration( + border: Border( + right: BorderSide( + width: 1, + color: Colors.black12, + ), + ), + ), + ), + ), + ); + row.children.add( + Expanded( + child: Container( + padding: EdgeInsets.only( + left: 16.0, right: 16.0, top: 20, bottom: 20), + child: Visibility( + child: getSearchDomainWidget(), + visible: selectedStore != null, + ), + ), + ), + ); + + return Scaffold( + appBar: MiniNavigationBar( + title: S + .of(context) + .blog, + back: true, + breadCrumbs: [ + BreadCrumb(S + .of(context) + .open_online_store, null), + ], + breadCrumbHeight: Constants.BREADCRUMB_HEIGHT, + ), + body: SingleChildScrollView( + child: Row( + children: [ + Container( + width: sideSpace, + ), + Expanded(child: row,), + Container( + width: sideSpace, + ), + ], + ), + ), + bottomNavigationBar: BottomNav(), + ); + } + + Widget getSearchDomainWidget() { + if (selectedStore == null) { + return SizedBox.shrink(); + } + Column col = Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [], + ); + col.children.add( + Container( + padding: EdgeInsets.only(bottom: 4,), + child: Text(selectedStore == null ? '' : selectedStore['name'], + style: TextStyle( + fontSize: 28, + ), + ), + ), + ); + Map existing_web_svc; + if (selectedStore != null && (selectedStore['services'] as List).length > 0) { + for (Mapsvc in (selectedStore['services'] as List)) { + if (svc['code'] == Constants.WEB_MINISTORE_SERVICE) { + existing_web_svc = svc; + break; + } + } + } + if (existing_web_svc != null) { + col.children.add( + Container( + padding: EdgeInsets.only(top: 8.0), + child: Text( + '${existing_web_svc['description']}', + ), + ), + ); + col.children.add( + Container( + padding: EdgeInsets.only(top: 4.0), + child: Text( + S.of(context).expiration_date + ": " + + Utils.utcDatetimeStringToLocalDatetimeString(context, existing_web_svc['expiration_date']), + ), + ), + ); + col.children.add( + Container( + padding: EdgeInsets.only(top: 4.0), + child: Text( + S.of(context).store + ": " + '${existing_web_svc['store']['name']}' + ), + ), + ); + col.children.add( + Container( + padding: EdgeInsets.only(top: 4.0), + child: Text( + S.of(context).domain_name + ": " + '${existing_web_svc['domain']}' + ), + ), + ); + col.children.add( + Container( + padding: EdgeInsets.only(top: 10.0), + child: ElevatedButton( + child: Text(S.of(context).renew_service_now), + onPressed: () { + Navigator.pushReplacement(context, MaterialPageRoute( + builder: (BuildContext context) => + BuyService(group.id, Constants.WEB_MINISTORE_SERVICE, + domain: existing_web_svc['domain'], + sid: existing_web_svc['store']['id'], + ), + )); + }, + ), + ), + ); + } else { + col.children.add( + Container( + padding: EdgeInsets.only(top: 8.0), + child: Text(S.of(context).enter_desired_domain), + ), + ); + col.children.add( + Container( + padding: EdgeInsets.only(top: 0,), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: TextFormField( + controller: domainController, + decoration: new InputDecoration( + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: Colors.black12, + ), + ), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: Colors.blue, + ), + ), + labelText: S.of(context).domains_separated_comma, + ), + style: TextStyle( + fontSize: 18.0 + ), + autofocus: true, + validator: (String value) { + if (value.trim().isEmpty) { + return S.of(context).domains_separated_comma; + } + return null; + }, + onChanged: (string) { + if (string.isNotEmpty) { + canSubmit = true; + } else { + canSubmit = false; + } + setState(() {}); + }, + ), + ), + Container( + padding: EdgeInsets.only(left: 8.0), + child: ElevatedButton( + child: Text( + S.of(context).check_domain_name, + ), + onPressed: domainController.text.length > 0 ? checkDomainAvailability : null, + ), + ), + ], + ), + ) + ); + if (domainResult.length > 0) { + for (dynamic dr in domainResult) { + col.children.add(_getDomain(dr)); + } + } + if (selectedDomain != null && service != null) { + col.children.add( + Container( + padding: EdgeInsets.only(top: 8.0), + child: Text( + service['description'], + ), + ), + ); + col.children.add( + Container( + padding: EdgeInsets.only(top: 8.0), + child: Text( + service['options'][0]['name'], + ), + ), + ); + col.children.add( + Container( + padding: EdgeInsets.only(top: 8.0), + child: Text( + '\$${service['options'][0]['price']}', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.orange, + ), + ), + ), + ); + col.children.add( + Container( + padding: EdgeInsets.only(top: 10.0), + child: ElevatedButton( + child: Text( + S.of(context).place_order_now, + ), + onPressed: () { + Navigator.pushReplacement(context, MaterialPageRoute( + builder: (BuildContext context) => + BuyService(group.id, Constants.WEB_MINISTORE_SERVICE, + domain: selectedDomain, + sid: selectedStore['id'], + ), + )); + }, + ), + ), + ); + } + } + return Container( + padding: EdgeInsets.only(bottom: 4,), + child: col, + ); + } + + @override + void initState() { + super.initState(); + HttpUtil.httpGet( + 'v1/get-contact-stores', + queryParameters: { + 'service': Constants.WEB_MINISTORE_SERVICE + } + ).then((value) { + setState(() { + stores = value['stores']; + service = value['service']; + group = Group.fromJson(value['group']); + print('stores: ${value}'); + }); + }).onError((error, stackTrace) { + Utils.showMessageDialog(context, error, onOk: () { + Routes.router.navigateTo(context, '/'); + }); + }); + } + + Future checkDomainAvailability() async { + Utils.showLoadingDialog(context); + selectedDomain = null; + domainResult = []; + setState(() {}); + HttpUtil.httpGet( + 'v1/check-domain-availability', + queryParameters: { + 'domain': domainController.text, + }, + ).then((value) { + Routes.router.pop(context); + print('value: $value'); + if (value['status'] == 'OK') { + domainResult = (value['domain_check_result'] as List); + setState(() {}); + } else if (value['status'] == 'ERROR') { + String errors = ''; + for (int i = 0; i < (value['errors'] as List).length; i++) { + errors += value['errors'][i] + '\n'; + } + Utils.showMessageDialog(context, errors); + } + }).onError((error, stackTrace) { + Routes.router.pop(context); + Utils.showMessageDialog(context, error); + }); + } + + Widget _getDomain(dynamic d) { + if ((d['available'] as bool)) { + return Container( + child: ListTile( + title: Text( + d['domain'], + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + leading: Radio( + value: d['domain'], + groupValue: selectedDomain, + onChanged: (val) { + setState(() { + selectedDomain = val; + }); + }, + ), + ), + ); + } else { + return Container( + padding: EdgeInsets.only(top: 1.0), + child: ListTile( + title: Text( + d['domain'], + style: TextStyle( + color: Colors.black45, + ), + ), + leading: Icon(Icons.clear, color: Colors.red,), + ), + ); + } + } +} diff --git a/lib/widgets/desktop/desktop_appbar_menu.dart b/lib/widgets/desktop/desktop_appbar_menu.dart index 70b5e06..759cd35 100644 --- a/lib/widgets/desktop/desktop_appbar_menu.dart +++ b/lib/widgets/desktop/desktop_appbar_menu.dart @@ -39,7 +39,8 @@ class DesktopAppBarMenu extends StatelessWidget { TextLink( S.of(context).home, '/', - color: Colors.white, + color: Colors.white60, + hoverColor: Colors.white, selected: currentRoute == '/', clearStack: true, ), @@ -47,14 +48,16 @@ class DesktopAppBarMenu extends StatelessWidget { TextLink( S.of(context).download, '/download', - color: Colors.white, + color: Colors.white60, + hoverColor: Colors.white, selected: currentRoute == '/download', ), SizedBox(width: 15.0,), TextLink( S.of(context).tutorials, Constants.TUTORIAL_URL, - color: Colors.white, + color: Colors.white60, + hoverColor: Colors.white, selected: currentRoute == '/tutorials', isLink: true, ), @@ -62,21 +65,24 @@ class DesktopAppBarMenu extends StatelessWidget { TextLink( S.of(context).support, '/my-support/${Constants.BUSINESS_ID}', - color: Colors.white, + color: Colors.white60, + hoverColor: Colors.white, selected: currentRoute == '/my-support/${Constants.BUSINESS_ID}', ), SizedBox(width: 15.0,), TextLink( S.of(context).shop, '/shop', - color: Colors.white, + color: Colors.white60, + hoverColor: Colors.white, selected: currentRoute == '/shop', ), SizedBox(width: 15.0,), TextLink( S.of(context).blog, '/blog/${Constants.BUSINESS_ID}', - color: Colors.white, + color: Colors.white60, + hoverColor: Colors.white, selected: currentRoute == '/blog/${Constants.BUSINESS_ID}', ), SizedBox(width: 15.0,), @@ -126,7 +132,8 @@ class DesktopAppBarMenu extends StatelessWidget { TextLink( S.of(context).login, '/login', - color: Colors.white, + color: Colors.white60, + hoverColor: Colors.white, selected: currentRoute == '/login', ), ], diff --git a/lib/widgets/desktop/desktop_blog.dart b/lib/widgets/desktop/desktop_blog.dart index 0340f1e..c4ef5f4 100644 --- a/lib/widgets/desktop/desktop_blog.dart +++ b/lib/widgets/desktop/desktop_blog.dart @@ -85,7 +85,7 @@ class DesktopBlogState extends State { BuildContext mainContext = context; return Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).blog, back: true, breadCrumbs: [ @@ -272,6 +272,7 @@ class DesktopBlogState extends State { 'size': Constants.BLOG_PER_PAGE_DESKTOP.toString() } ).then((value) { + print('value: $value'); if (mounted) { if (isRefresh) { _refreshController.refreshCompleted(); diff --git a/lib/widgets/desktop/desktop_buy_service.dart b/lib/widgets/desktop/desktop_buy_service.dart index df9fc9f..68db0fa 100644 --- a/lib/widgets/desktop/desktop_buy_service.dart +++ b/lib/widgets/desktop/desktop_buy_service.dart @@ -72,6 +72,18 @@ class DesktopBuyServiceState extends State { Utils.buildLine(S.of(context).your_group, widget.data['group']['name'], valueSize: 16), ); + if (widget.data['store']['id'] != null) { + col1.children.add( + Utils.buildLine(S.of(context).store, widget.data['store']['name'], valueSize: 16), + ); + } + + if (widget.data['domain'] != null) { + col1.children.add( + Utils.buildLine(S.of(context).domain_name, widget.data['domain'], valueSize: 16), + ); + } + if (widget.data['exists_service'] == null) { col1.children.add( Utils.buildLine(S.of(context).current_plan, 'N/A', valueSize: 16), @@ -171,7 +183,7 @@ class DesktopBuyServiceState extends State { ); return Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).blog, back: true, breadCrumbs: [ diff --git a/lib/widgets/desktop/desktop_checkout.dart b/lib/widgets/desktop/desktop_checkout.dart index b7badd4..da47598 100644 --- a/lib/widgets/desktop/desktop_checkout.dart +++ b/lib/widgets/desktop/desktop_checkout.dart @@ -178,7 +178,7 @@ class DesktopCheckoutState extends State with SingleTickerProvi Scaffold scaffold = Scaffold( key: _scaffoldKey, - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).blog, back: true, breadCrumbs: [ @@ -355,6 +355,7 @@ class DesktopCheckoutState extends State with SingleTickerProvi check(); }, initialLabelIndex: deliveryMethodIndex, + totalSwitches: shippingMethodLabels.length, ); switch (position) { case 0: diff --git a/lib/widgets/desktop/desktop_contact_us.dart b/lib/widgets/desktop/desktop_contact_us.dart index 99f0aff..6684098 100644 --- a/lib/widgets/desktop/desktop_contact_us.dart +++ b/lib/widgets/desktop/desktop_contact_us.dart @@ -329,7 +329,7 @@ class DesktopContactUsState extends State { ); } return Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).blog, back: true, breadCrumbs: [ diff --git a/lib/widgets/desktop/desktop_coupons.dart b/lib/widgets/desktop/desktop_coupons.dart index 67e2929..8f9c89b 100644 --- a/lib/widgets/desktop/desktop_coupons.dart +++ b/lib/widgets/desktop/desktop_coupons.dart @@ -78,7 +78,7 @@ class DesktopCouponsState extends State { ); return Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).blog, back: true, breadCrumbs: [ diff --git a/lib/widgets/desktop/desktop_edit_address.dart b/lib/widgets/desktop/desktop_edit_address.dart index 8da8630..c58a44e 100644 --- a/lib/widgets/desktop/desktop_edit_address.dart +++ b/lib/widgets/desktop/desktop_edit_address.dart @@ -399,7 +399,7 @@ class DesktopEditAddressState extends State { ); return Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).edit_address, back: true, breadCrumbs: [ diff --git a/lib/widgets/desktop/desktop_index_main_content_3.dart b/lib/widgets/desktop/desktop_index_main_content_3.dart index d9bde1f..ced65b8 100644 --- a/lib/widgets/desktop/desktop_index_main_content_3.dart +++ b/lib/widgets/desktop/desktop_index_main_content_3.dart @@ -101,7 +101,8 @@ class DesktopIndexMainContent3State extends State { TextLink(S.of(context).support_ticket, '/my-support/${Constants.BUSINESS_ID}', 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,) + TextLink(S.of(context).renew_license, '/renew-license', paddingVertical: 5.0, paddingHorizontal: 10.0,), + TextLink(S.of(context).create_a_online_store, '/contact-stores', paddingVertical: 5.0, paddingHorizontal: 10.0,) ], ), ), @@ -250,7 +251,8 @@ class DesktopIndexMainContent3State extends State { TextLink(S.of(context).support_ticket, '/my-support/${Constants.BUSINESS_ID}', paddingVertical: 5.0, paddingHorizontal: 0.0,), TextLink(S.of(context).contact_us, '/contact-us', paddingVertical: 5.0, paddingHorizontal: 0.0,), TextLink(S.of(context).about_us, '/about-us', paddingVertical: 5.0, paddingHorizontal: 0.0,), - TextLink(S.of(context).renew_license, '/renew-license', paddingVertical: 5.0, paddingHorizontal: 0.0,) + TextLink(S.of(context).renew_license, '/renew-license', paddingVertical: 5.0, paddingHorizontal: 0.0,), + TextLink(S.of(context).create_a_online_store, '/contact-stores', paddingVertical: 5.0, paddingHorizontal: 0.0,) ], ), ), diff --git a/lib/widgets/desktop/desktop_my_addresses.dart b/lib/widgets/desktop/desktop_my_addresses.dart index d57c442..05860bc 100644 --- a/lib/widgets/desktop/desktop_my_addresses.dart +++ b/lib/widgets/desktop/desktop_my_addresses.dart @@ -63,7 +63,7 @@ class DesktopMyAddressesState extends State { BuildContext mainContext = context; return Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).my_addresses, back: true, breadCrumbs: [ diff --git a/lib/widgets/desktop/desktop_my_cards.dart b/lib/widgets/desktop/desktop_my_cards.dart index 4e91346..241b443 100644 --- a/lib/widgets/desktop/desktop_my_cards.dart +++ b/lib/widgets/desktop/desktop_my_cards.dart @@ -48,7 +48,7 @@ class MyCardsState extends State { } return Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).blog, back: true, breadCrumbs: [ diff --git a/lib/widgets/desktop/desktop_my_support.dart b/lib/widgets/desktop/desktop_my_support.dart index 18b6e50..578159d 100644 --- a/lib/widgets/desktop/desktop_my_support.dart +++ b/lib/widgets/desktop/desktop_my_support.dart @@ -88,7 +88,7 @@ class DesktopMySupportState extends State { BuildContext mainContext = context; return Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).my_support, back: true, breadCrumbs: [ diff --git a/lib/widgets/desktop/desktop_navigationbar.dart b/lib/widgets/desktop/desktop_navigationbar.dart index 71cf412..51206ab 100644 --- a/lib/widgets/desktop/desktop_navigationbar.dart +++ b/lib/widgets/desktop/desktop_navigationbar.dart @@ -2,28 +2,25 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; -import 'package:flutter_wisetronic/widgets/desktop/desktop_appbar_menu.dart'; -import '../../widgets/general/breadcrumbs.dart'; import '../../constants.dart'; -import '../../dialog/logout_dialog.dart'; import '../../events/eventbus.dart'; import '../../events/events.dart'; -import '../../generated/l10n.dart'; import '../../models/user.dart'; -import '../../routes.dart'; import '../../store/store.dart'; import '../../utils/utils.dart'; -import '../../widgets/general/navigationbar_logo.dart'; -import '../../widgets/general/text_link.dart'; +import '../../widgets/desktop/desktop_appbar_menu.dart'; +import '../../widgets/general/breadcrumbs.dart'; +import '../../widgets/general/navigationbar.dart'; class DesktopNavigationBar extends StatefulWidget { final bool hasBack; final List breadCrumbs; final Widget shoppingCart; + final OnBackPress onBackPress; const DesktopNavigationBar({Key key, this.hasBack, this.breadCrumbs, - this.shoppingCart}) : super(key: key); + this.shoppingCart, this.onBackPress}) : super(key: key); @override State createState() { @@ -37,132 +34,6 @@ class DesktopNavigationBarState extends State { @override Widget build(BuildContext context) { - // String currentRoute = ModalRoute.of(context).settings.name; - // Stack stack = 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(), - // Expanded( - // child: Container( - // alignment: Alignment.centerRight, - // padding: EdgeInsets.only(left: 8.0, right: 16.0), - // child: SingleChildScrollView( - // scrollDirection: Axis.horizontal, - // child: Row( - // mainAxisSize: MainAxisSize.min, - // children: [ - // SizedBox(width: 20.0,), - // TextLink( - // S.of(context).home, - // '/', - // color: Colors.white, - // selected: currentRoute == '/', - // clearStack: true, - // ), - // 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, - // '/my-support/${Constants.BUSINESS_ID}', - // color: Colors.white, - // selected: currentRoute == '/my-support/${Constants.BUSINESS_ID}', - // ), - // 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/${Constants.BUSINESS_ID}', - // color: Colors.white, - // selected: currentRoute == '/blog/${Constants.BUSINESS_ID}', - // ), - // SizedBox(width: 15.0,), - // _user != null ? - // (currentRoute == '/me') ? - // MouseRegion( - // cursor: SystemMouseCursors.click, - // child: GestureDetector( - // child: Row( - // mainAxisAlignment: MainAxisAlignment.start, - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Container( - // padding: EdgeInsets.only(right: 4.0), - // child: Text( - // S.of(context).logout, - // style: TextStyle( - // color: Colors.white, - // ), - // ), - // ), - // Icon( - // Icons.logout, - // color: Colors.white, - // size: 16.0, - // ) - // ], - // ), - // onTap: () { - // showDialog( - // context: context, - // builder: (BuildContext context) { - // return logoutDialog(context); - // } - // ); - // }, - // ), - // ) : IconButton( - // icon: Icon( - // Icons.account_circle, - // color: Colors.white, - // ), - // onPressed: () { - // Routes.router.navigateTo(context, '/me'); - // }, - // ) : - // TextLink( - // S.of(context).login, - // '/login', - // color: Colors.white, - // selected: currentRoute == '/login', - // ), - // ], - // ), - // ), - // ), - // ), - // ], - // ), - // ), - // ], - // ); Widget sc = SizedBox.shrink(); if (widget.shoppingCart != null) { sc = widget.shoppingCart; @@ -171,8 +42,8 @@ class DesktopNavigationBarState extends State { if (widget.breadCrumbs != null && widget.breadCrumbs.length > 0) { breadCrumbBar = Container( width: MediaQuery.of(context).size.width, - height: 38.0, - color: Color(0xFF4FB0C6), + height: Constants.BREADCRUMB_HEIGHT, + padding: EdgeInsets.only(top: 6.0), child: Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, @@ -180,6 +51,7 @@ class DesktopNavigationBarState extends State { Expanded( child: BreadCrumbs( widget.hasBack ?? false, + onBackPress: widget.onBackPress, breadCrumbs: widget.breadCrumbs, ), ), @@ -189,14 +61,18 @@ class DesktopNavigationBarState extends State { ), ], ), + decoration: BoxDecoration( + color: Colors.black12, + border: Border( + bottom: BorderSide( + width: 1.0, + color: Colors.black26, + ), + ), + ), ); } - // stack.children.add( - // Positioned( - // top: 90.0, - // child: breadCrumbBar, - // ), - // ); + return Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/widgets/desktop/desktop_new_address.dart b/lib/widgets/desktop/desktop_new_address.dart index a43b79c..2aa38b7 100644 --- a/lib/widgets/desktop/desktop_new_address.dart +++ b/lib/widgets/desktop/desktop_new_address.dart @@ -324,7 +324,7 @@ class DesktopNewAddressState extends State { ); return Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).new_address, back: true, breadCrumbs: [ diff --git a/lib/widgets/desktop/desktop_new_comment.dart b/lib/widgets/desktop/desktop_new_comment.dart index ba9629b..03e48b4 100644 --- a/lib/widgets/desktop/desktop_new_comment.dart +++ b/lib/widgets/desktop/desktop_new_comment.dart @@ -62,7 +62,7 @@ class DesktopNewCommentState extends State { } return Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).new_comment, back: true, breadCrumbs: [ diff --git a/lib/widgets/desktop/desktop_order_detail.dart b/lib/widgets/desktop/desktop_order_detail.dart index 634f698..be3bfc6 100644 --- a/lib/widgets/desktop/desktop_order_detail.dart +++ b/lib/widgets/desktop/desktop_order_detail.dart @@ -958,7 +958,7 @@ class DesktopOrderDetailState extends State { ); return Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).blog, back: true, breadCrumbs: [ diff --git a/lib/widgets/desktop/desktop_orders.dart b/lib/widgets/desktop/desktop_orders.dart index 59308df..c67951e 100644 --- a/lib/widgets/desktop/desktop_orders.dart +++ b/lib/widgets/desktop/desktop_orders.dart @@ -98,7 +98,7 @@ class DesktopOrdersState extends State with SingleTickerProviderS return Scaffold( key: _scaffoldKey, - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).blog, back: true, breadCrumbs: [ diff --git a/lib/widgets/desktop/desktop_pay_now.dart b/lib/widgets/desktop/desktop_pay_now.dart index ecacd7f..bce196a 100644 --- a/lib/widgets/desktop/desktop_pay_now.dart +++ b/lib/widgets/desktop/desktop_pay_now.dart @@ -345,7 +345,7 @@ class DesktopPayNowState extends State { ); return Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).blog, back: true, breadCrumbs: [ diff --git a/lib/widgets/desktop/desktop_plain_page.dart b/lib/widgets/desktop/desktop_plain_page.dart index 9749e9e..2844fca 100644 --- a/lib/widgets/desktop/desktop_plain_page.dart +++ b/lib/widgets/desktop/desktop_plain_page.dart @@ -60,7 +60,7 @@ class DesktopPlainPageState extends State { )); return Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).blog, back: true, breadCrumbs: [ diff --git a/lib/widgets/desktop/desktop_product_detail_page.dart b/lib/widgets/desktop/desktop_product_detail_page.dart index bafb8b4..d6a5f70 100644 --- a/lib/widgets/desktop/desktop_product_detail_page.dart +++ b/lib/widgets/desktop/desktop_product_detail_page.dart @@ -79,7 +79,7 @@ class DesktopProductDetailPageState extends State } return Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).shop, back: true, breadCrumbs: [ diff --git a/lib/widgets/desktop/desktop_renew_license.dart b/lib/widgets/desktop/desktop_renew_license.dart index 912b584..4960562 100644 --- a/lib/widgets/desktop/desktop_renew_license.dart +++ b/lib/widgets/desktop/desktop_renew_license.dart @@ -167,7 +167,7 @@ class DesktopRenewLicenseState extends State { ); return Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).blog, back: true, breadCrumbs: [ diff --git a/lib/widgets/desktop/desktop_renew_minioffice.dart b/lib/widgets/desktop/desktop_renew_minioffice.dart index 8ee51ab..9685b83 100644 --- a/lib/widgets/desktop/desktop_renew_minioffice.dart +++ b/lib/widgets/desktop/desktop_renew_minioffice.dart @@ -136,7 +136,7 @@ class DesktopRenewMiniOfficeState extends State { ); return Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).blog, back: true, breadCrumbs: [ diff --git a/lib/widgets/desktop/desktop_search_place.dart b/lib/widgets/desktop/desktop_search_place.dart index 947ffc9..d49ee44 100644 --- a/lib/widgets/desktop/desktop_search_place.dart +++ b/lib/widgets/desktop/desktop_search_place.dart @@ -45,7 +45,7 @@ class DesktopSearchPlaceState extends State { } return Scaffold( - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).search_place, back: true, breadCrumbs: [ diff --git a/lib/widgets/desktop/desktop_set_password.dart b/lib/widgets/desktop/desktop_set_password.dart index 5568f41..d00acf3 100644 --- a/lib/widgets/desktop/desktop_set_password.dart +++ b/lib/widgets/desktop/desktop_set_password.dart @@ -288,7 +288,7 @@ class DesktopSetPasswordState extends State { ); }, queryParameters: { - 'action': 'reset_password', + 'action': 'create_user', }, isFormData: true, body: { diff --git a/lib/widgets/desktop/desktop_stripe_pay_web.dart b/lib/widgets/desktop/desktop_stripe_pay_web.dart index 0131180..802aa19 100644 --- a/lib/widgets/desktop/desktop_stripe_pay_web.dart +++ b/lib/widgets/desktop/desktop_stripe_pay_web.dart @@ -109,7 +109,7 @@ class DesktopStripePayWebState extends State { return Scaffold( key: _scaffoldKey, - appBar: NavigationBar( + appBar: MiniNavigationBar( title: S.of(context).blog, back: true, breadCrumbs: [ diff --git a/lib/widgets/desktop/desktop_tutorials.dart b/lib/widgets/desktop/desktop_tutorials.dart deleted file mode 100644 index 3119421..0000000 --- a/lib/widgets/desktop/desktop_tutorials.dart +++ /dev/null @@ -1,127 +0,0 @@ - -import '../../constants.dart'; -import '../../utils/iframe_web.dart' if (dart.library.io) '../../utils/fake_iframe_web.dart'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; - -class DesktopTutorials extends StatefulWidget { - const DesktopTutorials({Key key}) : super(key: key); - - @override - State createState() { - return DesktopTutorialsState(); - } - -} - -class DesktopTutorialsState extends State { - double sideSpace = 0; - double mainSpace = 1200; - - InAppWebViewController webView; - String url = ""; - double progress = 0; - bool isLoadStop = false; - - @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; - } - - if (kIsWeb) { - return Row( - children: [ - Container( - width: sideSpace, - ), - Expanded( - child: Column( - mainAxisSize: MainAxisSize.max, - children: [ - Expanded( - child: IFrameWeb( - width: double.maxFinite.toString(), - height: double.maxFinite.toString(), - src: Constants.TUTORIAL_URL, - ), - ), - ], - ), - ), - Container( - width: sideSpace, - ), - ], - ); - } else { - print('progress: $progress'); - return Stack( - children: [ - Row( - children: [ - Container( - width: sideSpace, - ), - Expanded( - child: InAppWebView( - initialUrlRequest: URLRequest(url: Uri.parse(Constants.TUTORIAL_URL)), - initialOptions: InAppWebViewGroupOptions( - crossPlatform: InAppWebViewOptions( - - ), - ), - onWebViewCreated: (InAppWebViewController controller) { - webView = controller; - }, - onLoadStart: (controller, url) { - if (mounted) { - setState(() { - this.url = url.toString(); - this.isLoadStop = false; - }); - } - }, - onLoadStop: (controller, url) async { - if (mounted) { - setState(() { - this.url = url.toString(); - this.isLoadStop = true; - }); - } - }, - onProgressChanged: (InAppWebViewController controller, int progress) { - if (mounted) { - setState(() { - if (this.progress < 1.0) { - this.isLoadStop = false; - } else { - this.isLoadStop = true; - } - this.progress = progress / 100; - }); - } - }, - ), - ), - Container( - width: sideSpace, - ), - ], - ), - isLoadStop ? Container() : - Center( - child: CircularProgressIndicator(), - ), - ], - ); - } - } - -} \ No newline at end of file diff --git a/lib/widgets/desktop/desktop_view_blog.dart b/lib/widgets/desktop/desktop_view_blog.dart index 3abc029..e0bcdc7 100644 --- a/lib/widgets/desktop/desktop_view_blog.dart +++ b/lib/widgets/desktop/desktop_view_blog.dart @@ -13,6 +13,8 @@ import '../../utils/http_util.dart'; import '../../utils/utils.dart'; import '../../widgets/general/breadcrumbs.dart'; +import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart'; + class DesktopViewBlog extends StatefulWidget { final Key key; final int bid; @@ -172,11 +174,7 @@ class DesktopViewBlogState extends State { : Container( width: mainSpace / 2 - 100.0, height: mainSpace / 2 - 100.0, - child: PhotoView( - imageProvider: NetworkImage( - 'https:${blog.imageUrl}', - ), - ), + child: Util.showImage('https:${blog.imageUrl}'), ), ), ], diff --git a/lib/widgets/desktop/product_item.dart b/lib/widgets/desktop/product_item.dart new file mode 100644 index 0000000..033f9f1 --- /dev/null +++ b/lib/widgets/desktop/product_item.dart @@ -0,0 +1,280 @@ + +import 'package:flutter/material.dart'; +import 'package:hovering/hovering.dart'; + +import '../../events/eventbus.dart'; +import '../../events/events.dart'; +import '../../generated/l10n.dart'; +import '../../models/business.dart'; +import '../../models/product.dart'; +import '../../pages/product_detail_page.dart'; +import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart'; +import '../../widgets/general/add_remove_button.dart'; +import '../../widgets/general/show_price.dart'; + +class ProductItem extends StatefulWidget { + final Business business; + final Product product; + final bool horizontal; + + const ProductItem(this.product, this.business, {Key key, this.horizontal = false}) : super(key: key); + + @override + State createState() => ProductItemState(); + +} + +class ProductItemState extends State { + + @override + Widget build(BuildContext context) { + return HoverWidget( + child: Container( + width: 160.0, + height: widget.horizontal ? 160 : 268.0, + padding: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 15.0).copyWith(bottom: 5.0), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: new BorderSide( + color: new Color(0xFFEBEBEB), + ), + ), + ), + child: new SizedBox.expand( + child: Container( + padding: EdgeInsets.only(left: 10.0, right: 10.0, top: 10.0, bottom: 10.0), + child: widget.horizontal ? getHorizontal(false) : getVertial(false), + ), + ), + ), + hoverChild: Container( + width: 160.0, + height: widget.horizontal ? 160 : 268.0, + padding: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 15.0).copyWith(bottom: 5.0), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + top: new BorderSide( + color: new Color(0xFFEBEBEB), + ), + left: new BorderSide( + color: new Color(0xFFEBEBEB), + ), + right: new BorderSide( + color: new Color(0xFFEBEBEB), + ), + bottom: new BorderSide( + color: new Color(0xFFBBBBBB), + ), + ), + ), + child: new SizedBox.expand( + child: Container( + padding: EdgeInsets.only(left: 10.0, right: 10.0, top: 10.0, bottom: 10.0), + child: widget.horizontal ? getHorizontal(true) : getVertial(true), + ), + ), + ), + onHover: (event) { + + } + ); + } + + Widget getHorizontal(bool onHover) { + return Row( + children: [ + Container( + margin: new EdgeInsets.all(10.0), + width: 110.0, + height: 110.0, + child: GestureDetector( + child: onHover && widget.product.secondImagePath.isNotEmpty ? + Util.showImage('${widget.product.secondImagePath}', + fit: BoxFit.fill, + ) : + Util.showImage('${widget.product.imagePath}', + fit: BoxFit.fill, + ), + onTap: (){ + _showProductDetail(); + }, + ), + ), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + child: GestureDetector( + child: Text( + '${widget.product.name}', +// overflow: kIsWeb ? null : TextOverflow.ellipsis, + overflow: TextOverflow.ellipsis, + maxLines: 2, + softWrap: true, + style: new TextStyle( + fontSize: 15.0, + ), + ), + onTap: (){ + _showProductDetail(); + }, + ), + ), + Text( + widget.product.description, +// overflow: kIsWeb ? null : TextOverflow.ellipsis, + overflow: TextOverflow.ellipsis, + maxLines: 2, + style: new TextStyle( + fontSize: 12.0, + color: new Color(0xFF999999), + ), + ), + new Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + child: widget.business.showMonthlySold ? + Text( + S.of(context).sold_per_month_token(widget.product.monthSales.toStringAsFixed(0)), + style: new TextStyle( + fontSize: 9.0 + ), + ) : SizedBox.shrink(), + ), + ShowPrice( + widget.product.price, + regularPrice: widget.product.regularPrice, + currencySign: '\$', + fontWeight: FontWeight.bold, + ), + ], + ), + AddRemoveButton(product: widget.product, business: widget.business, addOnly: false, onHovor: onHover,), + ], + ), + ], + ), + ), + ], + ); + } + + Widget getVertial(bool onHover) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new Container( + margin: new EdgeInsets.all(10.0), + width: 110.0, + height: 110.0, + child: GestureDetector( + child: onHover && widget.product.secondImagePath.isNotEmpty ? + Util.showImage('${widget.product.secondImagePath}', + fit: BoxFit.fill, + ) : + Util.showImage('${widget.product.imagePath}', + fit: BoxFit.fill, + ), + onTap: (){ + _showProductDetail(); + }, + ), + ), + new Expanded( + child: new Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + child: GestureDetector( + child: Text( + '${widget.product.name}', +// overflow: kIsWeb ? null : TextOverflow.ellipsis, + overflow: TextOverflow.ellipsis, + maxLines: 2, + softWrap: true, + style: new TextStyle( + fontSize: 15.0, + ), + ), + onTap: (){ + _showProductDetail(); + }, + ), + ), + Container( + child: Text( + widget.product.description, +// overflow: kIsWeb ? null : TextOverflow.ellipsis, + overflow: TextOverflow.ellipsis, + maxLines: 2, + style: new TextStyle( + fontSize: 12.0, + color: new Color(0xFF999999), + ), + ), + ), + new Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + child: widget.business.showMonthlySold ? + Text( + S.of(context).sold_per_month_token(widget.product.monthSales.toStringAsFixed(0)), + style: new TextStyle( + fontSize: 9.0 + ), + ) : SizedBox.shrink(), + ), + ShowPrice( + widget.product.price, + regularPrice: widget.product.regularPrice, + currencySign: '\$', + fontWeight: FontWeight.bold, + ), + ], + ), + AddRemoveButton(product: widget.product, business: widget.business, addOnly: false, onHovor: onHover,), + ], + ), + ], + ), + ), + ], + ); + } + + void _showProductDetail() { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ProductDetailPage( + product: widget.product, + business: widget.business, + )), + ); + } + + @override + void initState() { + super.initState(); + eventBus.on().listen((event) { + if (mounted) { + setState(() { + + }); + } + }); + } +} \ No newline at end of file diff --git a/lib/widgets/desktop/product_search.dart b/lib/widgets/desktop/product_search.dart new file mode 100644 index 0000000..4e2086f --- /dev/null +++ b/lib/widgets/desktop/product_search.dart @@ -0,0 +1,181 @@ + +import 'package:dio/dio.dart'; +import 'package:flappy_search_bar/flappy_search_bar.dart'; +import 'package:flutter/material.dart'; + +import '../../constants.dart'; +import '../../events/eventbus.dart'; +import '../../events/events.dart'; +import '../../generated/l10n.dart'; +import '../../models/business.dart'; +import '../../models/product.dart'; +import '../../pages/product_detail_page.dart'; +import '../../utils/http_util.dart'; +import '../../utils/utils.dart'; +import '../../widgets/general/bottom_nav.dart'; +import '../../widgets/general/breadcrumbs.dart'; +import '../../widgets/general/navigationbar.dart'; +import 'product_item.dart'; + +class ProductSearch extends StatefulWidget { + final Business business; + + const ProductSearch(this.business, {Key key}) : super(key: key); + + @override + State createState() => ProductSearchState(); +} + +class ProductSearchState extends State { + + double sideSpace = 0; + double mainSpace = 1200; + double rate = 1; + + int page = 1; + int numPerPage = 10; + int lastResultSize = 0; + double lastBottomPosition = 0; + String lastKeyword = ''; + + SearchBarController _controller = SearchBarController(); + + @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; + } + rate = mainSpace / 1200; + + return Scaffold( + appBar: MiniNavigationBar( + title: S.of(context).search_product, + back: true, + breadCrumbs: [ + BreadCrumb(S.of(context).search_product, null), + ], + breadCrumbHeight: Constants.BREADCRUMB_HEIGHT, + ), + drawer: null, + body: SafeArea( + child: Container( + child: Row( + children: [ + Container( + width: sideSpace, + ), + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: NotificationListener( + child: SearchBar( + searchBarController: _controller, + minimumChars: 2, + hintText: S.of(context).enter_keyword, + cancellationWidget: Text( + S.of(context).cancel, + ), + onSearch: search, + onItemFound: (Product searchProduct, int index) { + return ProductItem( + searchProduct, + widget.business, + horizontal: true, + ); + }, + onError: (error) { + return Center( + child: Text("$error"), + ); + }, + emptyWidget: Center( + child: Text( + S.of(context).empty_result_change_keyword, + ), + ), + ), + onNotification: (notification) { + if (notification.metrics.atEdge) { + print('fff: $page, $lastBottomPosition, ${notification.metrics.pixels}'); + if (page != 0 && lastResultSize >= numPerPage && notification.metrics.pixels != 0) { + if (notification.metrics.pixels > lastBottomPosition) { + lastBottomPosition = notification.metrics.pixels; + page += 1; + _controller.replayLastSearch(); + } + } + } + return true; + }, + ), + ), + ), + Container( + width: sideSpace, + ), + ], + ), + ), + ), + bottomNavigationBar: BottomNav(), + ); + } + + Future> search(String keyword) async { + if (lastKeyword != keyword) { + page = 1; + } + lastKeyword = keyword; + var result = await HttpUtil.httpGet('v1/search-store-product2', + queryParameters: { + 'store_id': widget.business.id, + 'keyword': keyword, + 'page': page, + 'num_per_page': numPerPage, + }, + returnError: true, + ); + if (result is DioError) { + if (result.response != null) { + throw RuntimeError(result.response.data); + } else { + throw RuntimeError(result.message); + } + } else if (result != null && result is List) { + lastBottomPosition = 0; + var r = result.map((e) => Product.fromJson(e)).toList(); + lastResultSize = r.length; + if (lastResultSize < numPerPage) { + page = 1; + } + return r; + } + return []; + } + + @override + void initState() { + super.initState(); + eventBus.on().listen((event) { + if (mounted) { + setState(() {}); + } + }); + } + + void _showProductDetail(Product p) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ProductDetailPage( + product: p, + business: widget.business, + )), + ); + } +} \ No newline at end of file diff --git a/lib/widgets/desktop/shop.dart b/lib/widgets/desktop/shop.dart new file mode 100644 index 0000000..82c7877 --- /dev/null +++ b/lib/widgets/desktop/shop.dart @@ -0,0 +1,297 @@ + + +import 'package:flutter/material.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; +import '../../utils/utils.dart'; +import '../../widgets/desktop/shop_products.dart'; +import '../../widgets/general/bottom_nav.dart'; +import '../../widgets/general/breadcrumbs.dart'; +import '../../widgets/general/navigationbar.dart'; +import '../../widgets/general/sliding_up_panel.dart'; +import '../../widgets/mobile/shopping_cart_bar.dart'; +import 'shop_bulletin.dart'; + +import '../../constants.dart'; +import '../../events/eventbus.dart'; +import '../../events/events.dart'; +import '../../generated/l10n.dart'; +import '../../models/business.dart'; +import '../../models/category_products.dart'; +import 'product_search.dart'; +import 'shop_promote.dart'; +import 'shopping_cart_widget.dart'; + +class Shop extends StatefulWidget { + final int businessId; + + const Shop({Key key, this.businessId}): super(key: key); + + @override + State createState() => ShopState(); + +} + +class ShopState extends State { + Business _business; + + PanelController panelController = PanelController(); + SlidingUpPanel _slidUpShoppingCart; + GlobalKey endKey = GlobalKey(); + + List _categoryProducts; + bool displayProductByCategoryClick = false; + String displayProductByCategoryClickIndicator = ''; + int categoryId = 0; + static int _productCurrentPage = 1; + + int _categoryIndex = 0; + bool _categoryIndexChange = false; + bool _isLoading = false; + + dynamic data; + + @override + Widget build(BuildContext context) { + if (_business == null) { + return Scaffold( + body: Center( + child: SpinKitWave( + color: Colors.lightBlueAccent, + size: 40.0, + ), + ), + ); + } + + _slidUpShoppingCart = SlidingUpPanel( + controller: panelController, + minHeight: 0.0, + maxHeight: 250.0, + isDraggable: false, + backdropEnabled: true, + slideDirection: SlideDirection.DOWN, + panel: ShoppingCartBar( + business: _business, + endKey: endKey, + barAtBottom: true, + hasPicture: true, + onEmptyCartListener: () { + Future.delayed(Duration(seconds: 1), () { + panelController.close(); + }); + }, + onPanelOpenCloseRequest: () { + if (panelController.isPanelOpen) { + panelController.close(); + } else { + panelController.open(); + } + }, + ), + ); + + Scaffold scaffold = Scaffold( + appBar: MiniNavigationBar( + title: S.of(context).shop, + back: true, + breadCrumbs: [ + BreadCrumb(S.of(context).shop, null), + BreadCrumb(null, null, + item: Container( + margin: EdgeInsets.only(left: 20.0), + child: Row( + children: [ + Container( + child: Icon( + Icons.search, + size: 24, + color: Colors.blue, + ), + ), + Container( + child: Text( + S.of(context).search_product, + ), + ), + ], + ), + ), + onTap: () { + Navigator.push(context, + MaterialPageRoute(builder: (BuildContext context) { + return ProductSearch(_business); + })); + }, + ), + ], + breadCrumbHeight: Constants.BREADCRUMB_HEIGHT, + shoppingCart: ShoppingCartWidget( + business: _business, + onTap: () { + if (panelController.isPanelClosed) { + panelController.open(); + } + }, + ), + ), + body: Scrollbar( + child: NotificationListener( + onNotification: (scrollNotification) { + if (scrollNotification is ScrollEndNotification && + scrollNotification.metrics.pixels == scrollNotification.metrics.maxScrollExtent) { + loadMoreProducts(); + } + return false; + }, + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + ShopPromote(data), + ShopBulletin(_business), + ShopProducts(data), + ], + ), + ), + ), + ), + bottomNavigationBar: BottomNav(), + ); + return Stack( + children: [ + Positioned( + top: 0, + left: 0, + right: 0, + bottom: 0, + child: scaffold, + ), + _slidUpShoppingCart, + ], + ); + } + + @override + void initState() { + super.initState(); + eventBus.on().listen((event) { + if (mounted) { + setState(() { + + }); + } + }); + eventBus.on().listen((event) { + if (mounted) { + // setState(() { + // categoryId = event.categoryId; + // _productCurrentPage = 1; + // }); + categoryId = event.categoryId; + _productCurrentPage = 1; + _isLoading = true; + Utils.showLoadingDialog(context, message: S.of(context).loading); + loadProducts(); + } + }); + loadProducts(); + } + + void loadProducts() { + print('categoryId $categoryId'); + if (categoryId < 0) { + return; + } + _productCurrentPage = 1; + Utils.loadProducts( + widget.businessId, categoryId, _productCurrentPage, false, + (value) { + if (_isLoading) { + _isLoading = false; + Navigator.of(context).pop(); + } + if (mounted) { + if (_business == null) { + setState(() { + displayProductByCategoryClick = + value['display_product_by_category_click']; + displayProductByCategoryClickIndicator = ''; + _business = Business.fromJson(value['business']); + _categoryProducts = (value['category_products'] as List) + .map((i) => CategoryProducts.fromJson(i)) + .toList(); + if (categoryId == 0 && displayProductByCategoryClick) { + categoryId = _categoryProducts[0].id; + } + data = value; + }); + } else { + eventBus.fire(GetCategoryProducts(value)); + } + } + }, + (error) { + print('error: $error'); + if (_isLoading) { + _isLoading = false; + Navigator.of(context).pop(); + } + if (mounted) { + setState(() {}); + } + Utils.showMessageDialog(context, error); + }, featuredCount: 6, hotSaleCount: 0, keyword: '' + ); + } + + void loadMoreProducts() { + if (_productCurrentPage == 0 || categoryId <= 0) { + return; + } + _productCurrentPage += 1; + Utils.loadProducts(widget.businessId, categoryId, _productCurrentPage, true, (value) { + if (_isLoading) { + _isLoading = false; + Navigator.of(context).pop(); + } + if (mounted) { + List moreCategoryProducts = (value as List).map((i) => CategoryProducts.fromJson(i)).toList(); + if (moreCategoryProducts.isEmpty) { + _productCurrentPage = 0; + } else { + if (moreCategoryProducts[0].products.length < Constants.ORDERS_PER_PAGE) { + _productCurrentPage = 0; + } + } + eventBus.fire(MoreCategoryProducts(moreCategoryProducts)); + } + }, (error) { + print('error: $error'); + if (_isLoading) { + _isLoading = false; + Navigator.of(context).pop(); + } + Utils.showMessageDialog(context, error); + } + ); + } + + int nextCategoryId(int currentCategoryId) { + if (_categoryProducts.length <= 0) { + return 0; + } + for (int i = 0; i < _categoryProducts.length; i++) { + if (_categoryProducts[i].id == currentCategoryId) { + try { + CategoryProducts cps = _categoryProducts[i + 1]; + return cps.id; + } catch (error) { + print('Error $error'); + } + } + } + return 0; + } +} \ No newline at end of file diff --git a/lib/widgets/desktop/desktop_shop.dart b/lib/widgets/desktop/shop_backup_dec_19_2021.dart similarity index 79% rename from lib/widgets/desktop/desktop_shop.dart rename to lib/widgets/desktop/shop_backup_dec_19_2021.dart index fba64f0..6534af1 100644 --- a/lib/widgets/desktop/desktop_shop.dart +++ b/lib/widgets/desktop/shop_backup_dec_19_2021.dart @@ -1,14 +1,11 @@ -import 'dart:async'; + import 'dart:math'; import 'package:badges/badges.dart'; import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; -import 'package:flutter_wisetronic/widgets/mobile/shopping_cart_bar.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:smooth_star_rating/smooth_star_rating.dart'; @@ -24,34 +21,31 @@ import '../../models/comment.dart'; import '../../models/product.dart'; import '../../models/product_image.dart'; import '../../pages/product_detail_page.dart'; -import '../../pages/store_product_search.dart'; -import '../../store/actions.dart'; import '../../store/store.dart'; import '../../utils/http_util.dart'; import '../../utils/shop_scroll_controller.dart'; import '../../utils/shop_scroll_coordinator.dart'; -import '../../utils/util_web.dart' - if (dart.library.io) '../../utils/util_io.dart'; +import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart'; import '../../utils/utils.dart'; import '../../widgets/general/add_remove_button.dart'; import '../../widgets/general/bottom_nav.dart'; import '../../widgets/general/breadcrumbs.dart'; import '../../widgets/general/carousel.dart'; import '../../widgets/general/navigationbar.dart'; -import '../../widgets/general/product_item.dart'; import '../../widgets/general/read_more_text.dart'; import '../../widgets/general/show_price.dart'; import '../../widgets/general/sliding_up_panel.dart'; -import '../../widgets/general/style.dart'; -import 'desktop_shopping_cart_widget.dart'; +import '../../widgets/mobile/shopping_cart_bar.dart'; +import 'product_item.dart'; +import 'shopping_cart_widget.dart'; -class DesktopShop extends StatefulWidget { +class Shop extends StatefulWidget { final int businessId; - const DesktopShop({Key key, this.businessId}) : super(key: key); + const Shop({Key key, this.businessId}) : super(key: key); @override - State createState() => DesktopShopState(); + State createState() => ShopState(); } MediaQueryData mediaQuery; @@ -59,7 +53,7 @@ double statusBarHeight; double screenWidth; double screenHeight; -class DesktopShopState extends State +class ShopState extends State with TickerProviderStateMixin, AutomaticKeepAliveClientMixin { GlobalKey _scaffoldKey = new GlobalKey(); @@ -109,7 +103,7 @@ class DesktopShopState extends State int _commentPageCount = 1; bool _commentLoadingFinish = false; RefreshController _commentRefreshController = - RefreshController(initialRefresh: true); + RefreshController(initialRefresh: true); PanelController panelController = PanelController(); SlidingUpPanel _slidUpShoppingCart; @@ -123,6 +117,44 @@ class DesktopShopState extends State double lastProductListScrollPositionPixel = 0; + final TextEditingController _searchController = new TextEditingController(); + Widget searchFieldPlaceHolder; + Icon searchIcon = new Icon( + Icons.search, + color: Colors.blue, + ); + bool _isSearching = false; + String _searchText = ""; + + dynamic responseData; + + ShopState() { + _searchController.addListener(() { + if (_searchController.text.isEmpty) { + setState(() { + // _isSearching = false; + _searchText = ""; + if (responseData != null) { + _categoryProducts.clear(); + _categoryProducts = (responseData['category_products'] as List) + .map((i) => CategoryProducts.fromJson(i)) + .toList(); + } else { + categoryId = 0; + loadProducts(); + } + }); + } else { + if (!displayProductByCategoryClick) { + setState(() { + _isSearching = true; + _searchText = _searchController.text; + }); + } + } + }); + } + void _onCommentRefresh() { if (_commentPage - 1 > 1) { _commentPage -= 1; @@ -253,9 +285,33 @@ class DesktopShopState extends State left: 10.0, top: 10.0, bottom: 10.0, + right: 10.0, + ), + margin: EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0), + width: 220.0, + height: 220.0, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(5.0)), + color: Colors.white, + border: Border( + top: BorderSide( + width: 1.0, + color: Colors.black12, + ), + bottom: BorderSide( + width: 1.0, + color: Colors.black12, + ), + left: BorderSide( + width: 1.0, + color: Colors.black12, + ), + right: BorderSide( + width: 1.0, + color: Colors.black12, + ), + ), ), - width: 240.0, - height: 320.0, child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -263,6 +319,7 @@ class DesktopShopState extends State child: Container( child: Util.showImage( _business.promoProducts[i].imagePath, + width: 120.0, ), ), onTap: () { @@ -307,8 +364,8 @@ class DesktopShopState extends State pinned: false, floating: true, delegate: _SliverAppBarDelegate2( - minHeight: 350.0, - maxHeight: 350.0, + minHeight: 260.0, + maxHeight: 260.0, child: Row( children: [ Container( @@ -413,10 +470,24 @@ class DesktopShopState extends State final newOffset = _pageScrollController.offset + ps.scrollDelta.dy; if (ps.scrollDelta.dy.isNegative) { _pageScrollController.jumpTo(max(0, newOffset)); + if (max(0, newOffset) == 0) { + _listScrollController1.jumpTo(max(0, _listScrollController1.offset - 10)); + } } else { _pageScrollController .jumpTo(min(_pageScrollController.position.maxScrollExtent, newOffset)); + if (newOffset > _pageScrollController.position.maxScrollExtent) { + _listScrollController1.jumpTo(min(_listScrollController1.position.maxScrollExtent, _listScrollController1.offset + 10)); + + } } + + // if (ps.scrollDelta.dy.isNegative) { + // _listScrollController2.jumpTo(max(0, newOffset)); + // } else { + // _listScrollController2 + // .jumpTo(min(_listScrollController2.position.maxScrollExtent, newOffset)); + // } } }, child: CustomScrollView( @@ -427,45 +498,86 @@ class DesktopShopState extends State pinned: true, floating: true, delegate: _SliverAppBarDelegate2( - minHeight: 94, - maxHeight: 94, + minHeight: 98, + maxHeight: 98, child: Column( children: [ - NavigationBar( + MiniNavigationBar( title: S.of(context).shop, back: true, breadCrumbs: [ BreadCrumb(S.of(context).shop, null), - BreadCrumb(null, null, + // BreadCrumb(null, null, + // item: Container( + // margin: EdgeInsets.only(left: 20.0), + // child: Row( + // children: [ + // Container( + // child: Icon( + // Icons.search, + // size: 24, + // color: Colors.blue, + // ), + // ), + // Container( + // child: Text( + // S.of(context).search_product, + // ), + // ), + // ], + // ), + // ), + // onTap: () { + // // Navigator.push(context, + // // MaterialPageRoute(builder: (BuildContext context) { + // // return ProductSearch(_business); + // // })); + // }, + // ), + BreadCrumb( + null, null, item: Container( - margin: EdgeInsets.only(left: 20.0), + width: 280.0, + padding: EdgeInsets.only(left: 20.0, right: 20.0), child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Container( - child: Icon( - Icons.search, - size: 24, - color: Colors.blue, + MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + child: Container( + padding: EdgeInsets.only(right: 10.0), + child: Icon( + searchIcon.icon, + size: 20.0, + color: Colors.blue, + ), + ), + onTap: () { + onSearchTap(); + }, ), ), - Container( - child: Text( - S.of(context).search_product, + Expanded(child: searchFieldPlaceHolder == null ? MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + child: Text( + S.of(context).search_products, + style: new TextStyle(color: Colors.blue), + ), + onTap: () { + onSearchTap(); + }, ), - ), + ) : searchFieldPlaceHolder), ], ), ), - onTap: () { - Navigator.push(context, - MaterialPageRoute(builder: (BuildContext context) { - return StoreProductSearch(_business); - })); - }, - ), + ) ], breadCrumbHeight: Constants.BREADCRUMB_HEIGHT, - shoppingCart: DesktopShoppingCartWidget( + shoppingCart: ShoppingCartWidget( business: _business, onTap: () { if (panelController.isPanelClosed) { @@ -573,21 +685,20 @@ class DesktopShopState extends State stack.children.addAll(children); if (!_business.isPublic) { - /* todo */ - // stack.children.add( - // Positioned( - // top: 0, - // right: 0, - // left: screenWidth - 100, - // bottom: screenHeight - 100, - // child: Image.asset( - // 'assets/images/under_renovation.png', - // width: 200.0, - // height: 200.0, - // fit: BoxFit.fill, - // ), - // ), - // ); + stack.children.add( + Positioned( + top: 0, + right: 0, + left: screenWidth - 100, + bottom: screenHeight - 100, + child: Image.asset( + 'assets/images/under_renovation.png', + width: 200.0, + height: 200.0, + fit: BoxFit.fill, + ), + ), + ); } return stack; @@ -626,7 +737,7 @@ class DesktopShopState extends State cancelButton: CupertinoActionSheetAction( child: Text(S.of(context).close), onPressed: () { - Navigator.of(context).pop(); + Navigator.of(context).maybePop(); }, ), ); @@ -872,8 +983,8 @@ class DesktopShopState extends State )); var duration = Duration( seconds: (_business.distanceInfo.duration != null - ? _business.distanceInfo.duration.value - : 30) + + ? _business.distanceInfo.duration.value + : 30) + _business.shippingTime * 60); var hours = duration.inHours.remainder(60); var minutes = duration.inMinutes.remainder(60); @@ -1008,28 +1119,28 @@ class DesktopShopState extends State children: [ _business.bulletin.isNotEmpty ? Row( crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( + children: [ + Container( padding: - EdgeInsets.only(left: 10.0, right: 5.0, bottom: 10.0), + EdgeInsets.only(left: 10.0, right: 5.0, bottom: 10.0), child: Icon( Icons.announcement, size: 14.0, color: Colors.white, )), - Container( - width: mediaQuery.size.width - 30.0, - padding: EdgeInsets.only(right: 10.0, bottom: 10.0), - child: new Text( - _business.bulletin.isEmpty ? '' : _business.bulletin, - softWrap: true, - style: new TextStyle( - fontSize: 12.0, color: const Color(0xFFDDDDDD)), + Container( + width: mediaQuery.size.width - 30.0, + padding: EdgeInsets.only(right: 10.0, bottom: 10.0), + child: new Text( + _business.bulletin.isEmpty ? '' : _business.bulletin, + softWrap: true, + style: new TextStyle( + fontSize: 12.0, color: const Color(0xFFDDDDDD)), // overflow: TextOverflow.ellipsis, - ), ), - ], - ) : SizedBox.shrink(), + ), + ], + ) : SizedBox.shrink(), _business.description.isNotEmpty ? Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, @@ -1276,7 +1387,7 @@ class DesktopShopState extends State height: 70.0, padding: new EdgeInsets.symmetric(horizontal: 10.0), decoration: new BoxDecoration( - color: _categoryIndex == i ? Style.backgroundColor : null, + color: _categoryIndex == i ? Colors.white : null, border: new Border( bottom: new BorderSide(color: new Color(0xFFEBEBEB)))), @@ -1309,10 +1420,10 @@ class DesktopShopState extends State _categoryIndexChange = true; _listScrollController1 .animateTo(height, - duration: new Duration( - microseconds: 200, - ), - curve: Curves.linear) + duration: new Duration( + microseconds: 200, + ), + curve: Curves.linear) .then((value) { _categoryIndexChange = false; }); @@ -1522,10 +1633,11 @@ class DesktopShopState extends State if (it.moveNext()) { r1.children.add( Container( - width: (mainSpace - 200) / c, + width: (mainSpace - 200) / c - 4.0, + margin: EdgeInsets.only(top: 2.0, bottom: 2.0, left: 2.0, right: 2.0), child: ProductItem( - product: it.current, - business: _business, + it.current, + _business, ), ), ); @@ -1656,128 +1768,6 @@ class DesktopShopState extends State } }); - // onProductWillAddToCartSubscription = - // eventBus.on().listen((event) { - // if (mounted) { - // - // CartInfo cartInfo = - // Utils.getCartInfoByBusiness(store.state.cartInfos, event.business); - // - // if (cartInfo == null || cartInfo.productList.length == 0) { - // cartInfo = CartInfo(); - // cartInfo.id = 0; - // cartInfo.amountPaid = 0.0; - // cartInfo.businessInfo = event.business; - // cartInfo.extraFeeList = []; - // cartInfo.discountList = []; - // CartLineItem lineItem = _newCartLineItem( - // id: 0, - // price: event.price, - // product: event.product, - // name: event.product.name, - // description: event.description, - // quantity: 1.0); - // cartInfo.productList = [lineItem]; - // store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList( - // store.state.cartInfos, cartInfo))); - // eventBus.fire(new OnCartInfoUpdated()); - // } else { - // if (event.product.productAttributes.length > 0) { - // CartLineItem lineItem = _newCartLineItem( - // id: 0, - // price: event.price, - // product: event.product, - // name: event.product.name, - // description: event.description, - // quantity: 1.0); - // cartInfo.productList.add(lineItem); - // store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList( - // store.state.cartInfos, cartInfo))); - // eventBus.fire(new OnCartInfoUpdated()); - // } else { - // int found = -1; - // for (var i = 0; i < cartInfo.productList.length; i++) { - // if (event.product.id == cartInfo.productList[i].product.id) { - // found = i; - // break; - // } - // } - // if (found == -1) { - // CartLineItem lineItem = _newCartLineItem( - // id: 0, - // price: event.price, - // product: event.product, - // name: event.product.name, - // description: event.description, - // quantity: 1.0); - // cartInfo.productList.add(lineItem); - // store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList( - // store.state.cartInfos, cartInfo))); - // eventBus.fire(new OnCartInfoUpdated()); - // } else { - // if (cartInfo.productList[found].quantity + 1.0 > - // event.product.leftNum) { - // Fluttertoast.showToast( - // msg: S.of(context).product_insufficient, - // toastLength: Toast.LENGTH_SHORT, - // gravity: ToastGravity.CENTER, - // backgroundColor: Colors.red, - // textColor: Colors.white); - // } else { - // cartInfo.productList[found].quantity += 1; - // store.dispatch(new UpdateCartInfo( - // Utils.addCartInfoToCartInfoList( - // store.state.cartInfos, cartInfo))); - // eventBus.fire(new OnCartInfoUpdated()); - // } - // } - // } - // } - // } - // }); - // onProductWillRemoveFromCartSubscription = - // eventBus.on().listen((event) { - // if (mounted) { - // CartInfo cartInfo = - // Utils.getCartInfoByBusiness(store.state.cartInfos, event.business); - // if (cartInfo != null) { - // if (cartInfo.productList.length > 0) { - // if (event.productListIndex != -1) { - // if (cartInfo.productList[event.productListIndex].quantity <= 1) { - // cartInfo.productList.removeAt(event.productListIndex); - // } else { - // cartInfo.productList[event.productListIndex].quantity -= 1; - // } - // } else { - // int productListIndex = -1; - // for (var i = 0; i < cartInfo.productList.length; i++) { - // if (cartInfo.productList[i].product.id == event.product.id) { - // productListIndex = i; - // break; - // } - // } - // if (productListIndex != -1) { - // if (cartInfo.productList[productListIndex].quantity <= 1) { - // cartInfo.productList.removeAt(productListIndex); - // } else { - // cartInfo.productList[productListIndex].quantity -= 1; - // } - // } - // } - // } - // - // if (cartInfo.productList.length <= 0) { - // store.dispatch(UpdateCartInfo(Utils.removeCartInfoFromCartInfoList( - // store.state.cartInfos, cartInfo))); - // } else { - // store.dispatch(UpdateCartInfo(Utils.addCartInfoToCartInfoList( - // store.state.cartInfos, cartInfo))); - // } - // eventBus.fire(new OnCartInfoUpdated()); - // } - // } - // }); - loadProducts(); } @@ -1792,68 +1782,80 @@ class DesktopShopState extends State lastProductListScrollPositionPixel = 0; _productCurrentPage = 1; Utils.loadProducts( - widget.businessId, categoryId, _productCurrentPage, false, - (value) { - if (_isLoading) { - _isLoading = false; - Navigator.of(context).pop(); - } - if (mounted) { - setState(() { - displayProductByCategoryClick = - value['display_product_by_category_click']; - displayProductByCategoryClickIndicator = ''; - _business = Business.fromJson(value['business']); - _categoryProducts = (value['category_products'] as List) - .map((i) => CategoryProducts.fromJson(i)) - .toList(); + widget.businessId, categoryId, _productCurrentPage, false, + (value) { + if (_isLoading) { + _isLoading = false; + Navigator.of(context).pop(); + } + if (mounted) { + setState(() { - _featuredProducts = (value['featured_products'] as List) - .map((i) => Product.fromJson(i)) - .toList(); - _hotSaleProducts = (value['hot_sale_products'] as List) - .map((i) => Product.fromJson(i)) - .toList(); - _prompts = value['prompt'] as List; + _isSearching = false; - if (_hotSaleProducts.length > 0) { - CategoryProducts hs = CategoryProducts( - Constants.HOT_SALE_ID, - widget.businessId, - S.of(context).hot_sale, - '', - '', - _hotSaleProducts); - _categoryProducts.insert(0, hs); - } + if (_searchController.text.isEmpty) { + responseData = value; + } + displayProductByCategoryClick = + value['display_product_by_category_click']; + displayProductByCategoryClickIndicator = ''; + _business = Business.fromJson(value['business']); + _categoryProducts = (value['category_products'] as List) + .map((i) => CategoryProducts.fromJson(i)) + .toList(); - if (_featuredProducts.length > 0) { - CategoryProducts fe = CategoryProducts( - Constants.FEATURED_PRODUCT_ID, - widget.businessId, - S.of(context).featured_product, - '', - '', - _featuredProducts); - _categoryProducts.insert(0, fe); - } + // _featuredProducts = (value['featured_products'] as List) + // .map((i) => Product.fromJson(i)) + // .toList(); + // _hotSaleProducts = (value['hot_sale_products'] as List) + // .map((i) => Product.fromJson(i)) + // .toList(); + _featuredProducts = []; + _hotSaleProducts = []; + _prompts = value['prompt'] as List; - checkActionAndClose(context); + if (_hotSaleProducts.length > 0) { + CategoryProducts hs = CategoryProducts( + Constants.HOT_SALE_ID, + widget.businessId, + S.of(context).hot_sale, + '', + '', + _hotSaleProducts); + _categoryProducts.insert(0, hs); + } - if (displayProductByCategoryClick) { - _resetProductListScroll(); - } - }); - } - }, - (error) { - print('error: $error'); - if (_isLoading) { - _isLoading = false; - Navigator.of(context).pop(); - } - Utils.showMessageDialog(context, error); - } + if (_featuredProducts.length > 0) { + CategoryProducts fe = CategoryProducts( + Constants.FEATURED_PRODUCT_ID, + widget.businessId, + S.of(context).featured_product, + '', + '', + _featuredProducts); + _categoryProducts.insert(0, fe); + } + + checkActionAndClose(context); + + if (displayProductByCategoryClick) { + _resetProductListScroll(); + } + }); + } + }, + (error) { + print('error: $error'); + _isSearching = false; + if (_isLoading) { + _isLoading = false; + Navigator.of(context).maybePop(); + } + if (mounted) { + setState(() {}); + } + Utils.showMessageDialog(context, error); + }, featuredCount: 5, hotSaleCount: 0, keyword: _searchController.text ); } @@ -1863,59 +1865,59 @@ class DesktopShopState extends State } _productCurrentPage += 1; Utils.loadProducts(widget.businessId, categoryId, _productCurrentPage, true, - (value) { - if (_isLoading) { - _isLoading = false; - Navigator.of(context).pop(); - } - if (mounted) { - setState(() { - List moreCategoryProducts = - (value as List).map((i) => CategoryProducts.fromJson(i)).toList(); - if (moreCategoryProducts.isEmpty) { - _productCurrentPage = 0; - displayProductByCategoryClickIndicator = - S.of(context).end_of_the_list; - } else { - if (moreCategoryProducts[0].products.length < Constants.ORDERS_PER_PAGE) { + (value) { + if (_isLoading) { + _isLoading = false; + Navigator.of(context).maybePop(); + } + if (mounted) { + setState(() { + List moreCategoryProducts = + (value as List).map((i) => CategoryProducts.fromJson(i)).toList(); + if (moreCategoryProducts.isEmpty) { _productCurrentPage = 0; displayProductByCategoryClickIndicator = S.of(context).end_of_the_list; } else { - displayProductByCategoryClickIndicator = - S.of(context).pull_up_to_load_more; + if (moreCategoryProducts[0].products.length < Constants.ORDERS_PER_PAGE) { + _productCurrentPage = 0; + displayProductByCategoryClickIndicator = + S.of(context).end_of_the_list; + } else { + displayProductByCategoryClickIndicator = + S.of(context).pull_up_to_load_more; + } + CategoryProducts currentCp = + getCategoryProductByCategoryId(categoryId); + if (currentCp != null) { + currentCp.products.addAll(moreCategoryProducts[0].products); + } else { + _productCurrentPage = 0; + displayProductByCategoryClickIndicator = + S.of(context).end_of_the_list; + } } - CategoryProducts currentCp = - getCategoryProductByCategoryId(categoryId); - if (currentCp != null) { - currentCp.products.addAll(moreCategoryProducts[0].products); - } else { - _productCurrentPage = 0; - displayProductByCategoryClickIndicator = - S.of(context).end_of_the_list; - } - } - }); - } - }, - (error) { - print('error: $error'); - if (_isLoading) { - _isLoading = false; - Navigator.of(context).pop(); - } - Utils.showMessageDialog(context, error); - } + }); + } + }, + (error) { + print('error: $error'); + if (_isLoading) { + _isLoading = false; + Navigator.of(context).maybePop(); + } + Utils.showMessageDialog(context, error); + }, keyword: _searchController.text ); } CartLineItem _newCartLineItem( {int id, - double price, - Product product, - String name, - String description, - double quantity}) { + double price, + Product product, + String name, + String description, + double quantity}) { CartLineItem lineItem = CartLineItem(); lineItem.unitPrice = price; lineItem.product = product; @@ -2087,10 +2089,10 @@ class DesktopShopState extends State S.of(context).store_closed, ), actions: [ - FlatButton( + TextButton( child: Text(S.of(context).ok), onPressed: () { - Navigator.of(context).pop(); + Navigator.of(context).maybePop(); showPrompt(0); }, ) @@ -2143,10 +2145,10 @@ class DesktopShopState extends State ), ), actions: [ - FlatButton( + TextButton( child: Text(S.of(context).ok), onPressed: () { - Navigator.of(context).pop(); + Navigator.of(context).maybePop(); showPrompt(0); }, ) @@ -2169,7 +2171,7 @@ class DesktopShopState extends State title: Text(_prompt['title']), content: Text(_prompt['message']), actions: [ - FlatButton( + TextButton( child: Text(S.of(context).ok), onPressed: () { Navigator.of(context).pop(); @@ -2184,6 +2186,158 @@ class DesktopShopState extends State @override bool get wantKeepAlive => true; + + void onSearchTap() { + setState(() { + if (searchIcon.icon == Icons.search) { + searchIcon = new Icon( + Icons.close, + color: Colors.white, + ); + if (displayProductByCategoryClick) { + searchFieldPlaceHolder = Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: + TextField( + controller: _searchController, + textInputAction: TextInputAction.search, + onSubmitted: (value) { + onSearchButtonTap(); + }, + style: TextStyle( + color: Colors.black87, + ), + decoration: new InputDecoration( + hintText: S + .of(context) + .enter_keyword, + hintStyle: TextStyle(color: Colors.black26)), + onChanged: searchOperation, + ), + ), + SizedBox(width: 5,), + ElevatedButton.icon( + style: ElevatedButton.styleFrom( + primary: Colors.redAccent, + onPrimary: Colors.white, + padding: EdgeInsets.only(left: 5, right: 5, top: 5, bottom: 5), + elevation: 2.0, + shape: new RoundedRectangleBorder( + borderRadius: new BorderRadius.circular(5.0), + ), + ), + onPressed: onSearchButtonTap, + icon: Icon( + Icons.search, + size: 16, + color: Colors.green, + ), + label: Text( + S.of(context).search, + style: TextStyle( + color: Colors.green, + ), + ), + ), + ], + ); + } else { + searchFieldPlaceHolder = TextField( + controller: _searchController, + style: TextStyle( + color: Colors.black87, + ), + decoration: new InputDecoration( + hintText: S + .of(context) + .enter_keyword, + hintStyle: TextStyle(color: Colors.black26)), + onChanged: searchOperation, + ); + _handleSearchStart(); + } + } else { + _handleSearchEnd(); + } + }); + } + + void _handleSearchStart() { + setState(() { + _isSearching = true; + }); + } + + void _handleSearchEnd() { + setState(() { + searchIcon = new Icon( + Icons.search, + color: Colors.blue, + ); + searchFieldPlaceHolder = MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + child: Text( + S.of(context).search_products, + style: new TextStyle(color: Colors.blue), + ), + onTap: () { + onSearchTap(); + }, + ), + ); + _isSearching = false; + _searchController.clear(); + if (displayProductByCategoryClick) { + categoryId = 0; + loadProducts(); + } + }); + } + + void searchOperation(String searchText) { + if (displayProductByCategoryClick) { + + } else { + if (responseData != null) { + _categoryProducts.clear(); + List cps = (responseData['category_products'] as List) + .map((i) { + CategoryProducts cp = CategoryProducts.fromJson(i); + List ps = []; + for (Product p in cp.products) { + if (p.name.toLowerCase().contains(searchText.toLowerCase()) || + p.description.toLowerCase().contains(searchText.toLowerCase()) || + (p.detailDescription != null && p.detailDescription.toLowerCase().contains(searchText.toLowerCase()))) { + ps.add(p); + } + } + if (ps.length > 0) { + cp.products = ps; + return cp; + } + }).toList(); + for (CategoryProducts cp in cps) { + if (cp != null) { + _categoryProducts.add(cp); + } + } + print('$searchText, count: ${_categoryProducts.length}'); + setState(() {}); + } + } + } + + void onSearchButtonTap() { + String kw = _searchController.text; + if (kw.isNotEmpty) { + _handleSearchStart(); + loadProducts(); + } + } } class _SliverAppBarDelegate2 extends SliverPersistentHeaderDelegate { diff --git a/lib/widgets/desktop/shop_bulletin.dart b/lib/widgets/desktop/shop_bulletin.dart new file mode 100644 index 0000000..33a4f3e --- /dev/null +++ b/lib/widgets/desktop/shop_bulletin.dart @@ -0,0 +1,70 @@ + + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import '../../models/business.dart'; + +class ShopBulletin extends StatefulWidget { + final Business business; + + const ShopBulletin(this.business, {Key key}): super(key: key); + + @override + State createState() => ShopBulletinState(); + +} + +class ShopBulletinState 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; + } + + if (widget.business.bulletin != null && widget.business.bulletin.isNotEmpty) { + return Container( + margin: EdgeInsets.only(bottom: 12), + child: Row( + children: [ + Container( + width: sideSpace, + ), + Expanded( + child: Container( + padding: EdgeInsets.only(top: 10, left: 16.0, right: 16.0, bottom: 10.0), + child: Text( + '${widget.business.bulletin}', + overflow: TextOverflow.ellipsis, + maxLines: 3, + style: TextStyle( + color: Colors.white, + ), + ), + decoration: BoxDecoration( + color: Colors.orangeAccent, + border: Border.all( + color: Colors.red[500], + width: 1.0, + ), + borderRadius: BorderRadius.all(Radius.circular(16)), + ), + ), + ), + Container( + width: sideSpace, + ), + ], + ), + ); + } + return SizedBox.shrink(); + } + +} \ No newline at end of file diff --git a/lib/widgets/desktop/shop_products.dart b/lib/widgets/desktop/shop_products.dart new file mode 100644 index 0000000..d6a6916 --- /dev/null +++ b/lib/widgets/desktop/shop_products.dart @@ -0,0 +1,431 @@ + +import 'package:badges/badges.dart'; +import 'package:flutter/material.dart'; + +import '../../constants.dart'; +import '../../events/eventbus.dart'; +import '../../events/events.dart'; +import '../../generated/l10n.dart'; +import '../../models/business.dart'; +import '../../models/cart_info.dart'; +import '../../models/category_products.dart'; +import '../../store/store.dart'; +import '../../utils/utils.dart'; +import '../../widgets/desktop/product_item.dart'; + +class ShopProducts extends StatefulWidget { + final dynamic data; + + const ShopProducts(this.data, {Key key}): super(key: key); + + @override + State createState() => ShopProductsState(); +} + +class ShopProductsState extends State { + double sideSpace = 0; + double mainSpace = 1200; + + dynamic data; + + static const num _categoryHeight = 50.0; + static const num _categoryDescHeight = 50.0; + static const num _productHeight = 266.0; + + bool displayProductByCategoryClick = false; + String displayProductByCategoryClickIndicator = ''; + int categoryId = 0; + double leftSideMenuWidth = 0; + + int _categoryIndex = 0; + List _categoryProducts = []; + Business _business; + + double menuPosition = 0; + + ScrollController _menuScrollController = ScrollController(); + + @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 Container( + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: sideSpace, + ), + Expanded( + child: Container( + child: + // Row( + // mainAxisAlignment: MainAxisAlignment.start, + // crossAxisAlignment: CrossAxisAlignment.start, + // mainAxisSize: MainAxisSize.min, + // children: [ + // _buildCategories(), + // Expanded( + // child: _buildProducts(), + // ), + // ], + // ), + IntrinsicHeight( + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: [ + _buildCategories(), + Expanded( + child: _buildProducts(), + ), + ], + ), + ), + ), + ), + Container( + width: sideSpace, + ), + ], + ), + ); + } + + Widget _buildCategories() { + return new Container( + width: leftSideMenuWidth, + height: 500, + color: new Color(0xFFF5F5F5), + child: new SizedBox.expand( + child: ListView.builder( + physics: ClampingScrollPhysics(), + controller: _menuScrollController, + itemCount: _categoryProducts == null ? 0 : _categoryProducts.length, + itemBuilder: (BuildContext context, int i) { + CategoryProducts cp = _categoryProducts[i]; + int qtyInCategory = 0; + CartInfo cartInfo = Utils.getCartInfoByBusiness(store.state.cartInfos, _business); + if (cartInfo != null && + cartInfo.businessInfo.id == _business.id && + cartInfo.productList != null) { + for (var i = 0; i < cartInfo.productList.length; i++) { + if (cartInfo.productList[i].product.categoryId == cp.id) { + qtyInCategory += cartInfo.productList[i].quantity.ceil(); + } + } + } + Row categoryRow = Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [], + ); + categoryRow.children.add( + Expanded( + flex: 1, + child: Container( + margin: EdgeInsets.only(top: 5.0, bottom: 5.0), + child: Text( + cp.name, + style: TextStyle( + fontSize: 13.0, + fontWeight: (cp.id == Constants.FEATURED_PRODUCT_ID || + cp.id == Constants.HOT_SALE_ID) + ? FontWeight.bold + : FontWeight.normal, + color: (cp.id == Constants.HOT_SALE_ID) + ? Colors.redAccent + : ((cp.id == Constants.FEATURED_PRODUCT_ID) + ? Colors.lightGreen + : Colors.black87)), +// overflow: kIsWeb ? null : TextOverflow.ellipsis, + overflow: TextOverflow.ellipsis, + softWrap: true, + maxLines: 2, + ), + ), + ), + ); + if (qtyInCategory > 0) { + categoryRow.children.add( + Badge( + badgeContent: Text( + '$qtyInCategory', + style: TextStyle( + color: Colors.white, + fontSize: 11.0, + ), + ), + animationType: BadgeAnimationType.scale, + ), + ); + } else { + categoryRow.children.add(SizedBox.shrink()); + } + return GestureDetector( + child: new Container( + height: 70.0, + padding: new EdgeInsets.symmetric(horizontal: 10.0), + decoration: new BoxDecoration( + color: cp.id == categoryId ? Colors.white : null, + border: new Border( + bottom: + new BorderSide(color: new Color(0xFFEBEBEB)))), + child: categoryRow, + ), + onTap: () => _selectCategory(cp.id), + ); + } + ), + ), + ); + } + + void _selectCategory(int i) { + categoryId = i; + eventBus.fire(CategoryChangeEvent(i)); + } + + Widget _buildProducts() { + if (_categoryProducts == null) { + return SizedBox.shrink(); + } + Column col = new Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [], + ); + for (int i = 0; i < _categoryProducts.length; i++) { + CategoryProducts cp = _categoryProducts[i]; + if (cp.products.length > 0) { + col.children.add(new Container( + height: _categoryDescHeight, + padding: new EdgeInsets.symmetric(horizontal: 10.0), + color: new Color(0xFFF5F5F5), + child: new Row( + children: [ + new Expanded( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + textBaseline: TextBaseline.alphabetic, + children: [ + new Padding( + padding: new EdgeInsets.only(right: 5.0), + child: new Text( + cp.name, + style: new TextStyle( + fontSize: 16.0, + fontWeight: + (cp.id == Constants.FEATURED_PRODUCT_ID || + cp.id == Constants.HOT_SALE_ID) + ? FontWeight.bold + : FontWeight.normal, + color: (cp.id == Constants.HOT_SALE_ID) + ? Colors.redAccent + : ((cp.id == + Constants.FEATURED_PRODUCT_ID) + ? Colors.lightGreen + : Colors.black87)), + overflow: TextOverflow.ellipsis, + ), + ), + new Visibility( + visible: cp.description.isNotEmpty, + child: new Text( + cp.description, + overflow: TextOverflow.ellipsis, + style: new TextStyle( + fontSize: 10.0, + color: new Color(0xFF999999)), + ), + replacement: const SizedBox.shrink()), + ], + )) + ], + ))); + + var it = cp.products.iterator; + for (int i = 0; i < cp.products.length; i++) { + var r1 = Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [], + ); + double d = getProductCountInRow(); + int c = int.parse(d.toString()); + while (d > 0) { + if (it.moveNext()) { + r1.children.add( + Container( + width: (mainSpace - leftSideMenuWidth) / c - 4.0, + margin: EdgeInsets.only(top: 2.0, bottom: 2.0, left: 2.0, right: 2.0), + child: ProductItem( + it.current, + _business, + ), + ), + ); + } + d -= 1; + } + col.children.add(r1); + } + + if (displayProductByCategoryClick) { + if (displayProductByCategoryClickIndicator.isNotEmpty) { + col.children.add( + Container( + padding: EdgeInsets.all(12.0), + child: Center( + child: Text( + displayProductByCategoryClickIndicator, + style: TextStyle( + color: Colors.black54, + ), + ), + ), + ), + ); + } else if (categoryId > 0) { + if (cp.products.length < Constants.ORDERS_PER_PAGE) { + col.children.add( + Container( + padding: EdgeInsets.all(12.0), + child: Center( + child: Text( + S + .of(context) + .end_of_the_list, + style: TextStyle( + color: Colors.black54, + ), + ), + ), + ), + ); + } else { + col.children.add( + Container( + padding: EdgeInsets.all(12.0), + child: Center( + child: Text( + S + .of(context) + .pull_up_to_load_more, + style: TextStyle( + color: Colors.black54, + ), + ), + ), + ), + ); + } + } + } + } + } + return col; + } + + void loadData() { + // _categoryProducts .clear(); + _categoryProducts = (data['category_products'] as List) + .map((i) => CategoryProducts.fromJson(i)) + .toList(); + _business = Business.fromJson(data['business']); + displayProductByCategoryClick = data['display_product_by_category_click']; + if (displayProductByCategoryClick) { + leftSideMenuWidth = 200; + } + displayProductByCategoryClickIndicator = ''; + if (categoryId == 0 && displayProductByCategoryClick) { + categoryId = _categoryProducts[0].id; + } + setState(() { + + }); + } + + @override + void initState() { + super.initState(); + data = widget.data; + loadData(); + eventBus.on().listen((event) { + if (mounted) { + data = event.data; + loadData(); + } + }); + eventBus.on().listen((event) { + if (mounted) { + setState(() { + List moreCategoryProducts = event.data; + if (moreCategoryProducts.isEmpty) { + displayProductByCategoryClickIndicator = S + .of(context) + .end_of_the_list; + } else { + if (moreCategoryProducts[0].products.length < + Constants.ORDERS_PER_PAGE) { + displayProductByCategoryClickIndicator = S + .of(context) + .end_of_the_list; + } else { + displayProductByCategoryClickIndicator = + S + .of(context) + .pull_up_to_load_more; + } + CategoryProducts currentCp = + getCategoryProductByCategoryId(categoryId); + if (currentCp != null) { + currentCp.products.addAll(moreCategoryProducts[0].products); + } else { + displayProductByCategoryClickIndicator = S + .of(context) + .end_of_the_list; + } + } + }); + } + }); + } + + int numCategoriesHasProducts() { + int num = 0; + for (CategoryProducts cp in _categoryProducts) { + if (cp.products.length > 0) { + num += 1; + } + } + return num; + } + + CategoryProducts getCategoryProductByCategoryId(int cid) { + for (CategoryProducts cp in _categoryProducts) { + if (cp.id == cid) { + return cp; + } + } + return null; + } + + double getProductCountInRow() { + double d = 2; + if (mainSpace >= 800 && mainSpace < 1000) { + d = 3; + } else if (mainSpace >= 1000) { + d = 4; + } + return d; + } +} \ No newline at end of file diff --git a/lib/widgets/desktop/shop_promote.dart b/lib/widgets/desktop/shop_promote.dart new file mode 100644 index 0000000..e3bf2c9 --- /dev/null +++ b/lib/widgets/desktop/shop_promote.dart @@ -0,0 +1,185 @@ + +import 'package:flutter/material.dart'; +import '../../generated/l10n.dart'; +import '../../pages/product_detail_page.dart'; +import '../../widgets/general/add_remove_button.dart'; +import '../../widgets/general/show_price.dart'; + +import '../../models/business.dart'; +import '../../models/product.dart'; +import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart'; + +class ShopPromote extends StatefulWidget { + final dynamic data; + + const ShopPromote(this.data, {Key key}): super(key: key); + + @override + State createState() => ShopPromoteState(); +} + +class ShopPromoteState extends State { + double sideSpace = 0; + double mainSpace = 1200; + + Business _business; + + @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; + } + + Row promoteRow = getPromoteRow(); + if (promoteRow.children.length > 0) { + return Container( + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: sideSpace, + ), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.only(top: 12, bottom: 6), + child: Text( + S.of(context).promotions, + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + ), + Container( + padding: EdgeInsets.only(bottom: 10), + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: promoteRow, + ), + ), + ], + ), + ), + Container( + width: sideSpace, + ), + ], + ), + ); + } else { + return SizedBox.shrink(); + } + } + + @override + void initState() { + super.initState(); + _business = Business.fromJson(widget.data['business']); + } + + Row getPromoteRow() { + Row promotRow = Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [], + ); + for (var i = 0; i < _business.promoProducts.length; i++) { + promotRow.children.add(Container( + padding: EdgeInsets.only( + left: 10.0, + top: 10.0, + bottom: 10.0, + right: 10.0, + ), + margin: EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0), + width: 220.0, + height: 220.0, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(5.0)), + color: Colors.white, + border: Border( + top: BorderSide( + width: 1.0, + color: Colors.black12, + ), + bottom: BorderSide( + width: 1.0, + color: Colors.black12, + ), + left: BorderSide( + width: 1.0, + color: Colors.black12, + ), + right: BorderSide( + width: 1.0, + color: Colors.black12, + ), + ), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + GestureDetector( + child: Container( + child: Util.showImage( + _business.promoProducts[i].imagePath, + width: 120.0, + ), + ), + onTap: () { + _showProductDetail(_business.promoProducts[i]); + }, + ), + Container( + child: Text( + _business.promoProducts[i].name, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 14.0), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ShowPrice( + _business.promoProducts[i].price, + currencySign: '\$', + fontWeight: FontWeight.bold, + smallFontSize: 15, + largeFontSize: 24, + regularPrice: _business.promoProducts[i].regularPrice, + ), + Container( + child: AddRemoveButton( + product: _business.promoProducts[i], + business: _business, + addOnly: true, + ), + ) + ], + ) + ], + ), + )); + } + return promotRow; + } + + void _showProductDetail(Product p) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ProductDetailPage( + product: p, + business: _business, + )), + ); + } +} \ No newline at end of file diff --git a/lib/widgets/desktop/shopping_cart_widget.dart b/lib/widgets/desktop/shopping_cart_widget.dart new file mode 100644 index 0000000..739a918 --- /dev/null +++ b/lib/widgets/desktop/shopping_cart_widget.dart @@ -0,0 +1,79 @@ + +import 'package:flutter/material.dart'; + +import '../../events/eventbus.dart'; +import '../../events/events.dart'; +import '../../models/business.dart'; +import '../../models/cart_info.dart'; +import '../../store/store.dart'; +import '../../utils/utils.dart'; + +class ShoppingCartWidget extends StatefulWidget { + final Business business; + final Function onTap; + + ShoppingCartWidget({@required this.business, this.onTap}); + + @override + State createState() => ShoppingCartWidgetState(); +} + +class ShoppingCartWidgetState extends State { + CartInfo cartInfo; + double totalPrice = 0.0; + + @override + Widget build(BuildContext context) { + totalPrice = 0.0; + cartInfo = Utils.getCartInfoByBusiness(store.state.cartInfos, widget.business); + if (cartInfo != null && cartInfo.businessInfo.id == widget.business.id) { + totalPrice = cartInfo.getTotalPrice(); + } + Row row = Row( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + padding: EdgeInsets.only(left: 16.0, right: 4.0, top: 8.0), + child: Icon( + Icons.shopping_basket_outlined, + size: 24, + color: Colors.blue, + ), + ), + Container( + padding: EdgeInsets.only(left: 4.0, right: 16.0, top: 8.0), + child: Text( + '\$${totalPrice.toStringAsFixed(2)}', + style: TextStyle( + color: totalPrice > 0 ? Colors.red : Colors.black45, + fontWeight: totalPrice > 0 ? FontWeight.bold : FontWeight.normal, + ), + ), + ), + ], + ); + return MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + child: Container( + child: row, + width: 160.0, + ), + onTap: widget.onTap, + ), + ); + } + + @override + void initState() { + super.initState(); + eventBus.on().listen((event) { + if (mounted) { + setState(() { + + }); + } + }); + } +} \ No newline at end of file diff --git a/lib/widgets/general/breadcrumbs.dart b/lib/widgets/general/breadcrumbs.dart index 3ea5179..e45edcf 100644 --- a/lib/widgets/general/breadcrumbs.dart +++ b/lib/widgets/general/breadcrumbs.dart @@ -4,11 +4,13 @@ import 'package:flutter/rendering.dart'; import '../../generated/l10n.dart'; import '../../routes.dart'; +import 'navigationbar.dart'; class BreadCrumbs extends StatelessWidget { final List breadCrumbs; final bool hasBack; - const BreadCrumbs(this.hasBack, {this.breadCrumbs, Key key}) : super(key: key); + final OnBackPress onBackPress; + const BreadCrumbs(this.hasBack, {this.breadCrumbs, Key key, this.onBackPress}) : super(key: key); @override Widget build(BuildContext context) { @@ -39,8 +41,8 @@ class BreadCrumbs extends StatelessWidget { ), ], ), - onTap: () { - Routes.router.pop(context); + onTap: onBackPress != null ? onBackPress : () { + Navigator.of(context).maybePop(); }, ), ), @@ -72,7 +74,7 @@ class BreadCrumbs extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - padding: EdgeInsets.only(top: 0.0), + padding: EdgeInsets.only(top: 6.0, left: 4.0, right: 4.0), child: Icon( Icons.circle, size: 6.0, @@ -123,7 +125,7 @@ class BreadCrumbs extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - padding: EdgeInsets.only(top: 0.0), + padding: EdgeInsets.only(top: 6.0, left: 4.0, right: 4.0), child: Icon( Icons.circle, size: 6.0, diff --git a/lib/widgets/general/navigationbar.dart b/lib/widgets/general/navigationbar.dart index 9be5b98..7504fc9 100644 --- a/lib/widgets/general/navigationbar.dart +++ b/lib/widgets/general/navigationbar.dart @@ -6,7 +6,9 @@ import '../../widgets/desktop/desktop_navigationbar.dart'; import '../../widgets/mobile/mobile_navigationbar.dart'; import 'breadcrumbs.dart'; -class NavigationBar extends StatefulWidget implements PreferredSizeWidget { +typedef OnBackPress(); + +class MiniNavigationBar extends StatefulWidget implements PreferredSizeWidget { final Key key; final String title; final bool back; @@ -16,7 +18,7 @@ class NavigationBar extends StatefulWidget implements PreferredSizeWidget { final double breadCrumbHeight; final Widget shoppingCart; - NavigationBar({Key key, PreferredSizeWidget bottom, String title, + MiniNavigationBar({Key key, PreferredSizeWidget bottom, String title, bool back, bool toHome, bool showMe, this.breadCrumbs, this.breadCrumbHeight, this.shoppingCart}) : key = key, @@ -32,12 +34,12 @@ class NavigationBar extends StatefulWidget implements PreferredSizeWidget { @override State createState() { - return NavigationBarState(); + return MiniNavigationBarState(); } } -class NavigationBarState extends State { +class MiniNavigationBarState extends State { @override Widget build(BuildContext context) { diff --git a/lib/widgets/general/payment_verification_code_dialog.dart b/lib/widgets/general/payment_verification_code_dialog.dart index 1909e72..b6b2cac 100644 --- a/lib/widgets/general/payment_verification_code_dialog.dart +++ b/lib/widgets/general/payment_verification_code_dialog.dart @@ -33,6 +33,9 @@ class PaymentVerificationCodeDialogState extends State - ScreenTypeLayout( - mobile: MobileProductItem(product: product, business: business,), - tablet: DesktopProductItem(product: product, business: business,), - desktop: DesktopProductItem(product: product, business: business,), - ), - ); - } - -} \ No newline at end of file diff --git a/lib/widgets/general/text_link.dart b/lib/widgets/general/text_link.dart index 77b152b..4ebf529 100644 --- a/lib/widgets/general/text_link.dart +++ b/lib/widgets/general/text_link.dart @@ -3,6 +3,7 @@ import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_wisetronic/utils/utils.dart'; +import 'package:hovering/hovering.dart'; import 'package:url_launcher/url_launcher.dart'; import '../../routes.dart'; @@ -11,6 +12,7 @@ class TextLink extends StatelessWidget { final String title; final String url; final Color color; + final Color hoverColor; final double paddingHorizontal; final double paddingVertical; final FontWeight fontWeight; @@ -24,8 +26,14 @@ class TextLink extends StatelessWidget { final bool closeDrawer; final bool isEmail; final bool isPhone; + final double fontSize; + final bool isAddress; + final TextOverflow overflow; + final int maxLines; + TextLink(this.title, this.url, { this.color, + this.hoverColor, this.paddingHorizontal, this.paddingVertical, this.fontWeight, @@ -39,6 +47,10 @@ class TextLink extends StatelessWidget { bool closeDrawer, bool isEmail, bool isPhone, + double fontSize, + bool isAddress, + TextOverflow overflow, + int maxLines, }) : isLink = isLink ?? false, replace = replace ?? false, @@ -47,7 +59,11 @@ class TextLink extends StatelessWidget { rootNavigator = rootNavigator ?? false, closeDrawer = closeDrawer ?? false, isEmail = isEmail ?? false, - isPhone = isPhone ?? false; + isPhone = isPhone ?? false, + fontSize = fontSize ?? null, + isAddress = isAddress ?? false, + overflow = overflow ?? TextOverflow.ellipsis, + maxLines = maxLines ?? 1; @override Widget build(BuildContext context) { @@ -59,19 +75,37 @@ class TextLink extends StatelessWidget { vertical: paddingVertical ?? 0.0, horizontal: paddingHorizontal ?? 0.0 ), - child: Text( - title, - style: TextStyle( - color: color ?? Colors.blue, - fontWeight: fontWeight ?? FontWeight.normal, + child: HoverWidget( + child: Text( + title, + style: TextStyle( + color: color ?? Colors.blue, + fontWeight: fontWeight ?? FontWeight.normal, + fontSize: fontSize, + ), + overflow: overflow, + maxLines: maxLines, ), + hoverChild: Text( + title, + style: TextStyle( + color: hoverColor ?? Colors.grey, + fontSize: fontSize, + fontWeight: fontWeight ?? FontWeight.normal, + ), + overflow: overflow, + maxLines: maxLines, + ), + onHover: (event) { + + }, ), decoration: BoxDecoration( border: (selected != null && selected) ? Border( - bottom: BorderSide( - color: color ?? Colors.blue, - width: 3.0, - ) + bottom: BorderSide( + color: color ?? Colors.blue, + width: 3.0, + ) ) : null, ), ), @@ -81,6 +115,8 @@ class TextLink extends StatelessWidget { Utils.openEmail(url); } else if (isPhone) { Utils.callPhone(url); + } else if (isAddress) { + await launch('https://maps.google.com/?q=${url}'); } else if (!isLink) { if (closeDrawer) { Routes.router.pop(context); diff --git a/lib/widgets/mobile/create_online_store_1.dart b/lib/widgets/mobile/create_online_store_1.dart new file mode 100644 index 0000000..7225210 --- /dev/null +++ b/lib/widgets/mobile/create_online_store_1.dart @@ -0,0 +1,411 @@ + +import 'package:flutter/material.dart'; + +import '/models/group.dart'; +import '/pages/buy_service.dart'; +import '../../constants.dart'; +import '../../generated/l10n.dart'; +import '../../routes.dart'; +import '../../utils/http_util.dart'; +import '../../utils/utils.dart'; + +class CreateOnlineStore1 extends StatefulWidget { + final int businessId; + + const CreateOnlineStore1(this.businessId, {Key key}) : super(key: key); + + @override + State createState() { + return CreateOnlineStore1State(); + } + +} + +class CreateOnlineStore1State extends State { + + TextEditingController groupNumberController = TextEditingController(); + + TextEditingController domainController = TextEditingController(); + + bool canSubmit = false; + + List stores = []; + Map service; + dynamic selectedStore; + + Group group; + + String selectedDomain; + List domainResult = []; + + @override + Widget build(BuildContext context) { + Column col = Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [], + ); + + col.children.add( + Container( + padding: EdgeInsets.only(top: 20, left: 16, right: 16, bottom: 10,), + child: Text( + S.of(context).open_online_store, + style: TextStyle( + fontSize: 28, + ), + ), + ), + ); + col.children.add( + Container( + padding: EdgeInsets.only(top: 4, bottom: 4, left: 16.0, right: 16.0), + child: Text( + S.of(context) + .select_a_store, + style: TextStyle( + color: Colors.black45, + ), + ), + ), + ); + col.children.add( + Container( + padding: EdgeInsets.only(top: 4, bottom: 4, left: 16.0, right: 16.0), + child: DropdownButton( + items: stores.map((e) => DropdownMenuItem( + value: e, + child: Text(e['name']), + )).toList(), + isExpanded: false, + hint: Text(S.of(context).select_a_store), + onChanged: (newValue) { + print('newValue $newValue'); + setState(() { + selectedStore = newValue; + }); + }, + value: selectedStore, + ), + ), + ); + col.children.add( + Container( + padding: EdgeInsets.only( + left: 16.0, right: 16.0, top: 20, bottom: 20), + child: Visibility( + child: getSearchDomainWidget(), + visible: selectedStore != null, + ), + ), + ); + + return Scaffold( + appBar: AppBar( + leading: IconButton( + icon: Icon(Icons.arrow_back_ios), + onPressed: (){ + Navigator.of(context).pop(); + }, + ), + title: Text(S.of(context).open_online_store), + backgroundColor: Theme.of(context).primaryColor, + ), + body: SingleChildScrollView( + child: col, + ), + ); + } + + Widget getSearchDomainWidget() { + if (selectedStore == null) { + return SizedBox.shrink(); + } + Column col = Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [], + ); + col.children.add( + Container( + padding: EdgeInsets.only(bottom: 4,), + child: Text(selectedStore == null ? '' : selectedStore['name'], + style: TextStyle( + fontSize: 28, + ), + ), + ), + ); + Map existing_web_svc; + if (selectedStore != null && (selectedStore['services'] as List).length > 0) { + for (Mapsvc in (selectedStore['services'] as List)) { + if (svc['code'] == Constants.WEB_MINISTORE_SERVICE) { + existing_web_svc = svc; + break; + } + } + } + if (existing_web_svc != null) { + col.children.add( + Container( + padding: EdgeInsets.only(top: 8.0), + child: Text( + '${existing_web_svc['description']}', + ), + ), + ); + col.children.add( + Container( + padding: EdgeInsets.only(top: 4.0), + child: Text( + S.of(context).expiration_date + ": " + + Utils.utcDatetimeStringToLocalDatetimeString(context, existing_web_svc['expiration_date']), + ), + ), + ); + col.children.add( + Container( + padding: EdgeInsets.only(top: 4.0), + child: Text( + S.of(context).store + ": " + '${existing_web_svc['store']['name']}' + ), + ), + ); + col.children.add( + Container( + padding: EdgeInsets.only(top: 4.0), + child: Text( + S.of(context).domain_name + ": " + '${existing_web_svc['domain']}' + ), + ), + ); + col.children.add( + Container( + padding: EdgeInsets.only(top: 10.0), + child: ElevatedButton( + child: Text(S.of(context).renew_service_now), + onPressed: () { + Navigator.pushReplacement(context, MaterialPageRoute( + builder: (BuildContext context) => + BuyService(group.id, Constants.WEB_MINISTORE_SERVICE, + domain: existing_web_svc['domain'], + sid: existing_web_svc['store']['id'], + ), + )); + }, + ), + ), + ); + } else { + col.children.add( + Container( + padding: EdgeInsets.only(top: 8.0), + child: Text(S.of(context).enter_desired_domain), + ), + ); + col.children.add( + Container( + padding: EdgeInsets.only(top: 0,), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: TextFormField( + controller: domainController, + decoration: new InputDecoration( + enabledBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: Colors.black12, + ), + ), + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide( + color: Colors.blue, + ), + ), + labelText: S.of(context).domains_separated_comma, + ), + style: TextStyle( + fontSize: 18.0 + ), + autofocus: true, + validator: (String value) { + if (value.trim().isEmpty) { + return S.of(context).domains_separated_comma; + } + return null; + }, + onChanged: (string) { + if (string.isNotEmpty) { + canSubmit = true; + } else { + canSubmit = false; + } + setState(() {}); + }, + ), + ), + Container( + padding: EdgeInsets.only(left: 8.0), + child: ElevatedButton( + child: Text( + S.of(context).check_domain_name, + ), + onPressed: domainController.text.length > 0 ? checkDomainAvailability : null, + ), + ), + ], + ), + ) + ); + if (domainResult.length > 0) { + for (dynamic dr in domainResult) { + col.children.add(_getDomain(dr)); + } + } + if (selectedDomain != null && service != null) { + col.children.add( + Container( + padding: EdgeInsets.only(top: 8.0), + child: Text( + service['description'], + ), + ), + ); + col.children.add( + Container( + padding: EdgeInsets.only(top: 8.0), + child: Text( + service['options'][0]['name'], + ), + ), + ); + col.children.add( + Container( + padding: EdgeInsets.only(top: 8.0), + child: Text( + '\$${service['options'][0]['price']}', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.orange, + ), + ), + ), + ); + col.children.add( + Container( + padding: EdgeInsets.only(top: 10.0), + child: ElevatedButton( + child: Text( + S.of(context).place_order_now, + ), + onPressed: () { + Navigator.pushReplacement(context, MaterialPageRoute( + builder: (BuildContext context) => + BuyService(group.id, Constants.WEB_MINISTORE_SERVICE, + domain: selectedDomain, + sid: selectedStore['id'], + ), + )); + }, + ), + ), + ); + } + } + return Container( + padding: EdgeInsets.only(bottom: 4,), + child: col, + ); + } + + @override + void initState() { + super.initState(); + HttpUtil.httpGet( + 'v1/get-contact-stores', + queryParameters: { + 'service': Constants.WEB_MINISTORE_SERVICE + } + ).then((value) { + setState(() { + stores = value['stores']; + service = value['service']; + group = Group.fromJson(value['group']); + print('stores: ${value}'); + }); + }).onError((error, stackTrace) { + Utils.showMessageDialog(context, error, onOk: () { + Routes.router.navigateTo(context, '/'); + }); + }); + } + + Future checkDomainAvailability() async { + Utils.showLoadingDialog(context); + selectedDomain = null; + domainResult = []; + setState(() {}); + HttpUtil.httpGet( + 'v1/check-domain-availability', + queryParameters: { + 'domain': domainController.text, + }, + ).then((value) { + Routes.router.pop(context); + print('value: $value'); + if (value['status'] == 'OK') { + domainResult = (value['domain_check_result'] as List); + setState(() {}); + } else if (value['status'] == 'ERROR') { + String errors = ''; + for (int i = 0; i < (value['errors'] as List).length; i++) { + errors += value['errors'][i] + '\n'; + } + Utils.showMessageDialog(context, errors); + } + }).onError((error, stackTrace) { + Routes.router.pop(context); + Utils.showMessageDialog(context, error); + }); + } + + Widget _getDomain(dynamic d) { + if ((d['available'] as bool)) { + return Container( + child: ListTile( + title: Text( + d['domain'], + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + leading: Radio( + value: d['domain'], + groupValue: selectedDomain, + onChanged: (val) { + setState(() { + selectedDomain = val; + }); + }, + ), + ), + ); + } else { + return Container( + padding: EdgeInsets.only(top: 1.0), + child: ListTile( + title: Text( + d['domain'], + style: TextStyle( + color: Colors.black45, + ), + ), + leading: Icon(Icons.clear, color: Colors.red,), + ), + ); + } + } +} \ No newline at end of file diff --git a/lib/widgets/mobile/mobile_buy_service.dart b/lib/widgets/mobile/mobile_buy_service.dart index 4e0b587..3e77711 100644 --- a/lib/widgets/mobile/mobile_buy_service.dart +++ b/lib/widgets/mobile/mobile_buy_service.dart @@ -52,6 +52,18 @@ class MobileBuyServiceState extends State { Utils.buildLine(S.of(context).your_group, widget.data['group']['name'], valueSize: 16), ); + if (widget.data['store']['id'] != null) { + col1.children.add( + Utils.buildLine(S.of(context).store, widget.data['store']['name'], valueSize: 16), + ); + } + + if (widget.data['domain'] != null) { + col1.children.add( + Utils.buildLine(S.of(context).domain_name, widget.data['domain'], valueSize: 16), + ); + } + if (widget.data['exists_service'] == null) { col1.children.add( Utils.buildLine(S.of(context).current_plan, 'N/A', valueSize: 16), diff --git a/lib/widgets/mobile/mobile_checkout.dart b/lib/widgets/mobile/mobile_checkout.dart index 4596b64..30398cb 100644 --- a/lib/widgets/mobile/mobile_checkout.dart +++ b/lib/widgets/mobile/mobile_checkout.dart @@ -335,6 +335,7 @@ class MobileCheckoutState extends State with SingleTickerProvide check(); }, initialLabelIndex: deliveryMethodIndex, + totalSwitches: shippingMethodLabels.length, ); switch (position) { case 0: diff --git a/lib/widgets/mobile/mobile_navigation_drawer.dart b/lib/widgets/mobile/mobile_navigation_drawer.dart index d8a33fd..66f527c 100644 --- a/lib/widgets/mobile/mobile_navigation_drawer.dart +++ b/lib/widgets/mobile/mobile_navigation_drawer.dart @@ -189,6 +189,7 @@ class MobileNavigationDrawerState extends State { TextLink(S.of(context).contact_us, '/contact-us', paddingVertical: 5.0, paddingHorizontal: 10.0, closeDrawer: true,), TextLink(S.of(context).about_us, '/about-us', paddingVertical: 5.0, paddingHorizontal: 10.0, closeDrawer: true,), TextLink(S.of(context).renew_license, '/renew-license', paddingVertical: 5.0, paddingHorizontal: 10.0, closeDrawer: true,), + TextLink(S.of(context).create_a_online_store, '/contact-stores', paddingVertical: 5.0, paddingHorizontal: 10.0,), Container( margin: EdgeInsets.only(top: 20.0, bottom: 10.0), child: Text( diff --git a/lib/widgets/mobile/mobile_tutorials.dart b/lib/widgets/mobile/mobile_tutorials.dart deleted file mode 100644 index f6f6017..0000000 --- a/lib/widgets/mobile/mobile_tutorials.dart +++ /dev/null @@ -1,92 +0,0 @@ - -import '../../constants.dart'; -import '../../utils/iframe_web.dart' if (dart.library.io) '../../utils/fake_iframe_web.dart'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_inappwebview/flutter_inappwebview.dart'; - -class MobileTutorials extends StatefulWidget { - const MobileTutorials({Key key}) : super(key: key); - - @override - State createState() { - return MobileTutorialsState(); - } - -} - -class MobileTutorialsState extends State { - InAppWebViewController webView; - String url = ""; - double progress = 0; - bool isLoadStop = false; - - @override - Widget build(BuildContext context) { - if (kIsWeb) { - return Column( - mainAxisSize: MainAxisSize.max, - children: [ - Expanded( - child: IFrameWeb( - width: double.maxFinite.toString(), - height: double.maxFinite.toString(), - src: Constants.TUTORIAL_URL, - ), - ), - ], - ); - } else { - print('progress: $progress'); - return Stack( - children: [ - InAppWebView( - initialUrlRequest: URLRequest(url: Uri.parse(Constants.TUTORIAL_URL)), - initialOptions: InAppWebViewGroupOptions( - crossPlatform: InAppWebViewOptions( - - ), - ), - onWebViewCreated: (InAppWebViewController controller) { - webView = controller; - }, - onLoadStart: (controller, url) { - if (mounted) { - setState(() { - this.url = url.toString(); - this.isLoadStop = false; - }); - } - }, - onLoadStop: (controller, url) async { - if (mounted) { - setState(() { - this.url = url.toString(); - this.isLoadStop = true; - }); - } - }, - onProgressChanged: (InAppWebViewController controller, int progress) { - if (mounted) { - setState(() { - if (this.progress < 1.0) { - this.isLoadStop = false; - } else { - this.isLoadStop = true; - } - this.progress = progress / 100; - }); - } - }, - ), - isLoadStop ? Container() : - Center( - child: CircularProgressIndicator(), - ), - ], - ); - } - } - -} \ No newline at end of file diff --git a/lib/widgets/mobile/mobile_view_blog.dart b/lib/widgets/mobile/mobile_view_blog.dart index 37df121..da13d64 100644 --- a/lib/widgets/mobile/mobile_view_blog.dart +++ b/lib/widgets/mobile/mobile_view_blog.dart @@ -13,6 +13,8 @@ import '../../store/store.dart'; import '../../utils/http_util.dart'; import '../../utils/utils.dart'; +import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart'; + class MobileViewBlog extends StatefulWidget { final Key key; final int bid; @@ -126,11 +128,7 @@ class MobileViewBlogState extends State { Container( width: min(MediaQuery.of(context).size.width, MediaQuery.of(context).size.height) - 100.0, height: min(MediaQuery.of(context).size.width, MediaQuery.of(context).size.height) - 100.0, - child: PhotoView( - imageProvider: NetworkImage( - 'https:${blog.imageUrl}', - ), - ), + child: Util.showImage('https:${blog.imageUrl}'), ) : SizedBox.shrink(), decoration: BoxDecoration( border: Border( diff --git a/lib/widgets/mobile/product_item.dart b/lib/widgets/mobile/product_item.dart new file mode 100644 index 0000000..fb4e588 --- /dev/null +++ b/lib/widgets/mobile/product_item.dart @@ -0,0 +1,261 @@ + +import 'package:flutter/material.dart'; + +import '../../constants.dart'; +import '../../events/eventbus.dart'; +import '../../events/events.dart'; +import '../../generated/l10n.dart'; +import '../../models/business.dart'; +import '../../models/product.dart'; +import '../../pages/product_detail_page.dart'; +import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart'; +import '../../widgets/general/add_remove_button.dart'; +import '../../widgets/general/show_price.dart'; + +class ProductItem extends StatefulWidget { + final Business business; + final Product product; + final bool horizontal; + final double imageWidth; + + const ProductItem(this.product, this.business, { + Key key, + this.horizontal = false, + this.imageWidth = 110, + }) : super(key: key); + + @override + State createState() => ProductItemState(); + +} + +class ProductItemState extends State { + + @override + Widget build(BuildContext context) { + return Container( + // width: 160.0, + height: widget.horizontal ? Constants.PRODUCT_ITEM_HEIGHT_H : Constants.PRODUCT_ITEM_HEIGHT_V, + padding: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 15.0).copyWith(bottom: 5.0), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: new BorderSide( + color: new Color(0xFFEBEBEB), + ), + ), + ), + child: new SizedBox.expand( + child: Container( + padding: EdgeInsets.only(left: 10.0, right: 10.0, top: 10.0, bottom: 10.0), + child: widget.horizontal ? getHorizontal(true) : getVertial(true), + ), + ), + ); + } + + Widget getHorizontal(bool onHover) { + Row row1 = Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + margin: new EdgeInsets.all(10.0), + width: widget.imageWidth, + height: widget.imageWidth, + child: GestureDetector( + child: onHover && widget.product.secondImagePath.isNotEmpty ? + Util.showImage('${widget.product.secondImagePath}', + fit: BoxFit.fill, + ) : + Util.showImage('${widget.product.imagePath}', + fit: BoxFit.fill, + ), + onTap: (){ + _showProductDetail(); + }, + ), + ), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + child: GestureDetector( + child: Text( + '${widget.product.name}', +// overflow: kIsWeb ? null : TextOverflow.ellipsis, + overflow: TextOverflow.ellipsis, + maxLines: 2, + softWrap: true, + style: new TextStyle( + fontSize: 15.0, + ), + ), + onTap: (){ + _showProductDetail(); + }, + ), + ), + Text( + widget.product.description, +// overflow: kIsWeb ? null : TextOverflow.ellipsis, + overflow: TextOverflow.ellipsis, + maxLines: 2, + style: new TextStyle( + fontSize: 12.0, + color: new Color(0xFF999999), + ), + ), + ], + ), + ), + ], + ); + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + row1, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + child: widget.business.showMonthlySold ? + Text( + S.of(context).sold_per_month_token(widget.product.monthSales.toStringAsFixed(0)), + style: new TextStyle( + fontSize: 9.0 + ), + ) : SizedBox.shrink(), + ), + ShowPrice( + widget.product.price, + regularPrice: widget.product.regularPrice, + currencySign: '\$', + fontWeight: FontWeight.bold, + ), + ], + ), + AddRemoveButton(product: widget.product, business: widget.business, addOnly: false, onHovor: onHover,), + ], + ), + ], + ); + } + + Widget getVertial(bool onHover) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new Container( + margin: new EdgeInsets.all(10.0), + width: widget.imageWidth, + height: widget.imageWidth, + child: GestureDetector( + child: onHover && widget.product.secondImagePath.isNotEmpty ? + Util.showImage('${widget.product.secondImagePath}', + fit: BoxFit.fill, + ) : + Util.showImage('${widget.product.imagePath}', + fit: BoxFit.fill, + ), + onTap: (){ + _showProductDetail(); + }, + ), + ), + new Expanded( + child: new Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + child: GestureDetector( + child: Text( + '${widget.product.name}', +// overflow: kIsWeb ? null : TextOverflow.ellipsis, + overflow: TextOverflow.ellipsis, + maxLines: 2, + softWrap: true, + style: new TextStyle( + fontSize: 15.0, + ), + ), + onTap: (){ + _showProductDetail(); + }, + ), + ), + Container( + child: Text( + widget.product.description, +// overflow: kIsWeb ? null : TextOverflow.ellipsis, + overflow: TextOverflow.ellipsis, + maxLines: 2, + style: new TextStyle( + fontSize: 12.0, + color: new Color(0xFF999999), + ), + ), + ), + new Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + child: widget.business.showMonthlySold ? + Text( + S.of(context).sold_per_month_token(widget.product.monthSales.toStringAsFixed(0)), + style: new TextStyle( + fontSize: 9.0 + ), + ) : SizedBox.shrink(), + ), + ShowPrice( + widget.product.price, + regularPrice: widget.product.regularPrice, + currencySign: '\$', + fontWeight: FontWeight.bold, + ), + ], + ), + AddRemoveButton(product: widget.product, business: widget.business, addOnly: false, onHovor: onHover,), + ], + ), + ], + ), + ), + ], + ); + } + + void _showProductDetail() { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ProductDetailPage( + product: widget.product, + business: widget.business, + )), + ); + } + + @override + void initState() { + super.initState(); + eventBus.on().listen((event) { + if (mounted) { + setState(() { + + }); + } + }); + } +} \ No newline at end of file diff --git a/lib/widgets/mobile/product_search.dart b/lib/widgets/mobile/product_search.dart new file mode 100644 index 0000000..c025f85 --- /dev/null +++ b/lib/widgets/mobile/product_search.dart @@ -0,0 +1,152 @@ + +import 'package:dio/dio.dart'; +import 'package:flappy_search_bar/flappy_search_bar.dart'; +import 'package:flutter/material.dart'; + +import '../../events/eventbus.dart'; +import '../../events/events.dart'; +import '../../generated/l10n.dart'; +import '../../models/business.dart'; +import '../../models/product.dart'; +import '../../pages/product_detail_page.dart'; +import '../../utils/http_util.dart'; +import '../../utils/utils.dart'; +import '../../widgets/general/breadcrumbs.dart'; +import '../../widgets/general/navigationbar.dart'; +import 'product_item.dart'; + +class ProductSearch extends StatefulWidget { + final Business business; + + const ProductSearch(this.business, {Key key}) : super(key: key); + + @override + State createState() => ProductSearchState(); +} + +class ProductSearchState extends State { + + int page = 1; + int numPerPage = 10; + int lastResultSize = 0; + double lastBottomPosition = 0; + String lastKeyword = ''; + + SearchBarController _controller = SearchBarController(); + + @override + Widget build(BuildContext context) { + + return Scaffold( + appBar: MiniNavigationBar( + title: S.of(context).search_product, + back: true, + breadCrumbs: [ + BreadCrumb(S.of(context).search_product, null), + ], + ), + drawer: null, + body: SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: NotificationListener( + child: SearchBar( + searchBarController: _controller, + minimumChars: 2, + hintText: S.of(context).enter_keyword, + cancellationWidget: Text( + S.of(context).cancel, + ), + onSearch: search, + onItemFound: (Product searchProduct, int index) { + return ProductItem( + searchProduct, + widget.business, + horizontal: true, + imageWidth: 80.0, + ); + }, + onError: (error) { + return Center( + child: Text("$error"), + ); + }, + emptyWidget: Center( + child: Text( + S.of(context).empty_result_change_keyword, + ), + ), + ), + onNotification: (notification) { + if (notification.metrics.atEdge) { + print('fff: $page, $lastBottomPosition, ${notification.metrics.pixels}'); + if (page != 0 && lastResultSize >= numPerPage && notification.metrics.pixels != 0) { + if (notification.metrics.pixels > lastBottomPosition) { + lastBottomPosition = notification.metrics.pixels; + page += 1; + _controller.replayLastSearch(); + } + } + } + return true; + }, + ), + ), + ), + bottomNavigationBar: null, + ); + } + + Future> search(String keyword) async { + if (lastKeyword != keyword) { + page = 1; + } + lastKeyword = keyword; + var result = await HttpUtil.httpGet('v1/search-store-product2', + queryParameters: { + 'store_id': widget.business.id, + 'keyword': keyword, + 'page': page, + 'num_per_page': numPerPage, + }, + returnError: true, + ); + if (result is DioError) { + if (result.response != null) { + throw RuntimeError(result.response.data); + } else { + throw RuntimeError(result.message); + } + } else if (result != null && result is List) { + lastBottomPosition = 0; + var r = result.map((e) => Product.fromJson(e)).toList(); + lastResultSize = r.length; + if (lastResultSize < numPerPage) { + page = 1; + } + return r; + } + return []; + } + + @override + void initState() { + super.initState(); + eventBus.on().listen((event) { + if (mounted) { + setState(() {}); + } + }); + } + + void _showProductDetail(Product p) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ProductDetailPage( + product: p, + business: widget.business, + )), + ); + } +} \ No newline at end of file diff --git a/lib/widgets/mobile/mobile_shop.dart b/lib/widgets/mobile/shop.dart similarity index 79% rename from lib/widgets/mobile/mobile_shop.dart rename to lib/widgets/mobile/shop.dart index 8ac79d2..24137f0 100644 --- a/lib/widgets/mobile/mobile_shop.dart +++ b/lib/widgets/mobile/shop.dart @@ -1,63 +1,59 @@ -import 'dart:async'; + import 'dart:math'; import 'package:badges/badges.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/events/eventbus.dart'; +import 'package:flutter_wisetronic/events/events.dart'; +import 'package:flutter_wisetronic/generated/l10n.dart'; +import 'package:flutter_wisetronic/models/business.dart'; +import 'package:flutter_wisetronic/models/cart_info.dart'; +import 'package:flutter_wisetronic/models/cart_line_item.dart'; +import 'package:flutter_wisetronic/models/category_products.dart'; +import 'package:flutter_wisetronic/models/comment.dart'; +import 'package:flutter_wisetronic/models/product.dart'; +import 'package:flutter_wisetronic/models/product_image.dart'; +import 'package:flutter_wisetronic/pages/product_detail_page.dart'; +import 'package:flutter_wisetronic/store/store.dart'; +import 'package:flutter_wisetronic/utils/http_util.dart'; +import 'package:flutter_wisetronic/utils/shop_scroll_controller.dart'; +import 'package:flutter_wisetronic/utils/shop_scroll_coordinator.dart'; +import 'package:flutter_wisetronic/utils/utils.dart'; +import 'package:flutter_wisetronic/widgets/general/add_remove_button.dart'; +import 'package:flutter_wisetronic/widgets/general/animation_point_manager.dart'; +import 'package:flutter_wisetronic/widgets/general/carousel.dart'; +import 'package:flutter_wisetronic/widgets/general/read_more_text.dart'; import 'package:flutter_wisetronic/widgets/general/show_price.dart'; -import 'package:fluttertoast/fluttertoast.dart'; +import 'package:flutter_wisetronic/widgets/general/sliding_up_panel.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:smooth_star_rating/smooth_star_rating.dart'; import '../../constants.dart'; -import '../../events/eventbus.dart'; -import '../../events/events.dart'; -import '../../generated/l10n.dart'; -import '../../models/business.dart'; -import '../../models/cart_info.dart'; -import '../../models/cart_line_item.dart'; -import '../../models/category_products.dart'; -import '../../models/comment.dart'; -import '../../models/product.dart'; -import '../../models/product_image.dart'; -import '../../pages/product_detail_page.dart'; -import '../../pages/store_product_search.dart'; -import '../../routes.dart'; -import '../../store/actions.dart'; -import '../../store/store.dart'; -import '../../utils/http_util.dart'; -import '../../utils/shop_scroll_controller.dart'; -import '../../utils/shop_scroll_coordinator.dart'; -import '../../utils/util_web.dart' - if (dart.library.io) '../../utils/util_io.dart'; -import '../../utils/utils.dart'; -import '../../widgets/general/add_remove_button.dart'; -import '../../widgets/general/animation_point_manager.dart'; -import '../../widgets/general/carousel.dart'; -import '../../widgets/general/product_item.dart'; -import '../../widgets/general/read_more_text.dart'; -import '../../widgets/general/sliding_up_panel.dart'; -import '../../widgets/general/style.dart'; + +import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart'; +import 'product_item.dart'; +import 'product_search.dart'; import 'shopping_cart_bar.dart'; -class MobileShop extends StatefulWidget { - final int businessId; - - const MobileShop({Key key, this.businessId}) : super(key: key); - - @override - State createState() => MobileShopState(); -} - MediaQueryData mediaQuery; double statusBarHeight; double screenWidth; double screenHeight; -class MobileShopState extends State +class Shop extends StatefulWidget { + final int businessId; + + const Shop({Key key, this.businessId}) : super(key: key); + + @override + State createState() => ShopState(); +} + +class ShopState extends State with TickerProviderStateMixin, AutomaticKeepAliveClientMixin { + GlobalKey _scaffoldKey = new GlobalKey(); Business _business; @@ -75,7 +71,7 @@ class MobileShopState extends State static const num _categoryHeight = 50.0; static const num _categoryDescHeight = 50.0; - static const num _productHeight = 115.0; + static const num _productHeight = Constants.PRODUCT_ITEM_HEIGHT_H; int _categoryIndex = 0; bool _categoryIndexChange = false; @@ -103,7 +99,7 @@ class MobileShopState extends State int _commentPageCount = 1; bool _commentLoadingFinish = false; RefreshController _commentRefreshController = - RefreshController(initialRefresh: true); + RefreshController(initialRefresh: true); PanelController panelController = PanelController(); SlidingUpPanel _slidUpShoppingCart; @@ -256,9 +252,33 @@ class MobileShopState extends State padding: EdgeInsets.only( left: 10.0, top: 10.0, + right: 10.0, bottom: 10.0, ), - width: 150.0, + margin: EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(5.0)), + color: Colors.white, + border: Border( + top: BorderSide( + width: 1.0, + color: Colors.black12, + ), + bottom: BorderSide( + width: 1.0, + color: Colors.black12, + ), + left: BorderSide( + width: 1.0, + color: Colors.black12, + ), + right: BorderSide( + width: 1.0, + color: Colors.black12, + ), + ), + ), + width: 160.0, height: 220.0, child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -267,6 +287,7 @@ class MobileShopState extends State child: Container( child: Util.showImage( _business.promoProducts[i].imagePath, + width: 110.0, ), ), onTap: () { @@ -308,7 +329,7 @@ class MobileShopState extends State pinned: false, floating: true, delegate: _SliverAppBarDelegate2( - minHeight: 250.0, + minHeight: 256.0, maxHeight: 260.0, child: Column( mainAxisAlignment: MainAxisAlignment.start, @@ -359,7 +380,7 @@ class MobileShopState extends State icon: Icon(Icons.arrow_back_ios), onPressed: () { if (_animationFinish) { - Routes.router.pop(context); + Navigator.of(context).maybePop(); } }), titleSpacing: 0.0, @@ -371,8 +392,8 @@ class MobileShopState extends State onTap: () { Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) { - return StoreProductSearch(_business); - })); + return ProductSearch(_business); + })); }, ), ), @@ -540,7 +561,7 @@ class MobileShopState extends State cancelButton: CupertinoActionSheetAction( child: Text(S.of(context).close), onPressed: () { - Navigator.of(context).pop(); + Navigator.of(context).maybePop(); }, ), ); @@ -786,8 +807,8 @@ class MobileShopState extends State )); var duration = Duration( seconds: (_business.distanceInfo.duration != null - ? _business.distanceInfo.duration.value - : 30) + + ? _business.distanceInfo.duration.value + : 30) + _business.shippingTime * 60); var hours = duration.inHours.remainder(60); var minutes = duration.inMinutes.remainder(60); @@ -922,28 +943,28 @@ class MobileShopState extends State children: [ _business.bulletin.isNotEmpty ? Row( crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( + children: [ + Container( padding: - EdgeInsets.only(left: 10.0, right: 5.0, bottom: 10.0), + EdgeInsets.only(left: 10.0, right: 5.0, bottom: 10.0), child: Icon( Icons.announcement, size: 14.0, color: Colors.white, )), - Container( - width: mediaQuery.size.width - 30.0, - padding: EdgeInsets.only(right: 10.0, bottom: 10.0), - child: new Text( - _business.bulletin.isEmpty ? '' : _business.bulletin, - softWrap: true, - style: new TextStyle( - fontSize: 12.0, color: const Color(0xFFDDDDDD)), + Container( + width: mediaQuery.size.width - 30.0, + padding: EdgeInsets.only(right: 10.0, bottom: 10.0), + child: new Text( + _business.bulletin.isEmpty ? '' : _business.bulletin, + softWrap: true, + style: new TextStyle( + fontSize: 12.0, color: const Color(0xFFDDDDDD)), // overflow: TextOverflow.ellipsis, - ), ), - ], - ) : SizedBox.shrink(), + ), + ], + ) : SizedBox.shrink(), _business.description.isNotEmpty ? Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, @@ -1092,13 +1113,13 @@ class MobileShopState extends State } Widget _buildMainContent() { - return new Row( + return Row( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _buildCategories(), Expanded( child: _buildProducts(), - ) + ), ], ); } @@ -1116,7 +1137,7 @@ class MobileShopState extends State CategoryProducts cp = _categoryProducts[i]; int qtyInCategory = 0; CartInfo cartInfo = - Utils.getCartInfoByBusiness(store.state.cartInfos, _business); + Utils.getCartInfoByBusiness(store.state.cartInfos, _business); if (cartInfo != null && cartInfo.businessInfo.id == _business.id && cartInfo.productList != null) { @@ -1141,14 +1162,14 @@ class MobileShopState extends State style: TextStyle( fontSize: 13.0, fontWeight: (cp.id == Constants.FEATURED_PRODUCT_ID || - cp.id == Constants.HOT_SALE_ID) + cp.id == Constants.HOT_SALE_ID) ? FontWeight.bold : FontWeight.normal, color: (cp.id == Constants.HOT_SALE_ID) ? Colors.redAccent : ((cp.id == Constants.FEATURED_PRODUCT_ID) - ? Colors.lightGreen - : Colors.black87)), + ? Colors.lightGreen + : Colors.black87)), // overflow: kIsWeb ? null : TextOverflow.ellipsis, overflow: TextOverflow.ellipsis, softWrap: true, @@ -1178,10 +1199,10 @@ class MobileShopState extends State height: 70.0, padding: new EdgeInsets.symmetric(horizontal: 10.0), decoration: new BoxDecoration( - color: _categoryIndex == i ? Style.backgroundColor : null, + color: _categoryIndex == i ? Colors.white : null, border: new Border( bottom: - new BorderSide(color: new Color(0xFFEBEBEB)))), + new BorderSide(color: new Color(0xFFEBEBEB)))), child: categoryRow, ), onTap: () => _selectCategory(i), @@ -1208,10 +1229,10 @@ class MobileShopState extends State _categoryIndexChange = true; _listScrollController1 .animateTo(height, - duration: new Duration( - microseconds: 200, - ), - curve: Curves.linear) + duration: new Duration( + microseconds: 200, + ), + curve: Curves.linear) .then((value) { _categoryIndexChange = false; }); @@ -1316,7 +1337,7 @@ class MobileShopState extends State controller: _listScrollController1, // itemCount: displayProductByCategoryClick ? 1 : (_categoryProducts == null ? 0 : _categoryProducts.length), itemCount: - _categoryProducts == null ? 0 : numCategoriesHasProducts(), + _categoryProducts == null ? 0 : numCategoriesHasProducts(), itemBuilder: (BuildContext context, int i) { CategoryProducts cp; cp = _categoryProducts[i]; @@ -1357,42 +1378,42 @@ class MobileShopState extends State children: [ new Expanded( child: new Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - textBaseline: TextBaseline.alphabetic, - children: [ - new Padding( - padding: new EdgeInsets.only(right: 5.0), - child: new Text( - cp.name, - style: new TextStyle( - fontSize: 16.0, - fontWeight: + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + textBaseline: TextBaseline.alphabetic, + children: [ + new Padding( + padding: new EdgeInsets.only(right: 5.0), + child: new Text( + cp.name, + style: new TextStyle( + fontSize: 16.0, + fontWeight: (cp.id == Constants.FEATURED_PRODUCT_ID || - cp.id == Constants.HOT_SALE_ID) + cp.id == Constants.HOT_SALE_ID) ? FontWeight.bold : FontWeight.normal, - color: (cp.id == Constants.HOT_SALE_ID) - ? Colors.redAccent - : ((cp.id == - Constants.FEATURED_PRODUCT_ID) + color: (cp.id == Constants.HOT_SALE_ID) + ? Colors.redAccent + : ((cp.id == + Constants.FEATURED_PRODUCT_ID) ? Colors.lightGreen : Colors.black87)), - overflow: TextOverflow.ellipsis, - ), - ), - new Visibility( - visible: cp.description.isNotEmpty, - child: new Text( - cp.description, - overflow: TextOverflow.ellipsis, - style: new TextStyle( - fontSize: 10.0, - color: new Color(0xFF999999)), + overflow: TextOverflow.ellipsis, + ), ), - replacement: const SizedBox.shrink()), - ], - )) + new Visibility( + visible: cp.description.isNotEmpty, + child: new Text( + cp.description, + overflow: TextOverflow.ellipsis, + style: new TextStyle( + fontSize: 10.0, + color: new Color(0xFF999999)), + ), + replacement: const SizedBox.shrink()), + ], + )) ], ))); for (var p in cp.products) { @@ -1400,9 +1421,13 @@ class MobileShopState extends State children: [], ); - pStack.children.add(new ProductItem( - product: p, - business: _business, + pStack.children.add(Container( + // width: MediaQuery.of(context).size.width - 100.0, + child: ProductItem( + p, _business, + horizontal: true, + imageWidth: 80.0, + ), )); col.children.add(pStack); @@ -1494,129 +1519,6 @@ class MobileShopState extends State } }); - // onProductWillAddToCartSubscription = - // eventBus.on().listen((event) { - // if (mounted) { - // itemAddToCart(event.buttonKey); - // - // CartInfo cartInfo = - // Utils.getCartInfoByBusiness(store.state.cartInfos, event.business); - // - // if (cartInfo == null || cartInfo.productList.length == 0) { - // cartInfo = CartInfo(); - // cartInfo.id = 0; - // cartInfo.amountPaid = 0.0; - // cartInfo.businessInfo = event.business; - // cartInfo.extraFeeList = []; - // cartInfo.discountList = []; - // CartLineItem lineItem = _newCartLineItem( - // id: 0, - // price: event.price, - // product: event.product, - // name: event.product.name, - // description: event.description, - // quantity: 1.0); - // cartInfo.productList = [lineItem]; - // store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList( - // store.state.cartInfos, cartInfo))); - // eventBus.fire(new OnCartInfoUpdated()); - // } else { - // if (event.product.productAttributes.length > 0) { - // CartLineItem lineItem = _newCartLineItem( - // id: 0, - // price: event.price, - // product: event.product, - // name: event.product.name, - // description: event.description, - // quantity: 1.0); - // cartInfo.productList.add(lineItem); - // store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList( - // store.state.cartInfos, cartInfo))); - // eventBus.fire(new OnCartInfoUpdated()); - // } else { - // int found = -1; - // for (var i = 0; i < cartInfo.productList.length; i++) { - // if (event.product.id == cartInfo.productList[i].product.id) { - // found = i; - // break; - // } - // } - // if (found == -1) { - // CartLineItem lineItem = _newCartLineItem( - // id: 0, - // price: event.price, - // product: event.product, - // name: event.product.name, - // description: event.description, - // quantity: 1.0); - // cartInfo.productList.add(lineItem); - // store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList( - // store.state.cartInfos, cartInfo))); - // eventBus.fire(new OnCartInfoUpdated()); - // } else { - // if (cartInfo.productList[found].quantity + 1.0 > - // event.product.leftNum) { - // Fluttertoast.showToast( - // msg: S.of(context).product_insufficient, - // toastLength: Toast.LENGTH_SHORT, - // gravity: ToastGravity.CENTER, - // backgroundColor: Colors.red, - // textColor: Colors.white); - // } else { - // cartInfo.productList[found].quantity += 1; - // store.dispatch(new UpdateCartInfo( - // Utils.addCartInfoToCartInfoList( - // store.state.cartInfos, cartInfo))); - // eventBus.fire(new OnCartInfoUpdated()); - // } - // } - // } - // } - // } - // }); - // onProductWillRemoveFromCartSubscription = - // eventBus.on().listen((event) { - // if (mounted) { - // CartInfo cartInfo = - // Utils.getCartInfoByBusiness(store.state.cartInfos, event.business); - // if (cartInfo != null) { - // if (cartInfo.productList.length > 0) { - // if (event.productListIndex != -1) { - // if (cartInfo.productList[event.productListIndex].quantity <= 1) { - // cartInfo.productList.removeAt(event.productListIndex); - // } else { - // cartInfo.productList[event.productListIndex].quantity -= 1; - // } - // } else { - // int productListIndex = -1; - // for (var i = 0; i < cartInfo.productList.length; i++) { - // if (cartInfo.productList[i].product.id == event.product.id) { - // productListIndex = i; - // break; - // } - // } - // if (productListIndex != -1) { - // if (cartInfo.productList[productListIndex].quantity <= 1) { - // cartInfo.productList.removeAt(productListIndex); - // } else { - // cartInfo.productList[productListIndex].quantity -= 1; - // } - // } - // } - // } - // - // if (cartInfo.productList.length <= 0) { - // store.dispatch(UpdateCartInfo(Utils.removeCartInfoFromCartInfoList( - // store.state.cartInfos, cartInfo))); - // } else { - // store.dispatch(UpdateCartInfo(Utils.addCartInfoToCartInfoList( - // store.state.cartInfos, cartInfo))); - // } - // eventBus.fire(new OnCartInfoUpdated()); - // } - // } - // }); - loadProducts(); } @@ -1630,67 +1532,71 @@ class MobileShopState extends State } _productCurrentPage = 1; Utils.loadProducts( - widget.businessId, categoryId, _productCurrentPage, false, - (value) { - if (_isLoading) { - _isLoading = false; - Navigator.of(context).pop(); + widget.businessId, categoryId, _productCurrentPage, false, + (value) { + if (_isLoading) { + _isLoading = false; + Navigator.of(context).pop(); + } + if (mounted) { + setState(() { + + displayProductByCategoryClick = + value['display_product_by_category_click']; + displayProductByCategoryClickIndicator = ''; + _business = Business.fromJson(value['business']); + + _categoryProducts = (value['category_products'] as List) + .map((i) => CategoryProducts.fromJson(i)) + .toList(); + // _featuredProducts = (value['featured_products'] as List) + // .map((i) => Product.fromJson(i)) + // .toList(); + _featuredProducts = []; + // _hotSaleProducts = (value['hot_sale_products'] as List) + // .map((i) => Product.fromJson(i)) + // .toList(); + _hotSaleProducts = []; + _prompts = value['prompt'] as List; + + if (_hotSaleProducts.length > 0) { + CategoryProducts hs = CategoryProducts( + Constants.HOT_SALE_ID, + widget.businessId, + S.of(context).hot_sale, + '', + '', + _hotSaleProducts); + _categoryProducts.insert(0, hs); + } + + if (_featuredProducts.length > 0) { + CategoryProducts fe = CategoryProducts( + Constants.FEATURED_PRODUCT_ID, + widget.businessId, + S.of(context).featured_product, + '', + '', + _featuredProducts); + _categoryProducts.insert(0, fe); + } + + checkActionAndClose(context); + + if (displayProductByCategoryClick) { + _resetProductListScroll(); + } + }); + } + }, + (error) { + print('error: $error'); + if (_isLoading) { + _isLoading = false; + Navigator.of(context).maybePop(); + } + Utils.showMessageDialog(context, error); } - if (mounted) { - setState(() { - displayProductByCategoryClick = - value['display_product_by_category_click']; - displayProductByCategoryClickIndicator = ''; - _business = Business.fromJson(value['business']); - _categoryProducts = (value['category_products'] as List) - .map((i) => CategoryProducts.fromJson(i)) - .toList(); - _featuredProducts = (value['featured_products'] as List) - .map((i) => Product.fromJson(i)) - .toList(); - _hotSaleProducts = (value['hot_sale_products'] as List) - .map((i) => Product.fromJson(i)) - .toList(); - _prompts = value['prompt'] as List; - - if (_hotSaleProducts.length > 0) { - CategoryProducts hs = CategoryProducts( - Constants.HOT_SALE_ID, - widget.businessId, - S.of(context).hot_sale, - '', - '', - _hotSaleProducts); - _categoryProducts.insert(0, hs); - } - - if (_featuredProducts.length > 0) { - CategoryProducts fe = CategoryProducts( - Constants.FEATURED_PRODUCT_ID, - widget.businessId, - S.of(context).featured_product, - '', - '', - _featuredProducts); - _categoryProducts.insert(0, fe); - } - - checkActionAndClose(context); - - if (displayProductByCategoryClick) { - _resetProductListScroll(); - } - }); - } - }, - (error) { - print('error: $error'); - if (_isLoading) { - _isLoading = false; - Navigator.of(context).pop(); - } - Utils.showMessageDialog(context, error); - } ); } @@ -1700,59 +1606,59 @@ class MobileShopState extends State } _productCurrentPage += 1; Utils.loadProducts(widget.businessId, categoryId, _productCurrentPage, true, - (value) { - if (_isLoading) { - _isLoading = false; - Navigator.of(context).pop(); - } - if (mounted) { - setState(() { - List moreCategoryProducts = - (value as List).map((i) => CategoryProducts.fromJson(i)).toList(); - if (moreCategoryProducts.isEmpty) { - _productCurrentPage = 0; - displayProductByCategoryClickIndicator = - S.of(context).end_of_the_list; - } else { - if (moreCategoryProducts[0].products.length < Constants.ORDERS_PER_PAGE) { + (value) { + if (_isLoading) { + _isLoading = false; + Navigator.of(context).maybePop(); + } + if (mounted) { + setState(() { + List moreCategoryProducts = + (value as List).map((i) => CategoryProducts.fromJson(i)).toList(); + if (moreCategoryProducts.isEmpty) { _productCurrentPage = 0; displayProductByCategoryClickIndicator = S.of(context).end_of_the_list; } else { - displayProductByCategoryClickIndicator = - S.of(context).pull_up_to_load_more; + if (moreCategoryProducts[0].products.length < Constants.ORDERS_PER_PAGE) { + _productCurrentPage = 0; + displayProductByCategoryClickIndicator = + S.of(context).end_of_the_list; + } else { + displayProductByCategoryClickIndicator = + S.of(context).pull_up_to_load_more; + } + CategoryProducts currentCp = + getCategoryProductByCategoryId(categoryId); + if (currentCp != null) { + currentCp.products.addAll(moreCategoryProducts[0].products); + } else { + _productCurrentPage = 0; + displayProductByCategoryClickIndicator = + S.of(context).end_of_the_list; + } } - CategoryProducts currentCp = - getCategoryProductByCategoryId(categoryId); - if (currentCp != null) { - currentCp.products.addAll(moreCategoryProducts[0].products); - } else { - _productCurrentPage = 0; - displayProductByCategoryClickIndicator = - S.of(context).end_of_the_list; - } - } - }); + }); + } + }, + (error) { + print('error: $error'); + if (_isLoading) { + _isLoading = false; + Navigator.of(context).maybePop(); + } + Utils.showMessageDialog(context, error); } - }, - (error) { - print('error: $error'); - if (_isLoading) { - _isLoading = false; - Navigator.of(context).pop(); - } - Utils.showMessageDialog(context, error); - } ); } CartLineItem _newCartLineItem( {int id, - double price, - Product product, - String name, - String description, - double quantity}) { + double price, + Product product, + String name, + String description, + double quantity}) { CartLineItem lineItem = CartLineItem(); lineItem.unitPrice = price; lineItem.product = product; @@ -1787,9 +1693,9 @@ class MobileShopState extends State context, MaterialPageRoute( builder: (context) => ProductDetailPage( - product: p, - business: _business, - )), + product: p, + business: _business, + )), ); } @@ -1925,10 +1831,10 @@ class MobileShopState extends State S.of(context).store_closed, ), actions: [ - FlatButton( + TextButton( child: Text(S.of(context).ok), onPressed: () { - Navigator.of(context).pop(); + Navigator.of(context).maybePop(); showPrompt(0); }, ) @@ -1981,10 +1887,10 @@ class MobileShopState extends State ), ), actions: [ - FlatButton( + TextButton( child: Text(S.of(context).ok), onPressed: () { - Navigator.of(context).pop(); + Navigator.of(context).maybePop(); showPrompt(0); }, ) @@ -2007,10 +1913,10 @@ class MobileShopState extends State title: Text(_prompt['title']), content: Text(_prompt['message']), actions: [ - FlatButton( + TextButton( child: Text(S.of(context).ok), onPressed: () { - Navigator.of(context).pop(); + Navigator.of(context).maybePop(); showPrompt(idx + 1); }, ), @@ -2053,4 +1959,4 @@ class _SliverAppBarDelegate2 extends SliverPersistentHeaderDelegate { minHeight != oldDelegate.minHeight || child != oldDelegate.child; } -} +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 08e6aaa..6db5071 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -21,7 +21,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.8.1" + version: "2.8.2" awesome_card: dependency: transitive description: @@ -84,7 +84,7 @@ packages: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" charcode: dependency: transitive description: @@ -601,7 +601,7 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10" + version: "0.12.11" meta: dependency: transitive description: @@ -1000,7 +1000,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.2" + version: "0.4.3" timezone: dependency: transitive description: @@ -1119,7 +1119,7 @@ packages: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" video_player: dependency: transitive description: @@ -1219,5 +1219,5 @@ packages: source: hosted version: "2.2.1" sdks: - dart: ">=2.13.0 <3.0.0" + dart: ">=2.14.0 <3.0.0" flutter: ">=2.2.0" diff --git a/web/index.html b/web/index.html index 5142f9f..def91b0 100644 --- a/web/index.html +++ b/web/index.html @@ -20,7 +20,7 @@ - +