From b503cb7e6e66d86d439898c05fedc0ca0d3d85f4 Mon Sep 17 00:00:00 2001 From: jingyun <> Date: Fri, 4 Sep 2026 11:41:22 +0800 Subject: [PATCH] =?UTF-8?q?fix=EF=BC=9A=E8=8B=B9=E6=9E=9C=E4=B8=80?= =?UTF-8?q?=E9=94=AE=E7=99=BB=E5=BD=95=E9=A1=B5=E9=9D=A2=EF=BC=8C=E6=B7=B1?= =?UTF-8?q?=E6=B5=85=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jinzhi_onetap_back_daynight.png | Bin 0 -> 2200 bytes .../jinzhi_onetap_back_daynight.xml | 9 + .../res/drawable-xhdpi/jinzhi_onetap_back.png | Bin 0 -> 394 bytes .../jinzhi_onetap_back_daynight.png | Bin 0 -> 751 bytes .../drawable-xhdpi/jinzhi_onetap_button.png | Bin 0 -> 1055 bytes .../jinzhi_onetap_button_pressed.png | Bin 0 -> 1054 bytes .../drawable-xhdpi/jinzhi_onetap_checked.png | Bin 0 -> 479 bytes .../jinzhi_onetap_unchecked.png | Bin 0 -> 369 bytes .../drawable/jinzhi_onetap_back_daynight.xml | 9 + .../jinzhi_onetap_back.imageset/Contents.json | 1 + .../jinzhi_onetap_back.png | Bin 0 -> 394 bytes .../Contents.json | 8 + .../jinzhi_onetap_back_day.png | Bin 0 -> 382 bytes .../jinzhi_onetap_back_day@2x.png | Bin 0 -> 637 bytes .../jinzhi_onetap_back_day@3x.png | Bin 0 -> 463 bytes .../Contents.json | 8 + .../jinzhi_onetap_back_night.png | Bin 0 -> 322 bytes .../jinzhi_onetap_back_night@2x.png | Bin 0 -> 598 bytes .../jinzhi_onetap_back_night@3x.png | Bin 0 -> 461 bytes .../Contents.json | 8 + .../jinzhi_onetap_button.png | Bin 0 -> 2043 bytes .../jinzhi_onetap_button@2x.png | Bin 0 -> 4337 bytes .../jinzhi_onetap_button@3x.png | Bin 0 -> 6808 bytes .../Contents.json | 8 + .../jinzhi_onetap_button_pressed.png | Bin 0 -> 2035 bytes .../jinzhi_onetap_button_pressed@2x.png | Bin 0 -> 4360 bytes .../jinzhi_onetap_button_pressed@3x.png | Bin 0 -> 6868 bytes .../Contents.json | 1 + .../jinzhi_onetap_checked.png | Bin 0 -> 479 bytes .../Contents.json | 1 + .../jinzhi_onetap_unchecked.png | Bin 0 -> 369 bytes lib/common/tracking/umeng_service.dart | 16 +- .../auth/application/login_launcher.dart | 112 +-- .../application/one_key_login_service.dart | 694 +++++++++++++----- .../auth/utils/one_key_login_result.dart | 40 + 35 files changed, 687 insertions(+), 228 deletions(-) create mode 100644 android/app/src/main/res/drawable-night-xhdpi/jinzhi_onetap_back_daynight.png create mode 100644 android/app/src/main/res/drawable-night/jinzhi_onetap_back_daynight.xml create mode 100644 android/app/src/main/res/drawable-xhdpi/jinzhi_onetap_back.png create mode 100644 android/app/src/main/res/drawable-xhdpi/jinzhi_onetap_back_daynight.png create mode 100644 android/app/src/main/res/drawable-xhdpi/jinzhi_onetap_button.png create mode 100644 android/app/src/main/res/drawable-xhdpi/jinzhi_onetap_button_pressed.png create mode 100644 android/app/src/main/res/drawable-xhdpi/jinzhi_onetap_checked.png create mode 100644 android/app/src/main/res/drawable-xhdpi/jinzhi_onetap_unchecked.png create mode 100644 android/app/src/main/res/drawable/jinzhi_onetap_back_daynight.xml create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_back.imageset/Contents.json create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_back.imageset/jinzhi_onetap_back.png create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_back_day.imageset/Contents.json create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_back_day.imageset/jinzhi_onetap_back_day.png create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_back_day.imageset/jinzhi_onetap_back_day@2x.png create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_back_day.imageset/jinzhi_onetap_back_day@3x.png create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_back_night.imageset/Contents.json create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_back_night.imageset/jinzhi_onetap_back_night.png create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_back_night.imageset/jinzhi_onetap_back_night@2x.png create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_back_night.imageset/jinzhi_onetap_back_night@3x.png create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_button.imageset/Contents.json create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_button.imageset/jinzhi_onetap_button.png create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_button.imageset/jinzhi_onetap_button@2x.png create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_button.imageset/jinzhi_onetap_button@3x.png create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_button_pressed.imageset/Contents.json create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_button_pressed.imageset/jinzhi_onetap_button_pressed.png create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_button_pressed.imageset/jinzhi_onetap_button_pressed@2x.png create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_button_pressed.imageset/jinzhi_onetap_button_pressed@3x.png create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_checked.imageset/Contents.json create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_checked.imageset/jinzhi_onetap_checked.png create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_unchecked.imageset/Contents.json create mode 100644 ios/Runner/Assets.xcassets/jinzhi_onetap_unchecked.imageset/jinzhi_onetap_unchecked.png create mode 100644 lib/features/auth/utils/one_key_login_result.dart diff --git a/android/app/src/main/res/drawable-night-xhdpi/jinzhi_onetap_back_daynight.png b/android/app/src/main/res/drawable-night-xhdpi/jinzhi_onetap_back_daynight.png new file mode 100644 index 0000000000000000000000000000000000000000..305ac19d07cd1bb66f729d685ba1091a0f0413c2 GIT binary patch literal 2200 zcmeAS@N?(olHy`uVBq!ia0vp^89-dY!3HGdPHnehU|>wnbaoENc6N8p&&e+eE=WvH zb;&F)$VsdWFlJ!Tm{>buqxazefn)o_mM$n2kd=`!>U5qmiEEd|7EzZ%j?jazrtDj` za>6n9NlL8d{~MeBH*%fJ6Kl7!vfx-W`Ngv*OCBtGTB+Z;M5(I(ab3;(-H$C4Eb|KT zzB8||-WMHnN_+NFUDdBWEPEAro_(CNZoSvPb@q?{+I_j_cRF(a|Np%QyIvZunm%H4hSaM#_0 zi+n}Dx4g_*bJB8(aKsTln}Qn#7h0HPZ`%La+_=9Xw#fWp(EL`ZnpY<$Dyh#na=PGv z0rS)d=eD59<$dqU#qav}Zf#aiSg72xqhsq-z5+9M_3Y!fuGknDvBYfM`B19yiu=qp zVU5>=6Lzrl+zU9rE&OcO!*4Hb3_fTaxvet6ie;CsqFrCh3%TIW%mpuN7@3zR2``z( z7Yz(`mSj)o03Kcj#ysZ7?}7ZB)CkWsUtb0-Ae)1Mg;9!u706-)Vmn4@INOa;gMk?= z&cwjbp2@%hRpSSwL0|$9gY-aXrUguJ6&VYd;p_^K($bl#Q-Ks`fk$L91A~|<2s3&H zseE8yV9Lu3i71Ki^|4CM&(%vz$xlkvtH>0+>{umUo3Q%e#RDspr3imfVamB1>j zfNYSkzLEl1NlCV?QiN}Sf^&XRs)CuGfu4bq9hZWFf=y9MnpKdC8&o@xXRDM^Qc_^0 zuU}qXu2*iXmtT~wZ)j<0sc&GUZ)BtkRH0j3nOBlnp_^B%3^4>|j!SBBa#3bMNoIbY z0?6FNr2NtnTO}osMQ{LdXKF@SFQ zHXy^S0x~O7b0S?bb5rw*fljkCGBL0LTZ18ka43?_2qc{b7RWl0WRP@%Tw)a&lvbR7{`bs&qP>p*A-&C4vYGlE)zCJfbOqYsJ^q!@xkKUfqP|8`t9 z`tY=5$5m&ORL;P_eACm#F{Fa=?alMqmlI@;e^kFIP}md}STfH=V9!tH|Lp7iY%0S2 z7sbu_-=Goq&DqN; z{z=45rP!kd{37MIh>%ae7kahjR-j@^A1)jW>NZIYQ^5qZhRl%#K zuiB}=VYVghW+o%|arcX{YwcIoRmweqCba{|zTvBP!~&f}hX)a_)c6 z;}3Ih?eCg1eV-~vgvF}Nsl77M`&PbNEn%zrL(Hnx>4mi4=9@NAFOHPx=}i#t+a~N+ zcrPja1m|GEV{mXW(wYt_AadFqWU#ni-USAxubG1d;td&1jOtuTHy&#_U#OW5> zss_CmjStpdyW3q?mn3az9hhBpUwW18ZM!!U@=xqOx;A@)&g)zLt1eyKv@-e(|MNZj zE;&AUQ$6S1$yC z#j;mTS&dd3emUmEb=aUcU3*1Y(#}(n7HNB~?p{4N=gr&v_4d0(ziU~@8E|HoZF^B> zv~1Uks0+4d^Rg#qg_XvcuG{qY|0=GtySA^-;Q0TRWkSo6ZLM2YRxPty{7R15x#H{p zld75=(yGC$j;biVkIp*3f@7tYq!v%>l}!`Gs+_D==k_eoV!6t9(k*Duifwn_U7G0P z5z2AG?r@lgl;>Mj-p<>xQ=Ko}U;jrfRCU3;iC3z3C#!_2uBh6ZSI_O6`6a?*+ZHS3 zms@TnhyI+S{MYi*1Q8FRNokUA9zNXo>Vn7Nke82gw`_@8>m7AIo2B+*$zf+EE&YZ6 ziVK#w^;)e-`LIVR65-~;l1N#!` V!ZXLDUS)wQ5l>e?mvv4FO#qd5MF{`^ literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-night/jinzhi_onetap_back_daynight.xml b/android/app/src/main/res/drawable-night/jinzhi_onetap_back_daynight.xml new file mode 100644 index 0000000..181f897 --- /dev/null +++ b/android/app/src/main/res/drawable-night/jinzhi_onetap_back_daynight.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable-xhdpi/jinzhi_onetap_back.png b/android/app/src/main/res/drawable-xhdpi/jinzhi_onetap_back.png new file mode 100644 index 0000000000000000000000000000000000000000..d84cc9ef29935c4587f777442cfa1d040a4c7afd GIT binary patch literal 394 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7Ro>U<~whaSW-L^Y+&6Kxao0mW!?v zANYp2xQBc?!BWFDLFZo0F6SA+6QE3|w;dat;q4yECsy_!Ge}wMU+F z!J?0k8A8nJL>jn`_cI2({2|DoC3j!W;pyXO=8S}zXolXNe9i?6KfYx!G218Fz;=8) zHCwbPxC^Tld*dJaex`2^CoVzbr1wcN^5+IfWVg?4L1x#>}j0Mbab_Gb%ruyAVppsNi7srqa#SEKl#PgVUAMZ!^k;Yi>Ih|2CHb>)nKs8>42K2&w6nk$~OJ8!>FD(T(A=Q+G3CBI%2X3U!ItpD!TA49vF zM?Iq7AB}Y`xwzBewd|C1OTXV)zQX6k)4nL@F)r>}ZW(lwpYDF6Qy=$B`Qe)f1tN7dyKAPem;KAVhIh(x@s*8s)?6&p# z8*q*He^f3$@Hl)d^ne?!rk^Z~Vw3qhKS>o>L!Up?##ANRK$ zJ5u@V_{q%x>$2=cLQy^es)dCf2QyV96cp!1IDE!!0ocp6XWQYkFHj1@H|^s<%xcTX zI`CqS=PQ8IUiI(dC69suIui_$w@JO4gpZtgVfyD)VoaRWS9tw9ORPa*xjjNGFw!#o zi;jj(1VgU9sStZHr0_zU$;Oav&zcU{CXSL$dt==wX)$SR-VEuv&2E(xJjRkD`H%9i zSH6)zy^#^A86+rW^41b}RW}!^pPKqRZc+T#0QoiP(F2u-Fsu3nRUW~H9W%{7Ln#dL zc9d9b4wzasiBS(W1ooCqa0lRob5-qFWT}Utk;MZb2!wqs>mcrA_JD4T0GBi}M&IWP zFkIQ0G%f_d#RXy8SXJv}blp*$BgQ3;AO8pLzaQQ?!UbqwQ$WD9X@5i4Cw3;j(lEL# zTKs>&ucvjFe3*^H=lw&lp6Xu|1)z4C>i8<0l=B-Jy^I~$meLYGC-HZC$`ol>GXV9l zBg{hka43>UJ&I<2i71z{K`KS4ZlZQSApqXi1~Qy-Zh;o3&bL$z1?P6-RO*$vnu!WvBcN#YAn{KtT>4b-4w+xF!N|@KU3vV zYzR89PYV?r{ZW8EgSvnzbf`&nS~i3-tPn58=I8JI2B0@7?IC}V?~diA9p`lIPl!HUd|ZYgTvd3+~5{5Ax_ZSxJ=g F@GocRdNBY1 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/jinzhi_onetap_button_pressed.png b/android/app/src/main/res/drawable-xhdpi/jinzhi_onetap_button_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..cc64c57cdefe2df66ce414b7b7a2f9a5e42ff49a GIT binary patch literal 1054 zcmeAS@N?(olHy`uVBq!ia0y~yV7dTg7jUovN%Jf2(F_dCPd!~6Ln`LHz3Z6w*g(X^ z(Q^B#mn`%3j-NWv%`orCrmI4k6GN^hl}#@AdErNy-erb$@t40}%x7RonESJMmyhi0 zcOR1^84_%Y-2?Cbab`7UIPmifFMH`^e&MqW3|piw``Wr$Ff&}J@{s?>agm3?!QZg< zhQ8Q228J&Zm*g)q9x-NM*jx5Ax;qx6>bKP2Y4J*P7#So~m#m&&(2>r-aBpQ~u5Q!Ar^3JqR)x_@MivH@zDbg4GVWWiCOF}hkeR~}^o3vLS98>IpkwAHw{ zb~iIvaPr>2yR;#Kw=Qp-4H4YD)^@ihSWx-KrLBby-9RhdCVk7jYX6j%fnjkc)2&}X zn>!|*i9%OL_i z>-?=M48f+Sm&LwFRF`335U7y2a1Ch547sw6tWv-TVFD80Shjoy>Wg@n%x%KJ!19kf z<2BGje@gG46w6>>;NSofH-s*nGY5wHO@IC91&j;|3UH!e=ikTwBpDd4ZFFE}aBx5+ z9vo)pU}Q+J1)IwPGMo~^?%Da5lm4(XFjyF4F>ndv+vXMqh7Y&a&ejDcGXVh@u|ajg zT}Nhy1Doc@ZG$=Qz_o_5V~h+8^>@oRfy1Gm=@u6-3{KbPG_o-?G&BH-y^L>rm>C$B zwa0?R4kS55F9Zhs=E{Zb^Ytz$Nij4S&zfJdL6{F1MtgWNw1M7BH`@Oq9_+R-)-9qS z6*Iz1-oIjvasj5AO}nC)-j z0%Y3WzO{LG9$3^Cm|}L@yJ#$8WO#A%UY+hIT^W$|a#LPhONvic2MT9Iu8hoX_V+AMhAnaRKqwLdB2 zk>Gw#5R?14yszyuK|@}K0=wemi#6+Sw(AOBVPJSXQ=0GD{eO)5dk(fctoeEpnC}@p MUHx3vIVCg!0Bjd(vj6}9 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/jinzhi_onetap_checked.png b/android/app/src/main/res/drawable-xhdpi/jinzhi_onetap_checked.png new file mode 100644 index 0000000000000000000000000000000000000000..deb090ac14d3d5ec7457cf7553c489f9bf0204da GIT binary patch literal 479 zcmV<50U-W~P)TzC?#c;GKpCo7I_?JfP1oBDknaPn)lQWtJ zBgP@<4%VKLTxd`O2wD|%2OY28d}vUE5Q6CAUF^Ga6gea$$+aMQk|H6=wV+pUOUe;N z5ThiQf~X;&etw-Rh!o|x6GVcSbN7O%Lk@R)TnVy}<3_E zXD;c7_QVuivOWL(<3s#1Um1c~jF#$+VqFMmDMxkHs1rf0<*4ssbs+E#a!i)hx=HY@ zxB1$Tw39@$#~t-a!sGK!a#ZevJYaes{gEvPte(dh9ng}oiEA+ta1(ufr&ZCW`_y!G4w@67`M001Bz$}in{ Vm>P-_xTOF9002ovPDHLkV1jcK%^Ls! literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xhdpi/jinzhi_onetap_unchecked.png b/android/app/src/main/res/drawable-xhdpi/jinzhi_onetap_unchecked.png new file mode 100644 index 0000000000000000000000000000000000000000..1bfff56e2807e58354de46151e410cd9db487c73 GIT binary patch literal 369 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@Zgyv2V6^abaSW-L^Y*r*P_u#nYv6}H zCz<$~x}WSjdC%zQBOcX+?~Ic^itZ?KQczM-+LgZXX#ccNzgoIa{e1b$r;u&Rw1`4C z3I7$UK7Gk^jkoZ^WE1Ku_|IE7Q zdHRfnoX7I@5mGG2t==mx*mO~j_xbfZ?tT+bdsjVU*u*r|bKUiu*~d7A7*&`&SSD~N z2s$V=xG;1wkR%YcV9(E#u-f)J)wh3MRX;cfXo{Re<)rMe>b*Yd8L~Vt-|T5`{M7eN z!=t)b?(X#!R*sbpD%^dyy{q1eoJ`jHb~I{T$}~qaKHcn@-u}|Z)^0j;^4jK(y_LXl d;4**9U8Yi*CH-t;JTNF3JYD@<);T3K0RWGDlk@-p literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable/jinzhi_onetap_back_daynight.xml b/android/app/src/main/res/drawable/jinzhi_onetap_back_daynight.xml new file mode 100644 index 0000000..fab349f --- /dev/null +++ b/android/app/src/main/res/drawable/jinzhi_onetap_back_daynight.xml @@ -0,0 +1,9 @@ + + + diff --git a/ios/Runner/Assets.xcassets/jinzhi_onetap_back.imageset/Contents.json b/ios/Runner/Assets.xcassets/jinzhi_onetap_back.imageset/Contents.json new file mode 100644 index 0000000..ecd626a --- /dev/null +++ b/ios/Runner/Assets.xcassets/jinzhi_onetap_back.imageset/Contents.json @@ -0,0 +1 @@ +{"images":[{"filename":"jinzhi_onetap_back.png","idiom":"universal","scale":"1x"},{"idiom":"universal","scale":"2x"},{"idiom":"universal","scale":"3x"}],"info":{"author":"xcode","version":1}} diff --git a/ios/Runner/Assets.xcassets/jinzhi_onetap_back.imageset/jinzhi_onetap_back.png b/ios/Runner/Assets.xcassets/jinzhi_onetap_back.imageset/jinzhi_onetap_back.png new file mode 100644 index 0000000000000000000000000000000000000000..d84cc9ef29935c4587f777442cfa1d040a4c7afd GIT binary patch literal 394 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7Ro>U<~whaSW-L^Y+&6Kxao0mW!?v zANYp2xQBc?!BWFDLFZo0F6SA+6QE3|w;dat;q4yECsy_!Ge}wMU+F z!J?0k8A8nJL>jn`_cI2({2|DoC3j!W;pyXO=8S}zXolXNe9i?6KfYx!G218Fz;=8) zHCwbPxC^Tld*dJaex`2^CoVzbr1wc5F7#0d{N?sbW@chElpAxy7SRIdz?tCguLS169=HUafj8hd zMZ#smcfb{})_1SKXUaA-1>lcb$OgF9^=JWC818Eq;rthPn*vW2C=R!XtpOjv4N3{P zMN9^Iz^ztp2hP1dXTf6y`l4EBzGdQFV4nkz71#@Or?ejdFTe`esy3<$pw*&1-zX~& zs)=2WL=!o$PqPmWo0V$9;wku*R1xSU+R_qD%H&817i?K^fuAI-CeT~a2mL{nw_!Js zSZizrdZKHtc1P3&pd0PKoev*_4yl>|gG1;d7)QY^O0;BM@T|$2Qc^1aVE-443ODYy caxuBUH?M+O0IzkN5&!@I07*qoM6N<$f*{kM5dZ)H literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/jinzhi_onetap_back_day.imageset/jinzhi_onetap_back_day@2x.png b/ios/Runner/Assets.xcassets/jinzhi_onetap_back_day.imageset/jinzhi_onetap_back_day@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f0ddd079513761afa396aa74fd52f8beaab4f72d GIT binary patch literal 637 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEU~=(vaSW-L^K{nfE)heKw*8h< z=S9AZK69wm`(>*|o{VVBFO^>mU3NYB3Pyc;Ap*~RW2$aj)M|46VO^NGfOWFfvzpoa zM5jLa6CV_^iodTvUqDjX!mXg^fy6<>rev1m9DRZ^PysthCGi6dyag9l8TzXvaNl7$ zCid63hPRIQ4x1f=en`*ZTfJ2YjB6THKgd}y&3n21d6e*{EiW!LEIBxz;klNZ+?%Cc zA428__p|AAJ-M&-Gm!b*t9rILQSRh$wk6t=?!Wl!{y_0V=<)uoRu6T5{<+OsApc|S zgilEx`fN*VC)r;$bUu6VeBy!oYVoP}&Zjzjno@If<%E;lO%y79_PvQY@g!Pef{l87 znNi9oQ(lk%&Yx1#|Eo6VW#)^X%-_1xu)=F!8)LJHec-9!PcMF(A7H-w^z6KvwVDR6 zzP5|Z-?p_#F^=heIoIV-MzdK#mVd8bs*in9&vs`j<4%q*83&@8YZv{jTk*cg`g&-~ z(l-%btXSPv*6rFX<`dpnyjED7UE1i%4xYTyd-J0{>UZ6}XCu4rCD+C&vYTfmOg*>z zYDh$-`9ZCD)ln~FXD3WO|Nb6J_Jy`=;WdHQdA=LMcq>g0W^`K%_k7!7bZ|y{t?!QD zH_{hwFWz`oPHhjf+{+sak1s!bTifTvEAxXh=En-}TfuR^p?cTWcfbBKF6EqVq%q<@l@?mwb{$C#_EkbvNLAe=kUGI Vd9U*S2ryYOc)I$ztaD0e0sxUtCjbBd literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/jinzhi_onetap_back_day.imageset/jinzhi_onetap_back_day@3x.png b/ios/Runner/Assets.xcassets/jinzhi_onetap_back_day.imageset/jinzhi_onetap_back_day@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..3d3ebd4e98fc4a6c648fe8a608ba4c60c0bfcf75 GIT binary patch literal 463 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7Ro>V4UXZ;uumf=j|=atRoH#E*Gc0 zGirQaf1t>!abqgay07U`4gvfkU%yt>&N=#8t*)B4;XcC&-iABG6Q&FgILfE@^eaah zG1TptrXk9(e~-VmAVYo4zx7KQ9~`v4E~v%HkoQ=f@j&4p5r!Ro^BEYPf4s~1z;2&0 zgV3>ZR)pS{HByG%w%@Xk5T2(Eorzp!WfjK=%U{fzAhP0__ht1X>?(2{b?85omnC zm(V|fA)$8yQ$qIymW0j;Y#&%0U#;*~I#90c-8-M>!_^x_kC!v=>DRNYV{Z8JLzm$a gNddmdKI;Vst0OpjtaR2}S literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/jinzhi_onetap_back_night.imageset/Contents.json b/ios/Runner/Assets.xcassets/jinzhi_onetap_back_night.imageset/Contents.json new file mode 100644 index 0000000..7adef82 --- /dev/null +++ b/ios/Runner/Assets.xcassets/jinzhi_onetap_back_night.imageset/Contents.json @@ -0,0 +1,8 @@ +{ + "images" : [ + { "filename" : "jinzhi_onetap_back_night.png", "idiom" : "universal", "scale" : "1x" }, + { "filename" : "jinzhi_onetap_back_night@2x.png", "idiom" : "universal", "scale" : "2x" }, + { "filename" : "jinzhi_onetap_back_night@3x.png", "idiom" : "universal", "scale" : "3x" } + ], + "info" : { "author" : "xcode", "version" : 1 } +} diff --git a/ios/Runner/Assets.xcassets/jinzhi_onetap_back_night.imageset/jinzhi_onetap_back_night.png b/ios/Runner/Assets.xcassets/jinzhi_onetap_back_night.imageset/jinzhi_onetap_back_night.png new file mode 100644 index 0000000000000000000000000000000000000000..7de7bf77fd91d0579d48af2870f2c1baa3bded17 GIT binary patch literal 322 zcmV-I0lof-P)0XXeBmYfh}**y$tYdNQrZAWW`R@TWrb0 zIllhQvXqqn5&#N7u@t=U`gv^lN?Ia%sH*DjQYbY1N?NV;<1|e$#(Z>Lx0Wgdm%tgm zvDS_N(6;Tn*7`=^L6-twz=`P98(#*F<4H*HzYhR)g7k_3L1 zD3+2qF!N@9h*WHey+{~iz|6N%o@0p*V&*p@diKSl1hKzh-(_C=Wj>`TDcLXb3D(!J U0i!WAmH+?%07*qoM6N<$f|R+AD*ylh literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/jinzhi_onetap_back_night.imageset/jinzhi_onetap_back_night@2x.png b/ios/Runner/Assets.xcassets/jinzhi_onetap_back_night.imageset/jinzhi_onetap_back_night@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b9a8951dbb20ffd501edb58b25c45876f41cd731 GIT binary patch literal 598 zcmV-c0;&CpP)ey}D7PUHJlCx)c}U6$Dqljc=e2;sf*nT-=?4co$uE)fZ@!G~Z;>Oq-cB z{p5?eP~?hU@Xuv(eo%(cq41q^dZr0g3IG5A00000?g+ElELKB>nMeH^siDElXR@x> z>nEpT3~Kl!NuGP}$r$rat{02NJrz34d@k!|vw3E%t;@1xA4M-&k$>Vm5j8S=UDuzoEPEJa z8S<~4zgjMr_d^~2?01~+V;@%eF`QR$-okkc=Lya;oL|Cu4$}Ep)-21O?smJ*c_M1% zH3a8l8H$K5nx@%TRn<9P6h*t=?+?zok3{rHZffq5^P@lfdEBpZL*GQ-k!um-{bVvR zN~!ZGidq#S+?QXT=N}~UMC7#AM{DiDdvDS-eJStH=ksn~aBv@QiMrPMsu#f%k%+)@ zBFM?m?+sRjk;Gn_UK+m_p^-k26G2V}IU$05%5&QA()iN+*GZ7y0z*ndEJ7d&3Q35O z1V$1RlAw@;4kSS#3AahYi|f5=NJ$`~<9551BsgQto4+Z-Nc~5mC_2hu)9JKv&b@Zd zeIAd;68VD~5`2<`qA0$$ZOh(!9sF0|hE9l*BzaKR_2p`{dKGjD-o%gp0SNB7;cY}1 kV4ULV;uumf=j|;|uLBMYE*JgY z)!(?Y;La|AUXE)&$|V&7_&2?JT{&-a#oZ(M>lr^tGwfuXKmx(WAoK9uq>qIz-fRc> zuL~_@dNBQarYh5e{`3F0nlS9Ccy8sS%6K66j|ziD-+U&9>mP*~9@y-&X1H^_oXz3T zk97CokICWd4=#r3mjx%eG?=?8-%;ByIp=~1!z#fLhAhD;3|fL$ z7+wj8Fs>2^VayVk!l)&1h4GP~48tP97=|RlISfjIcNiWC$S^Jvh+#|;n8T4E@O1TaS?83{1OUz9o$mku literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/jinzhi_onetap_button.imageset/Contents.json b/ios/Runner/Assets.xcassets/jinzhi_onetap_button.imageset/Contents.json new file mode 100644 index 0000000..b040bcf --- /dev/null +++ b/ios/Runner/Assets.xcassets/jinzhi_onetap_button.imageset/Contents.json @@ -0,0 +1,8 @@ +{ + "images" : [ + { "filename" : "jinzhi_onetap_button.png", "idiom" : "universal", "scale" : "1x" }, + { "filename" : "jinzhi_onetap_button@2x.png", "idiom" : "universal", "scale" : "2x" }, + { "filename" : "jinzhi_onetap_button@3x.png", "idiom" : "universal", "scale" : "3x" } + ], + "info" : { "author" : "xcode", "version" : 1 } +} diff --git a/ios/Runner/Assets.xcassets/jinzhi_onetap_button.imageset/jinzhi_onetap_button.png b/ios/Runner/Assets.xcassets/jinzhi_onetap_button.imageset/jinzhi_onetap_button.png new file mode 100644 index 0000000000000000000000000000000000000000..52e624bfb6f3664424a4bc6148f10d8c7eabf126 GIT binary patch literal 2043 zcmZvdc~lbU8pd%qlNi#J!cWjDzSG+R zbm9YRcbvBAzHzUsxMplM;ejgtiBE`aZ=+rPlfOt=%!?CW6mz|q?kn;7OFRM@1-N-n z+iHUZGjD4ruM?@p0HoX*DMM-3@`5AHAsXjB%PrvU;kvqea}`$cwcTX_3K$t=yG{On zK`<9``H~<&r`6x&cDV2l!pc7Ffov55AgJ#2m5-_)r0&bB+u^Pigl0uemP3Bl8J6hmmzz6t ztMF=1iD{nFw=bjQMSU5iY$PADcCl{ik-yU|B{oH|)tvAv|G8}jT;vTS5O7oPI&$$_ z&Y#RPsMp82T@gP_Y4Ja9+937Pi4(4MqViuf7dxAX*WRr}401tXDs&~U?;K5C()Ba* zA9y24cOLU(5@&4#B{WV!pL`ekL1OzQqITx>ovU+Tqb4PTO1ThrDy_Q3jMYY2;ZVy< zP}HmG14qry4!16LGlrL2{ZctHCzGfcFH_#bHLCC)zAf}WvOh>zqT$O%*udB;IGbO% z^Wz>S>>o=;Az`M|Io{|Kp<+804T$R%?`IViMLUyc3MZ@!TH+l?I-m~Y9O`IP_og#u ze=8yOZJZY0bzd3M-?qB=d_)Q_`0m<;Sq6=QH0M`58lu~gs1^cD%Go*OGYD5{{er8n zY&SHE%tsN8FyxPnatb~P#tjz{{Kv9xO^rY;TKfgWND~dg=ZqO$>N9yp`Z4ol{)?9d zn}wP9oeVyUnTp@dFfN}t;obk+t@b>5hu)W1>7(ZFy)OPm`+92X!RE*24(C-^JY)ka zTYN#Q9TAPs3@3uBPmZ)tEP0cvDMAZw!x_9uv_Q%vIb8@XpYC84^l~T(If}`^oM5$Q~>~HQG8vR zHt!`+j&wS&-Axmhxuxx1|KgU}v#iC?rdD-3RSfSc_W` zdn|0%PhCZv!CJ!I)xLqS`oin4S;0kft)%4QibMx^BQ7%hnKlb-1fIVQ94@lo+ILQt zw!|Enms`Rc2fq@$Z(6?j#E)%x6yQ_2z)Zu(;>(}3&i*sPQ!5zVZu(6%2DCu3&$WWP z>l$B*UmkDaaO0Y+_SXy?)P;-I|E)2MSq_SuK7Ie~TV&-xTp;>{zl(1*UkhBM)U1p8k*04v`20-*Q;G4bKlwi; z>Gl2XozbeQoZyY?nCwtU+;L9d@?sG)Iqh}X*~LWJN3 zGZ7Dk3N{<0Xj6J)fQPwW$n1L)G3XNpVnG1Z>z!gF)#*+ye!nkqjgw=v*a3kpJ^z#OtkY?#XP6}g7i_-PvDUcrlv9cY~o->e+bJD=u52Xp!7wQ+4{3Rl$su~ zW7Qw=*1>E`kF8=Q<7uWwP^p>&Y%(Qsx~e(v_Ea`Qi+g9d?Nh^cYdB-H6FADVI6DR= z*W~7%U(?i}=r z5L+5yXRUsLE&{$ZexoZ|{Qm}@Q&uUtVaQ7`rZQ$x_WmOKgx#F!0DzxQAiC}#_R_xq Di!k^M literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/jinzhi_onetap_button.imageset/jinzhi_onetap_button@2x.png b/ios/Runner/Assets.xcassets/jinzhi_onetap_button.imageset/jinzhi_onetap_button@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..cd2077964ee4570c9500e0175401992158246852 GIT binary patch literal 4337 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 Y?ea}ht_AlsF4HQCBc6XKrghI@J z(3?ti_1a=vFrbkR^7pS{4&;0P_ z&3WdWd5+^N7?1c7aHEbQ{eGUjv4fpOmwh;14jo-+Q5nF+x+Yo-{;0+vsQW{x6&!^1UNglp1ivim;xUN_nUnoYu6e_;DionKc5I50omn_($OeIg=H zo>+FOu?^pu7?)}ej@TD>vhVS zW$m(tS<9BTZK>r!a}ytsSt%QlleIy1&)%Zr9F@oR9}p2)BWsqm%Nk}av!+?wmY?AS-~mec7(b~g9$kMud85B#XM zg{oc2O7Rnse$;DQVXd>~rQ60YQ+5C0FSQ0c7g_}OfbR#3h-_pLLamNpnCEKT%D3}u zhUZ+yvz>*MN5xM>`j$1$T9;)!8)taV2ghr6CFfulGZhi(bJn`lJjZL^1@`tn^?T^c zNQ;PUU}>SBwa*h7iG^l-qceICyh zAkBMN`@D~Q*j=FIZAr9n$hX^e<$Y>|*v(?w8kcHu?N z^10pIY})ik?}w2QTyrn~>UQ~YUd1{4lAMUh24^j^rdivpajA99vTt`sc%!2fX+q=` z&a`HDzdl4BBb{}9=OQ9&U=6dDS<|d-);Me3;{D4fI^6hqvgUre%|G$Gfo;4#dy9_u zRMzq)L_{995a9v`Wi3!}oLADQiep4G{_nq5x zoKplvWaEtdwrr=eFw38313##p<@UrxITO6}xGzm|EFN%dFaMrxaiBfRxq)p|()vKH z5fqUpS+7&pENhoF%vxr5EstNi?S9W=GsBA?6i!~`c(u+?x*h1Y={iSwF&Pn&CquNQ zE_szauRy!S`(t}Ky1Zq}JuqVFbQoOI5hgD%n$4q^Cpoa z)d8yAHgp#t210L(CHvcU8rJAgMAn|WvMcE)=kaz$m%Iw?Iodc*xWIew?BVkAR;^@J zfwEKL)2H!^>u4q~@j~W#BRUSng6H!Zb$i01NE?n2Y!#srC?adwy{(cqF()gx?y$jD z%Vm7#B4>)gsj)p=vqPt*$POP~dDOSmSIU!}TaSQStgH<;8#~xpblHdF<F2h0+)7g^W5+iJ|XgPmUChL7FTV(vK?k4zAKa;*RA$7{tHWOCMja2 R>Zkw!002ovPDHLkV1oKN8btsA literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/jinzhi_onetap_button_pressed.imageset/jinzhi_onetap_button_pressed@2x.png b/ios/Runner/Assets.xcassets/jinzhi_onetap_button_pressed.imageset/jinzhi_onetap_button_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..aadbfd8cf21f80c6ae624892f21346ec98b79867 GIT binary patch literal 4360 zcmZ`+cT|(vw+)Djpr|8F5Rsn((q%-YCQ6mwOF|PV0V5z)B!(g)LmvTU1VRy#&_YQF z2uM+y0-+NiRFw_^lmJQyyf4hmTkoy6-alDc-#zE*l8w5JjtFL{>DkO_G>HN@P?oG${X-0N{M|%%sRJMYvijzND zI<|P=hr$Vab2-^pf5Kw%D9bsl0Dg$OsyJBO>h-9E{Ryv<2Wv$14B#B`bCx8FK?TDNxs*n-tBiZYf<7Btq8 zS;u-4jXHg6jeNe!6wimd{4R}Tl~|0Ut*$;u?IlTB#rgY3)jtJ+ zDvGsra=M}oV&(#s4cwhPovoJ}bn~WpwL+Q8a-r~{qU-~2*Cw;D4OCl^c{E-Ah*HI) zICGyp75B~j-e>D%CiQ~B%=!Wp+2F7K((EKm z;V4py+p6M2suD}y3tJgGp;H2(^HgtDB?zb7u?}Bb+QdE0jb{skc4^bnwfmwj{uW~^ zBTM|&b&|T1v;s0d=!e+dAgSR=USz+@QASH$lLL{=`~(4kt_do(*>k-s9Fpdb1b596 zUZnA*>{uXSVg@l;gO;6JKev1rG5!6uJaL^ocl|zMie`>}llS~-{CO+D7|IsP&JfKoWFLOkn4``NIf%h zH1Z|4z%#>(HvImUmOmsvuG>=iuTKi+H&TQse3R8y)q|piHfcHW8qZFHK&1s&5|;5E z9y*3){VCMzp(839OAj=j9+0Wir$4+r8;x-iavJC(Y|-{L!dw+R?fd(7uAqpDrMe3t z()Sn{IyugrD*%`8JX@9KxWTql4wr-AL$BzAgc4EX)z#>ky%(^XY|1w!AmAxsWKu(J zS3GuqSOq2NTil-wu58Uzc^%9KYL@2vHo;YxRztyz&(tX{za->`XO0%_47?cgtBs9q zbLMxVgEE~C1Sq#+nAajKzG1_I3BW2 zt}(a3+*Gs92||_Y$j?=UP(w%$w|5rWgw$!F06411o*IAIp|z4`i%A;tMm^r) zF@_npU8)fj*8Z`HihB8(H-z-c3tSqm0Nce8WXRQnL+kIS0myqd{2D$$!D@I_nX1Z4 zUC8)mO116vU4aEFDAJgWE+fq3_<^S%#t2X&dv-L+5)qIR$&41N%4XiO;4GR(I|_h5 zYs+1H|8e7(JNkUXM!zV1D`u_#WmuFP9VPH|FV1*x^*CfB%Lf*oxIK4@roR7SB1Pf* zaS-Uy)O?0Cv7JC6%oDZ=$B6v)8w~l`%-wqPRd(14y{b3R3$Dv&*a%2zcv;t)>@t@} z>EEteqXyJFIW6+IJZ}6hximmXUE9e-Uiclbdi_kK$X3ZR0By^WZ3&`&(_ek*BiZI` z|KUmYEE|9))|zWpWr0Nh(Hxd97Yf>*4q1INIVw1C@LM?G9hKa?R=V%<^=5;={Mp5x z?JNl6;3wD-#v3Xw6KIUoCBer80KP71T1^Vs*rbP+$Oe7;87x8yhhzq@Gsjw|(`NO= z*U{OXnRQrH*3Tm#kl+=BBI0+%b%YY)2BLa@W-Vcw;iVuLUiP@Bo6@lRWkbA<#C$2e z9t#11BJL0+h&PG4L>r<9F_=-cuI4JXefsPz4-oYA%GtdAFCl&pji5J z`$(eEQz+!1D(bDN8ruco)EeK3&G-A&f|Pt~JuwamR!RcGhtM|>HA>CGYN!SDHn)9E zXQIw8)xpa;hUu>{Unhu5fZe0BmHz+}Ul3ob;Xp>NE#|{MIl=g`+$LX9%Qh^~l@akz zEk7w*Q+z0oDE^ed96B}mRUYladC~NhiM&&Y4AsR3`SQ*whEoIr5V!eb^!vMpAJ;|J zJqYzh@lT`hZ@E@%7<8x|)S>Qx0v0CjL$2Hx| zi_+kqgqv_D#)<)0+umk=ie)x;$)I1YP1d$Bs+!iQAMZT&0K;hjklQzkhX$ z`4*$jq4O1p_uj7xU`Ina+hqnNxahk{82R&HQ)NS4qvvu>p2Y|Hp@|6_s*JF@$bC+Y zzPl$i6MJGNEjqiwYMnJHI##sD1CweWM*V>0=^A2ygUg-i|lCoW^N#u9@DgTo3I-jPxC21{GSLJKQq; za6|NsY?9M~$_Gh_h;PTO-ns4u;WDyXcc!YI} zjQ_qUQ0&EL`Ml5lahVOs&L;A&n~}=n9RA8O1)r{*0qUZSKq1Z(w~0}?2aCiisplXL zAkDnet@(`gMFR`(t z9#Gc#yHX&P#*Pa?mxv&@%fR<$1719!RVj0T7~wkPw4lt*id&q}PGm*iYYEylIvC70 zmy!~uA7uwt`rRp^l&9OVwrR+Y6>?ok%@3?YT4>Bi0Q=q;v6}d|-}dHonDwvxTg7RE zsXEsaIZxaM^5XkQ?fF;5>F*e)jW&Y=#~=#{th)=~T?#UvVy%Kn+nf0&K?(kKR!wWw zLAjooP0$;509rPH5=aTAgs|`_VP4c*`&oo4@zJHGI5CxlL+$5!GJ5`jP+-yVWCrD@eC2o*$~ zB`$p4HC1E$tU6eJq*hCqq7>AJbaZ+pnydprI|OPv-4$DG_$K1*1ui+=(J{!3kfg2r zv>O`Zu1@OGpg&fH+18aScJs32hyKC!@2tnQPkZ4)gEi^11%!8w$sz}42P3d@b?u~R zfSq@C&=M#SS`Tf3c0mVG0|?XlQshj;*XNd>9-wd!S3J!N^jiI7fyQapX%`~H$QfiR zS*QoL7FZ7Xwl?*7RHmcSd0AL1-LqINUs`w0(0>ky)$YuK)r}Xgdc$&G#wx5VFkh%m zuJpdEyxcaekTxz%!flCa38!@wK5$8AHEWxPw@0D}-h=Ex3&#Guo)g-bL*vR$*-I<% zR#^TuFEpvDhNm*7TAl;(UK126ya>aU1~@3JHCfjr(zDn2!Cv1wp5}yB#WzGY^cOG_ z3hPUfrXJwU+pz!>5p2G@cKO}ZZXkHt!>{Y5z1zfF8HA2jT3=3AlCBm$KM_k1RK5rV zGNVZZ?lJ$K`^TWCvx66XhP|KE;jVvGggu zpXiL%z~PXi!sCh2NS~1|Nu5hw9{?f@domDVd(c#jvFO5?aPH9e=A^F~2B{_0S}T~f1fCe!>D5MSNTot{uSc>t8Wi?0X2VWZxNj^v-Ep!HJsduN zDkz46!*}tA4^M=g10b#A8u$qn0hGHG1BwyFgknaqpjgF=gu|BgC-&}(An%OFy=atN z%1m^*q1u5l!<3JOebG5>4wO#3g^{WG;Tt4XBFs@AB3HlL-)cg0E-spWYS_q&*m}^5 zUCA+HMmc-gcL(|=?7|Rswt?doV>W@+nc`T%D#ZO*L0~TOR@T^Sis`!lpC?hn22rmr zF`-~?M%+=V;a=Vi{<#{H&uGpMsJj2~QZc!X;E{!RtW|J9ajKJ#VQbG;S#QdpmjKzi zw2Z#<=MO}5fqOQwL%wLUrN=))yVFBg_i3RuqG88%c_ke(c;sujFWN|Ph>t*;+QYt# zln=@k2bw0-jq7LHugq%wxolBfZ{di8Tj@CWPyFNw2KQz;AG1Y2CW}T#LE%rY57#vstX zrrq!92e@`WkIwv=2Z02#wA58iLlM*=_zT3k?c#Fh;<{qzulX{ct5rzR`xmQ%)4WK7 zvo@s5`l6EjqMTSe(LJL=+Ns7I;zGhkhknivbgeyYdv<5P|DJ;!_xm%S-ygJY(kI!> z%W6sAD$z3txTvO04iIR8XSJ;=Hs&w-1S9Cp!GyVnUoR+_zpq||xP}C0M-6W=Z4sJA zFQNDK$!x>;@#1TvJJ*)u zopz*fS?ldAg-sq8-#$omrsL{^R;o#dV4sn&W-*vNM?~#4y6#L+RanDhMr2O2D)Rah zxTxZ>>x#5Jg9ldH@MziTh0wYpp;T4(V2-9)n;a9DS+XhDvCTG+Z zotNE?jZ)A7-WyTMEOk;+qE|i*bJVQ+ehgB3xo+1{Xl(T=<>vNV9BSbH&H_R?H&p3Z zy)yj?G|;oBp(-Uy@;ITW`ps}sg{*f4J|o@!|1N$xOe9cswzOOUk@Cc z^j6@)C}DQO-J&)NWBCD9ypGqOwte5JKD*+sAyvATZdl`LcB^o#W5(xhULz?ek$2sB zASde1N~-bg7dju}#kcjDQEc}kRRz9>vOrb~x~p(mAoOJI0fY zRW(>qSiXLaydo6yMdn&^@YkEmUW)JAdel|s5W^XeptsCWa)TFX(~0)a1m`YHH1@=( zzgq&i%4!jXYA3^_IGBER)5)1~v$c+I57fmpG*7=w+5QYkyZ|$qq_z3O3?RL-f?ubE zPp&Q4`naz;M4n@jk&#y`Z)g-fo9B}1XdMSPR?VH~VtNPEY-6JwAOQyR*ck3VG2HhA zbJsKEqsFgCgedh!YN;5VF+qa)iMiyKc~EH#e36CZd;LJQx|MiD-UnH!pi_OXX#A_T zL(J|h`nfi;w;_+Nx~#xTW{T&~1}5B!T+^W4ctV?LgG3XrAzrAAoY#jRv}d85=6Nr7 zGFboTfNb#%jE_78xp&P5N%Ea`XV zvvs52n$Yyy`*ty!Mh=M<=^9_cqOLzq=8qFtpC^c=%TZkYAN@o35+ZbH=fP8TRZLI# zN!C(#^ekq1Sc>mrZ{mJo_XG`OYS zqIdfm@23jvSk_VwOCt#StHb~KeiyH2rQth%lVryCWD0sL;i#uho*eDN!^S^4IoYw_ z7x67OYv~F!3#;xretmIiZq894=r!X5w9Dvan`O+hJt)pGj)AM+GzWjIR~p$rT&zmj zmnvRH>%~P%l+N58(ziL@(Z|k|Sa;u)t3Sp41j2okF+1L(gFfG19UR#fSWH$dBPJ%! z-0?~nmfgvFZrG}jb&zFCkfz<0lL&K53i<=M^dA4Is`dPu**QV1bm-7n762DDP);BDj_6T64C>X8`7M86;MeHW2@1D79Gn&hd@v32+v4RQ>2frT4AdhwI4 z@n+d&>}23npB}87k}|hUCtT1Rq6IDtAeYZRHauH z*d)hLNnGyJL(2-g)tcfsWG>tr;gvu+Zx^M`UZC%G)aHk^g4JCs9V-(nYb$4u!zlOH zvb{KCOT);ovNI@Qlql*F>grg|$XzJh1#LaI4^wcq z*OpGjbxO&n6WlxxvqVp8sTyCe)|>g8z-a1g$3;mR#0NtK8gu)%pw{#|g~eW8oQCu_k8T;I!#&vn?43jp%%hZD7Yo;)Yv)s9Gdl})^y7DIz@6m=o3d?uBH9s5M(;w~!2t&Tyo=C&> z#2qJ*>ouZ&`^@(=v@21>ibAHWoKa=OSC|r`tVLS+UgjY&P1J=$cboV z2}U1wI_x3oq37Y{k?4WKjS?~ATC$MgI&+t?>kW8gVvAL!_@k#l^=fLaIEB58mBnf% zqHtf3T@tXA#I$S^U)89WW>wf9mJFa|41^N$2pF$|@o~|}K!rqYH)Hn+oWr?yyId;-h zDx1r^&gYQw^ZYC*X|9Yg@`G!GE%fZ$ zA=`iu*Hdr_wuB|6cmz5+KLl&$dn~euXtm!d3-0$|IK7pqWHw={+)lHtd1{@>Fdc&E z_-rQD%vm(Lo8R1{?E8)%SKNC~+_@y(Wl&w09a3D0m9E%e>=Rp3l{9>GMWtK|)4z&Q zMiZ05m_Azcis{63xzTK(O8F|Q87?&(FP-Gqj-a%7_sB84;2j5-V!o@CYN?nD5<@ME zE=IB|Q)^~Fsb7F#73@yVS*u6#If;@FcE#UZC}nsUcSBcsT`Yx8>Jm z#*2JHa3D=jUzXC3b?(g}e3Fj%R2Zd8!+*_OdWJU)biSI}1X#uKSc>% zem*-BWFS1t47ozHFAYMbJZ}$gVY^z*Q4i`>R}~aQdMx(?oFpC~Mn{$v*bY@|hor+} z0p_RGRmCey!fTMuj#WKF}@IPJcAUDcstPvur{*fVuov& zEBR*oXK}z4j<#)&fh%DVnKLW(s5@*YJ_$b)Sl)~!U?;I_^bn=r*4)_;+M|9yvs=tF zEDV{whoCl4Tet&tF1eki|23so(&gyA?}JQk*4xt_glfVk0&Z=9M06rDYov?tL3S;@ z&!yTG4s{&;%o2(Ib23)V>Q$QpEV2Nd-57wK^uqWIC>Lg1no<5U;Ey_ZK@*`UXgicj zR+w*{5mz`*(r+cr%N=APG-YOUd6_fiZC#R`LHu?^d4BHNnse-E6?J2;OOE)O6q`P5 zJT4T?_NXw67NP!Q#MHU|&@0%|>2JyYJM02LXeAescxiu$;Xs24C@8xLbDYylSm?pA<@BFe*<`%fV_H<>99+9?qt;?5bN>- zdf^YU-h%N5YFrsz?wsENc)U0P9U7=tH6JMM^x^r>XGPy9Bl0tP|GG8;CI%7Gdh0ot zE|i zUY!o(kYRlp$-4sr(oX8o|MejF@G(I4LOY3wR+Ue8H9iom0;~e%f89m)DR#C~m9{vj zaI}df7v1fI5;Rxd-{7#vhB7b5!Ftw&J5*x5KPoPwiS;Ym2s==3zx;UyD)nqG*K#lW zD7{L+eGJRSPfi4$Ke607;Us8nMEP6a`E-y^43>l|)cj9JZDt&+xuyUkVY z7phHh+s**s69ikGQuRoXbkbaC4QfYMT<9@7yk6}q7x!oL+$KEIj-2vn|2cCXG9ki_ zqyxU<{DSLGSzIaDAU}#v*9GN2|GrzQtj4m~v=H#y+jFJ^kLvTI9(EQxyE%ES2?FRN zdoKY=)kGpHSg#0;<7+kS+v{MmsMfep?VA9(uPvDb5{u>`F?j34c+6aX8jYA{ zC3Nz56H6%i{e#_N^lxJEIe`qqOKTS8PB0!Qp3j_n$%c`zi+Ye)R}}`|@9#1~7Lu0I6w&TdN@NS|D9XZu((kkUMFTq?s*&w@kc>gph1=1t9 zi3UQ};wlsZHHTV2edFk} z_So?7_Vw<@ZA)rNKkfTJ=B`_hYEJtK}Sr#J=%j-%dC zY6fT@_&&3EW{dt}k7v?Zv!^B$({tXPGdl%uh2Sv&$$dd9 z0his{J*XbL#)MZ-<$|NL^wLb?U*GiUikh@#Vo2#5gHA)kw^^0~O%;|yu)Ak@;$gDl z*6c*U!VDIclQKAvN+L4?M(9{%zw2rr`Gr7QZG&MSi=8& z+f&PDkKtdnX>`hW$##)s*D}H8;wnunph3y}@0wl3-d@$8A55;(i1>^L4bfLvI9w1y&!VT<)#M?6-7AFccj7GM3s%U~GUojTZ#FNMTy9FRAN;N9OijbDJXSU-o+}^-nO^|B zOxSMCCw)rks6QJumI#aIy$@e62}deK5g+XJoaYu+Dv`OGrctc0l7xS2miD;3BDDt4 z5PFI5hLA}>5ON6b2zjN?C}sxHTLP;18B^Ka`(o=UVIHK1hFm1UERO9zBg3~3QdT{J zT!XAvA;L3qMUa_THE=VAx*uEq)9@vjF22SY5@`fl=$dAGpo@`_hetNFew5U<3c&5; z2-0FsH^NOHrim%%{)DL)XXT{lB1}K-1mGk}r}6qa8s#B znudJ(nZ3Q*m&L|n%%Qk~(4m5gf1~`D(se^7ITGyP$$_cG=P(JMEcctMk_Ub~?_#7kfM_Ia>mJX=Kf%C9=;CyU8cpUZ} zW4Rtt%hYR2jK|jD%=l{6G0@JdAyQ{kfFtD7kH_!o<2yWuBleg2=S!QmU=H6xW4*L%L9{YZm*{J3>%#6CB zYyNEaCu*aYR7*EwG?W#D)VLxm4F4cf^g<0-2+=`r7z}kSuY^9YnR9MOfgsyzPF z_;1KQpXurWy{u1Cwqp%D0SwOEhf$gCTVKi!@qfAjnEeUF@C@S1z^O}N=F;hL3-~P* zBVwydle(^ys%PuJJJb@zSzH4u43_HZ@jzyRO$cn!Ah2Bsi@;Ti!SJU*x( ziCZVLn=X+9*TW?}v$0uV1Qr3##%6T~BBPW>)|NH>+HU#pU zjy)ZIeVbW<7*6f4LXlHek`BSw(Q@C<{#pd`O7q@edXYU(~%HZRuzA)PoXwh)#~dOFp-L0 z<@daRnbU((8^_9JP_%;j4jt6*TQf=vh;7-6j8a?Tv~SdbFpn$l@R;~3;ag9Xw?|!C zm{J$C+{spI0p+kheN6XQJ918>vsvC8(r2Bu04n z14Z-h1%3aq0pI06PIJ4r{sx4>m?%WMXSf(5J0a=MtP5a-kJ9fiG5Q42-5-$>K2!$@ zs?lwpHbke(>%E=ec}%D!PuBnYkBrn?q#BVVl@nVb-9z<0K#u~s@be;6NU&4NC%Yb1 z9c$-XoU{Bahga2JN=L~AChTR089w?|I@xZ^^sXFLm=02A3S8P6=KX09uJcDX!~o3e zanHpjqxQNjNx2v*VMd(}4hl=3d5)IM2qsN71phwf!E(-NuIk6N|NlQ|#vCD-^n`A5 gmPoQXO^Uv=XZZQ8TzC?#c;GKpCo7I_?JfP1oBDknaPn)lQWtJ zBgP@<4%VKLTxd`O2wD|%2OY28d}vUE5Q6CAUF^Ga6gea$$+aMQk|H6=wV+pUOUe;N z5ThiQf~X;&etw-Rh!o|x6GVcSbN7O%Lk@R)TnVy}<3_E zXD;c7_QVuivOWL(<3s#1Um1c~jF#$+VqFMmDMxkHs1rf0<*4ssbs+E#a!i)hx=HY@ zxB1$Tw39@$#~t-a!sGK!a#ZevJYaes{gEvPte(dh9ng}oiEA+ta1(ufr&ZCW`_y!G4w@67`M001Bz$}in{ Vm>P-_xTOF9002ovPDHLkV1jcK%^Ls! literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/jinzhi_onetap_unchecked.imageset/Contents.json b/ios/Runner/Assets.xcassets/jinzhi_onetap_unchecked.imageset/Contents.json new file mode 100644 index 0000000..92165f0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/jinzhi_onetap_unchecked.imageset/Contents.json @@ -0,0 +1 @@ +{"images":[{"filename":"jinzhi_onetap_unchecked.png","idiom":"universal","scale":"1x"},{"idiom":"universal","scale":"2x"},{"idiom":"universal","scale":"3x"}],"info":{"author":"xcode","version":1}} diff --git a/ios/Runner/Assets.xcassets/jinzhi_onetap_unchecked.imageset/jinzhi_onetap_unchecked.png b/ios/Runner/Assets.xcassets/jinzhi_onetap_unchecked.imageset/jinzhi_onetap_unchecked.png new file mode 100644 index 0000000000000000000000000000000000000000..1bfff56e2807e58354de46151e410cd9db487c73 GIT binary patch literal 369 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@Zgyv2V6^abaSW-L^Y*r*P_u#nYv6}H zCz<$~x}WSjdC%zQBOcX+?~Ic^itZ?KQczM-+LgZXX#ccNzgoIa{e1b$r;u&Rw1`4C z3I7$UK7Gk^jkoZ^WE1Ku_|IE7Q zdHRfnoX7I@5mGG2t==mx*mO~j_xbfZ?tT+bdsjVU*u*r|bKUiu*~d7A7*&`&SSD~N z2s$V=xG;1wkR%YcV9(E#u-f)J)wh3MRX;cfXo{Re<)rMe>b*Yd8L~Vt-|T5`{M7eN z!=t)b?(X#!R*sbpD%^dyy{q1eoJ`jHb~I{T$}~qaKHcn@-u}|Z)^0j;^4jK(y_LXl d;4**9U8Yi*CH-t;JTNF3JYD@<);T3K0RWGDlk@-p literal 0 HcmV?d00001 diff --git a/lib/common/tracking/umeng_service.dart b/lib/common/tracking/umeng_service.dart index 5126676..4d8a20d 100644 --- a/lib/common/tracking/umeng_service.dart +++ b/lib/common/tracking/umeng_service.dart @@ -29,11 +29,17 @@ abstract final class UmengService { static Future _init() async { await DeviceHeaderService.to.ensureInitialized(); - await UmengCommonSdk.initCommon( - UmengConfig.androidAppKey, - UmengConfig.iosAppKey, - DeviceHeaderService.to.commonHeaders()['User-Channel'] ?? 'default', - UmengConfig.androidPushSecret, + // Keep the carrier-login launch path independent of UMeng Common's + // network initialization. Waiting for this future is what left the login + // overlay spinning forever in the base project; U-Verify is configured + // immediately below by initOneKeyLoginIfAllowed, as in Yanting. + unawaited( + UmengCommonSdk.initCommon( + UmengConfig.androidAppKey, + UmengConfig.iosAppKey, + DeviceHeaderService.to.commonHeaders()['User-Channel'] ?? 'default', + UmengConfig.androidPushSecret, + ).catchError((Object _) {}), ); _ready = true; } diff --git a/lib/features/auth/application/login_launcher.dart b/lib/features/auth/application/login_launcher.dart index 28fb4a0..3acd315 100644 --- a/lib/features/auth/application/login_launcher.dart +++ b/lib/features/auth/application/login_launcher.dart @@ -8,10 +8,8 @@ import '../../../common/router/app_router.dart'; import 'auth_controller.dart'; import 'one_key_login_service.dart'; -/// Shared login entry: launch the carrier-owned authorization page first and -/// use the Flutter SMS page only as a deliberate fallback. abstract final class LoginLauncher { - static final _service = OneKeyLoginService(); + static final OneKeyLoginService _service = OneKeyLoginService(); static bool _starting = false; static Future start( @@ -21,71 +19,95 @@ abstract final class LoginLauncher { }) async { if (_starting) return; _starting = true; - final dismissLoading = _showLoading(context); + + var loadingVisible = false; + + void showLoading() { + if (loadingVisible || !context.mounted) return; + loadingVisible = true; + unawaited( + showDialog( + context: context, + useRootNavigator: true, + barrierDismissible: false, + builder: (_) => const PopScope( + canPop: false, + child: Center(child: CircularProgressIndicator()), + ), + ), + ); + } + + void dismissLoading() { + if (!loadingVisible || !context.mounted) return; + loadingVisible = false; + Navigator.of(context, rootNavigator: true).pop(); + } + try { final observer = _OneKeyLoginLifecycleObserver(_service); - WidgetsBinding.instance.addObserver(observer); + var observerAdded = false; late final OneKeyLoginOutcome outcome; try { + WidgetsBinding.instance.addObserver(observer); + observerAdded = true; + // Carrier-auth initialization only begins after this explicit login + // action. Keep the loading indicator visible while the native SDK + // determines whether one-key login can be launched. + showLoading(); outcome = await _service.start( context: context, verifyToken: ref.read(authProvider.notifier).verifyOneKeyLogin, + // The native carrier page follows the device, while linked H5 pages + // retain the appearance selected inside the app. + appIsDark: Theme.of(context).brightness == Brightness.dark, + nativeIsDark: + MediaQuery.platformBrightnessOf(context) == Brightness.dark, onNativeRequestDispatched: dismissLoading, onAuthPageOpened: dismissLoading, ); - } catch (_) { - outcome = OneKeyLoginOutcome.fallback; } finally { - WidgetsBinding.instance.removeObserver(observer); + dismissLoading(); + if (observerAdded) WidgetsBinding.instance.removeObserver(observer); } + if (!context.mounted) return; - if (outcome == OneKeyLoginOutcome.success) { - context.go(next?.isNotEmpty == true ? next! : AppRoutes.profile); - return; - } - if (outcome == OneKeyLoginOutcome.fallback || - outcome == OneKeyLoginOutcome.unsupported) { - final target = next == null || next.isEmpty - ? AppRoutes.login - : '${AppRoutes.login}?next=${Uri.encodeComponent(next)}'; - if (GoRouterState.of(context).matchedLocation != AppRoutes.login) { - await context.push(target); - } + switch (outcome) { + case OneKeyLoginOutcome.success: + if (next != null && next.isNotEmpty) GoRouter.of(context).go(next); + return; + case OneKeyLoginOutcome.cancelled: + case OneKeyLoginOutcome.busy: + return; + case OneKeyLoginOutcome.fallback: + case OneKeyLoginOutcome.unsupported: + await openSmsLogin(context, next: next); } } finally { - dismissLoading(); _starting = false; } } +} - static VoidCallback _showLoading(BuildContext context) { - var visible = true; - unawaited( - showDialog( - context: context, - useRootNavigator: true, - barrierDismissible: false, - builder: (_) => const PopScope( - canPop: false, - child: Center(child: CircularProgressIndicator()), - ), - ), - ); - return () { - if (visible && context.mounted) { - Navigator.of(context, rootNavigator: true).pop(); - } - visible = false; - }; - } +Future openSmsLogin( + BuildContext context, { + String? next, + Future Function()? onReturn, +}) async { + if (!context.mounted) return; + if (GoRouterState.of(context).matchedLocation == AppRoutes.login) return; + final location = next == null || next.isEmpty + ? AppRoutes.login + : '${AppRoutes.login}?next=${Uri.encodeComponent(next)}'; + await GoRouter.of(context).push(location); + if (context.mounted) await onReturn?.call(); } class _OneKeyLoginLifecycleObserver with WidgetsBindingObserver { - _OneKeyLoginLifecycleObserver(this._service); - final OneKeyLoginService _service; - + _OneKeyLoginLifecycleObserver(this.service); + final OneKeyLoginService service; @override void didChangeAppLifecycleState(AppLifecycleState state) { - if (state == AppLifecycleState.resumed) _service.onAppResumed(); + if (state == AppLifecycleState.resumed) service.onAppResumed(); } } diff --git a/lib/features/auth/application/one_key_login_service.dart b/lib/features/auth/application/one_key_login_service.dart index 5a43d21..cfc8f03 100644 --- a/lib/features/auth/application/one_key_login_service.dart +++ b/lib/features/auth/application/one_key_login_service.dart @@ -7,139 +7,286 @@ import 'package:umeng_verify_sdk/umeng_verify_sdk.dart'; import '../../../common/config/app_h5_urls.dart'; import '../../../common/tracking/umeng_service.dart'; +import '../utils/one_key_login_result.dart'; enum OneKeyLoginOutcome { success, fallback, cancelled, unsupported, busy } -/// Runs only after an explicit user login action. Do not add an availability -/// probe or `accelerateLoginPage` outside this class: Xiaomi rejects that as -/// background carrier-auth prefetch. -class OneKeyLoginService { - Future? _operation; - bool _authPageOpened = false; - bool _terminal = false; - Timer? _resumeCancellation; - void Function(OneKeyLoginOutcome)? _completeCurrent; +enum OneKeyLoginPlatform { android, ios, unsupported } - Future start({ - required BuildContext context, - required Future Function(String token) verifyToken, - VoidCallback? onNativeRequestDispatched, - VoidCallback? onAuthPageOpened, - }) { - if (_operation != null) return Future.value(OneKeyLoginOutcome.busy); - _terminal = false; - _authPageOpened = false; - final operation = _start( - context: context, - verifyToken: verifyToken, - onNativeRequestDispatched: onNativeRequestDispatched, - onAuthPageOpened: onAuthPageOpened, - ); - _operation = operation; - return operation.whenComplete(() { - _operation = null; - _completeCurrent = null; - }); +typedef OneKeyLoginCallback = void Function(Object? result); + +abstract interface class OneKeyLoginGateway { + OneKeyLoginPlatform get platform; + + void setTokenCallback(OneKeyLoginCallback? callback); + + void setUiCallback(OneKeyLoginCallback? callback); + + void setWidgetCallback(OneKeyLoginCallback? callback); + + Future requestLogin(UMCustomModel uiConfig); + + void closeAuthPage(); + + void clearCallbacks(); +} + +class UmengOneKeyLoginGateway implements OneKeyLoginGateway { + const UmengOneKeyLoginGateway(); + + @override + OneKeyLoginPlatform get platform { + if (kIsWeb) return OneKeyLoginPlatform.unsupported; + if (Platform.isAndroid) return OneKeyLoginPlatform.android; + if (Platform.isIOS) return OneKeyLoginPlatform.ios; + return OneKeyLoginPlatform.unsupported; } - Future _start({ - required BuildContext context, - required Future Function(String token) verifyToken, - VoidCallback? onNativeRequestDispatched, - VoidCallback? onAuthPageOpened, - }) async { - if (kIsWeb || (!Platform.isAndroid && !Platform.isIOS)) { - return OneKeyLoginOutcome.unsupported; + @override + void setTokenCallback(OneKeyLoginCallback? callback) { + if (platform == OneKeyLoginPlatform.ios) { + UmengVerifySdk.getLoginTokenCallback(callback); + } else if (platform == OneKeyLoginPlatform.android) { + UmengVerifySdk.setTokenResultCallback_android(callback); } - final uiConfig = _uiConfig(context); - await UmengService.initOneKeyLoginIfAllowed(); - final completer = Completer(); + } - void complete(OneKeyLoginOutcome outcome) { - if (_terminal) return; - _terminal = true; - _resumeCancellation?.cancel(); - _resumeCancellation = null; - _clearCallbacks(); - completer.complete(outcome); + @override + void setUiCallback(OneKeyLoginCallback? callback) { + if (platform == OneKeyLoginPlatform.android) { + UmengVerifySdk.setUIClickCallback_android(callback); } + } - _completeCurrent = complete; - - void handleUiResult(Object? result) { - final code = _code(result); - if (code == '700000') complete(OneKeyLoginOutcome.cancelled); - if (code == '700001') complete(OneKeyLoginOutcome.fallback); + @override + void setWidgetCallback(OneKeyLoginCallback? callback) { + if (platform == OneKeyLoginPlatform.ios) { + UmengVerifySdk.getWidgetEventCallback(callback); } + } - void handleTokenResult(Object? result) { - final code = _code(result); - // iOS 700002 is only the native button click; token follows later. - if (Platform.isIOS && code == '700002') return; - // 600024 is Android environment availability, not a login result. - if (code == '600024') return; - if (code == '600001') { - if (!_authPageOpened) { - _authPageOpened = true; - onAuthPageOpened?.call(); - } - return; - } - if (code == '700000') { - complete(OneKeyLoginOutcome.cancelled); - return; - } - if (code == '700001') { - complete(OneKeyLoginOutcome.fallback); - return; - } - if (code != '600000' || result is! Map) { - complete(OneKeyLoginOutcome.fallback); - return; - } - final token = result['token']?.toString(); - if (token == null || token.isEmpty) { - complete(OneKeyLoginOutcome.fallback); - return; - } - unawaited(() async { - try { - await verifyToken(token); - complete(OneKeyLoginOutcome.success); - } catch (_) { - complete(OneKeyLoginOutcome.fallback); - } finally { - _closeNativePage(); - } - }()); - } + @override + Future requestLogin(UMCustomModel uiConfig) async { + await UmengVerifySdk.getLoginTokenWithTimeout(3, uiConfig); + } - if (Platform.isIOS) { - UmengVerifySdk.getLoginTokenCallback(handleTokenResult); - UmengVerifySdk.getWidgetEventCallback((_) {}); - } else { - UmengVerifySdk.setTokenResultCallback_android(handleTokenResult); - UmengVerifySdk.setUIClickCallback_android(handleUiResult); - } - try { - final request = UmengVerifySdk.getLoginTokenWithTimeout(3, uiConfig); - onNativeRequestDispatched?.call(); + @override + void closeAuthPage() { + if (platform == OneKeyLoginPlatform.ios) { unawaited( - request.catchError((Object _) { - complete(OneKeyLoginOutcome.unsupported); - }), + UmengVerifySdk.cancelLoginVCAnimated( + true, + ).catchError((Object _) => null), ); - return await completer.future.timeout( - const Duration(seconds: 20), - onTimeout: () => OneKeyLoginOutcome.fallback, - ); - } finally { - _clearCallbacks(); + } else if (platform == OneKeyLoginPlatform.android) { + UmengVerifySdk.quitLoginPage_android(); } } + @override + void clearCallbacks() { + UmengVerifySdk.getLoginTokenCallback(null); + UmengVerifySdk.getWidgetEventCallback(null); + UmengVerifySdk.setTokenResultCallback_android(null); + UmengVerifySdk.setUIClickCallback_android(null); + } +} + +class OneKeyLoginSdkResult { + const OneKeyLoginSdkResult({ + required this.outcome, + this.token, + this.code, + this.reason, + }); + + final OneKeyLoginOutcome outcome; + final String? token; + final String? code; + final String? reason; +} + +class OneKeyLoginSdkSession { + OneKeyLoginSdkSession( + this._gateway, { + this.onNativeRequestDispatched, + this.onAuthPageOpened, + }); + + final OneKeyLoginGateway _gateway; + final VoidCallback? onNativeRequestDispatched; + final VoidCallback? onAuthPageOpened; + final _result = Completer(); + var _started = false; + var _terminal = false; + var _closed = false; + var _authPageOpened = false; + Timer? _resumeCancellation; + + Future start(UMCustomModel uiConfig) { + if (_started) return _result.future; + _started = true; + + if (_gateway.platform == OneKeyLoginPlatform.unsupported) { + _complete( + const OneKeyLoginSdkResult( + outcome: OneKeyLoginOutcome.unsupported, + reason: 'unsupported_platform', + ), + ); + return _result.future; + } + + // Availability checking already pre-accelerates the carrier page. Start + // the token request directly here; the SDK performs its own preflight when + // needed and reports its timeout/error through the registered callback. + unawaited(_startNativeLogin(uiConfig)); + return _result.future; + } + + Future _startNativeLogin(UMCustomModel uiConfig) async { + try { + _gateway.setTokenCallback(_handleTokenResult); + _gateway.setWidgetCallback((Object? _) {}); + _gateway.setUiCallback(_handleUiResult); + final nativeRequest = _gateway.requestLogin(uiConfig); + onNativeRequestDispatched?.call(); + await nativeRequest; + } catch (_) { + final completed = _complete( + const OneKeyLoginSdkResult( + outcome: OneKeyLoginOutcome.unsupported, + reason: 'launch_error', + ), + ); + if (completed) close(); + } + } + + void _handleUiResult(Object? result) { + final code = extractUmengLoginCode(result); + if (isUmengCancel(result)) { + _complete( + OneKeyLoginSdkResult( + outcome: OneKeyLoginOutcome.cancelled, + code: code, + reason: 'cancel', + ), + ); + } else if (isUmengManualSwitch(result)) { + _complete( + OneKeyLoginSdkResult( + outcome: OneKeyLoginOutcome.fallback, + code: code, + reason: 'manual_switch', + ), + ); + } + } + + void _handleTokenResult(Object? result) { + final code = extractUmengLoginCode(result); + // On iOS, 700002 only means the user tapped the authorization page's + // login button. It is followed by a separate 600000 (or 600xxx) token + // callback, so completing the session here discards that callback. + if (_gateway.platform == OneKeyLoginPlatform.ios && code == '700002') { + return; + } + // Android `checkEnvAvailable_android` reports 600024 through the same + // token callback. It means the terminal supports authentication, not that + // this login attempt failed; wait for the actual login callback instead. + if (isUmengEnvironmentAvailable(result)) { + return; + } + if (isUmengAuthPage(result)) { + if (_authPageOpened) return; + _authPageOpened = true; + onAuthPageOpened?.call(); + return; + } + if (isUmengCancel(result)) { + _complete( + OneKeyLoginSdkResult( + outcome: OneKeyLoginOutcome.cancelled, + code: code, + reason: 'cancel', + ), + ); + return; + } + if (isUmengManualSwitch(result)) { + _complete( + OneKeyLoginSdkResult( + outcome: OneKeyLoginOutcome.fallback, + code: code, + reason: 'manual_switch', + ), + ); + return; + } + if (isUmengFallbackLoginCode(result)) { + _complete( + OneKeyLoginSdkResult( + outcome: OneKeyLoginOutcome.fallback, + code: code, + reason: 'sdk_fallback', + ), + ); + return; + } + if (!isUmengTokenSuccess(result) || result is! Map) { + _complete( + OneKeyLoginSdkResult( + outcome: OneKeyLoginOutcome.fallback, + code: code, + reason: 'token_failed', + ), + ); + return; + } + + final token = result['token']?.toString(); + if (token == null || token.isEmpty) { + _complete( + OneKeyLoginSdkResult( + outcome: OneKeyLoginOutcome.fallback, + code: code, + reason: 'token_empty', + ), + ); + return; + } + _complete( + OneKeyLoginSdkResult( + outcome: OneKeyLoginOutcome.success, + token: token, + code: code, + ), + ); + } + + bool _complete(OneKeyLoginSdkResult result) { + if (_terminal) return false; + _terminal = true; + _resumeCancellation?.cancel(); + _resumeCancellation = null; + _gateway.clearCallbacks(); + _result.complete(result); + return true; + } + + void cancel() { + _complete( + const OneKeyLoginSdkResult( + outcome: OneKeyLoginOutcome.cancelled, + reason: 'disposed', + ), + ); + close(); + } + void onAppResumed() { - if (!Platform.isAndroid || + if (_gateway.platform != OneKeyLoginPlatform.android || !_authPageOpened || _terminal || _resumeCancellation != null) { @@ -147,72 +294,263 @@ class OneKeyLoginService { } _resumeCancellation = Timer(const Duration(milliseconds: 500), () { _resumeCancellation = null; - if (_terminal) return; - _completeCurrent?.call(OneKeyLoginOutcome.cancelled); - _closeNativePage(); + final completed = _complete( + const OneKeyLoginSdkResult( + outcome: OneKeyLoginOutcome.cancelled, + reason: 'auth_page_returned', + ), + ); + if (completed) close(); }); } - UMCustomModel _uiConfig(BuildContext context) { - const ink = Color(0xFF202124); - const muted = Color(0xFF8A8F98); - const background = Color(0xFFFFFFFF); - final model = UMCustomModel() - ..logoIsHidden = true - ..numberColor = ink.toARGB32() - ..numberFont = 30 - ..navTitle = ['', Colors.transparent.toARGB32(), 0] - ..navColor = background.toARGB32() - ..backgroundColor_ios = background.toARGB32() - ..sloganText = ['', background.toARGB32(), 0] - ..privacyPreText = '我已阅读并同意' - ..privacyOne = ['《隐私政策》', AppH5Urls.privacyUrl] - ..privacyTwo = ['《用户协议》', AppH5Urls.userProtocolUrl] - ..privacyColors = [muted.toARGB32(), ink.toARGB32()] - ..changeBtnTitle = ['其他手机号登录', ink.toARGB32(), 16] - ..loginBtnText = ['本机号码一键登录', Colors.white.toARGB32(), 16] - ..privacyFont = 12 - ..checkBoxIsChecked = false; - if (Platform.isAndroid) { - model.numberFrame = [-1, 156, -1, -1]; - model.loginBtnFrame = [-1, 283, -1, -1, 52]; - model.changeBtnFrame = [368, -1, -1, -1]; - model.privacyFrame = [-1, 427, -1, -1]; - } else { - final title = UMCustomWidget('title', UMCustomWidgetType.textView) - ..title = '金值' - ..titleFont = 26 - ..titleColor = ink.toARGB32() - ..width = MediaQuery.sizeOf(context).width.toInt() - ..height = 54 - ..top = 26 - ..textAlignment = UMCustomWidgetTextAlignmentType.center - ..isClickEnable = false - ..rootViewId = UMRootViewId.body; - model.customWidget = [title.toJsonMap()]; - model.privacyFont = 13; - model.checkBoxWH = 20; - model.checkBoxIsChecked = true; - } - return model; - } - - String _code(Object? result) => result is Map - ? (result['code'] ?? result['resultCode'] ?? '').toString() - : ''; - - void _clearCallbacks() { - UmengVerifySdk.getLoginTokenCallback(null); - UmengVerifySdk.getWidgetEventCallback(null); - UmengVerifySdk.setTokenResultCallback_android(null); - UmengVerifySdk.setUIClickCallback_android(null); - } - - void _closeNativePage() { - if (Platform.isIOS) { - unawaited(UmengVerifySdk.cancelLoginVCAnimated(true)); - } else { - UmengVerifySdk.quitLoginPage_android(); - } + void close() { + if (_closed) return; + _closed = true; + _gateway.closeAuthPage(); } } + +class OneKeyLoginService { + OneKeyLoginService({ + OneKeyLoginGateway gateway = const UmengOneKeyLoginGateway(), + Future Function() initializeSdk = + UmengService.initOneKeyLoginIfAllowed, + }) : _gateway = gateway, + _initializeSdk = initializeSdk; + + final OneKeyLoginGateway _gateway; + final Future Function() _initializeSdk; + OneKeyLoginSdkSession? _activeSession; + Future? _activeOperation; + _OneKeyLoginPhase _phase = _OneKeyLoginPhase.idle; + int _generation = 0; + + Future start({ + required BuildContext context, + required Future Function(String loginToken) verifyToken, + required bool appIsDark, + required bool nativeIsDark, + VoidCallback? onNativeRequestDispatched, + VoidCallback? onAuthPageOpened, + }) { + if (_phase == _OneKeyLoginPhase.authPageVisible || + _phase == _OneKeyLoginPhase.verifying) { + return Future.value(OneKeyLoginOutcome.busy); + } + + if (_phase == _OneKeyLoginPhase.launching) { + _activeSession?.cancel(); + _activeSession = null; + } + + final generation = ++_generation; + _phase = _OneKeyLoginPhase.launching; + final operation = _start( + generation: generation, + context: context, + verifyToken: verifyToken, + appIsDark: appIsDark, + nativeIsDark: nativeIsDark, + onNativeRequestDispatched: () { + if (generation != _generation) return; + onNativeRequestDispatched?.call(); + }, + onAuthPageOpened: () { + if (generation != _generation) return; + _phase = _OneKeyLoginPhase.authPageVisible; + onAuthPageOpened?.call(); + }, + ); + _activeOperation = operation; + return operation.whenComplete(() { + if (generation == _generation && identical(_activeOperation, operation)) { + _activeOperation = null; + _phase = _OneKeyLoginPhase.idle; + } + }); + } + + Future _start({ + required int generation, + required BuildContext context, + required Future Function(String loginToken) verifyToken, + required bool appIsDark, + required bool nativeIsDark, + VoidCallback? onNativeRequestDispatched, + VoidCallback? onAuthPageOpened, + }) async { + if (_gateway.platform == OneKeyLoginPlatform.unsupported) { + return OneKeyLoginOutcome.unsupported; + } + + await _initializeSdk(); + if (generation != _generation) return OneKeyLoginOutcome.cancelled; + if (!context.mounted) return OneKeyLoginOutcome.cancelled; + final uiConfig = _buildUiConfig(context, appIsDark, nativeIsDark); + final session = OneKeyLoginSdkSession( + _gateway, + onNativeRequestDispatched: onNativeRequestDispatched, + onAuthPageOpened: onAuthPageOpened, + ); + _activeSession = session; + try { + final sdkResult = await session.start(uiConfig); + if (!context.mounted) { + session.close(); + return OneKeyLoginOutcome.cancelled; + } + if (sdkResult.outcome != OneKeyLoginOutcome.success) { + session.close(); + return sdkResult.outcome; + } + + final token = sdkResult.token; + if (token == null || token.isEmpty) { + session.close(); + return OneKeyLoginOutcome.fallback; + } + + if (generation == _generation) { + _phase = _OneKeyLoginPhase.verifying; + } + await verifyToken(token); + session.close(); + return OneKeyLoginOutcome.success; + } catch (_) { + session.close(); + return OneKeyLoginOutcome.fallback; + } finally { + if (identical(_activeSession, session)) { + _activeSession = null; + } + } + } + + void cancel() { + _generation++; + _activeSession?.cancel(); + _activeSession = null; + _activeOperation = null; + _phase = _OneKeyLoginPhase.idle; + } + + void onAppResumed() { + _activeSession?.onAppResumed(); + } + + UMCustomModel _buildUiConfig( + BuildContext context, + bool appIsDark, + bool nativeIsDark, + ) { + final width = MediaQuery.of(context).size.width; + // UVerify follows Android's system theme, which can differ from Flutter's + // active theme. iOS colors are fixed at launch, so it receives a palette + // resolved from the device appearance. + final useDarkPalette = + _gateway.platform == OneKeyLoginPlatform.ios && nativeIsDark; + final pageBg = useDarkPalette ? const Color(0xFF0F0F0F) : Colors.white; + final titleInk = useDarkPalette + ? const Color(0xFFF0F0F0) + : const Color(0xFF252529); + final hintInk = useDarkPalette + ? const Color(0xFFA1A1AA) + : const Color(0xFF8E8E93); + const buttonInk = Color(0xFF0F1A00); + final transparent = Colors.transparent.toARGB32(); + final titleColor = titleInk.toARGB32(); + final hintColor = hintInk.toARGB32(); + final buttonTextColor = buttonInk.toARGB32(); + final bgColor = pageBg.toARGB32(); + final protocolUrl = AppH5UrlsHelper.buildUrlWithNight( + AppH5Urls.userProtocolUrl, + appIsDark, + ); + final privacyUrl = AppH5UrlsHelper.buildUrlWithNight( + AppH5Urls.privacyUrl, + appIsDark, + ); + + final model = UMCustomModel(); + final titleWidget = UMCustomWidget('title', UMCustomWidgetType.textView) + ..title = '金值' + ..titleFont = 28 + ..textAlignment = UMCustomWidgetTextAlignmentType.center + ..top = 26 + ..width = width.toInt() + ..height = 54 + ..titleColor = titleColor + ..isClickEnable = false + ..rootViewId = UMRootViewId.body; + + model.logoIsHidden = true; + model.numberColor = titleColor; + model.numberFont = 32; + model.sloganText = ['', bgColor, 0]; + model.navTitle = ['', transparent, 0]; + model.privacyPreText = '我已阅读并同意'; + model.privacyOne = ['《隐私政策》', privacyUrl]; + model.privacyTwo = ['《用户协议》', protocolUrl]; + model.privacyColors = [hintColor, titleColor]; + model.changeBtnTitle = ['其他手机号登录', titleColor, 16]; + model.privacyOperatorPreText = '《'; + model.privacyOperatorSufText = '》'; + model.autoHideLoginLoading = false; + model.customWidget = [titleWidget.toJsonMap()]; + + if (_gateway.platform == OneKeyLoginPlatform.ios) { + model.loginBtnText = ['本机号码一键登录', buttonTextColor, 20]; + model.loginBtnBgImgs_ios = [ + 'jinzhi_onetap_button', + 'jinzhi_onetap_button', + 'jinzhi_onetap_button_pressed', + ]; + model.backgroundColor_ios = bgColor; + model.navColor = bgColor; + // Always use our paired assets so both appearances keep the same iOS + // chevron geometry and differ only in color. + model.navBackImage = useDarkPalette + ? 'jinzhi_onetap_back_night' + : 'jinzhi_onetap_back_day'; + model.privacyConectTexts = ['和', '']; + model.privacyFont = 13; + model.checkBoxImages = [ + 'jinzhi_onetap_unchecked', + 'jinzhi_onetap_checked', + ]; + // 原生 SDK 会按该尺寸直接放大图片;36pt 会让协议勾选显得过重。 + model.checkBoxWH = 22; + model.checkBoxIsChecked = true; + } else { + model.numberFrame = [-1, 156, -1, -1]; + // Keep the same Android SDK frame as caizhi. The capsule's visible + // geometry is determined by the native drawable's intrinsic size. + model.loginBtnFrame = [-1, 283, -1, -1, 56]; + model.changeBtnFrame = [368, -1, -1, -1]; + model.privacyFrame = [-1, 427, -1, -1]; + // Android only accepts width/height here. The back drawable itself uses + // caizhi's 48×120 transparent canvas to position the arrow correctly. + model.navBackButtonFrame = [-1, -1, 72, 120]; + model.loginBtnText = ['本机号码一键登录', buttonTextColor, 16]; + model.loginBtnBgImg_android = 'jinzhi_onetap_button'; + model.navBackImage = 'jinzhi_onetap_back_daynight'; + model.navColor = transparent; + model.privacyFont = 12; + model.privacyConectTexts = ['和', '、']; + model.checkBoxWH = 14; + model.checkBoxIsChecked = false; + model.checkBoxImages = [ + 'jinzhi_onetap_unchecked', + 'jinzhi_onetap_checked', + ]; + model.privacyNavColor = bgColor; + model.privacyNavTitleColor = titleColor; + model.privacyNavTitleFont = 16; + } + + return model; + } +} + +enum _OneKeyLoginPhase { idle, launching, authPageVisible, verifying } diff --git a/lib/features/auth/utils/one_key_login_result.dart b/lib/features/auth/utils/one_key_login_result.dart new file mode 100644 index 0000000..bf2c395 --- /dev/null +++ b/lib/features/auth/utils/one_key_login_result.dart @@ -0,0 +1,40 @@ +const _umengFallbackCodes = { + '600002', + '600004', + '600005', + '600007', + '600008', + '600009', + '600010', + '600011', + '600012', + '600013', + '600014', + '600015', + '600017', + '600021', + '600023', + '600025', + '600026', +}; + +String? extractUmengLoginCode(Object? result) { + if (result is! Map) return null; + final code = result['code'] ?? result['resultCode']; + final value = code?.toString(); + return value == null || value.isEmpty ? null : value; +} + +bool isUmengTokenSuccess(Object? result) => + extractUmengLoginCode(result) == '600000'; +bool isUmengAuthPage(Object? result) => + extractUmengLoginCode(result) == '600001'; +bool isUmengEnvironmentAvailable(Object? result) => + extractUmengLoginCode(result) == '600024'; +bool isUmengCancel(Object? result) => extractUmengLoginCode(result) == '700000'; +bool isUmengManualSwitch(Object? result) => + extractUmengLoginCode(result) == '700001'; +bool isUmengFallbackLoginCode(Object? result) { + final code = extractUmengLoginCode(result); + return code != null && _umengFallbackCodes.contains(code); +}