From 79f9ba132e14712728230f5930f9e91660066449 Mon Sep 17 00:00:00 2001 From: Piotr Dabrowski Date: Wed, 2 Oct 2013 10:19:31 +0200 Subject: [PATCH] application sources from tizen_2.2 Change-Id: Iefce6159f80ca8d9dae4852c2884af5c8a4da1da --- bluetoothchat-snapshot.png | Bin 0 -> 10882 bytes description.xml | 10 ++ description.xsl | 97 ++++++++++++++ project/.project | 63 +++++++++ project/AUTHORS | 7 + project/LICENSE.Flora | 206 +++++++++++++++++++++++++++++ project/NOTICE | 4 + project/config.xml | 14 ++ project/css/style.css | 184 ++++++++++++++++++++++++++ project/icon.png | Bin 0 -> 15199 bytes project/index.html | 36 +++++ project/js/app.client.js | 112 ++++++++++++++++ project/js/app.client.model.js | 141 ++++++++++++++++++++ project/js/app.config.js | 29 +++++ project/js/app.helpers.js | 19 +++ project/js/app.js | 213 ++++++++++++++++++++++++++++++ project/js/app.model.js | 85 ++++++++++++ project/js/app.server.js | 93 +++++++++++++ project/js/app.server.model.js | 81 ++++++++++++ project/js/app.ui.events.js | 214 ++++++++++++++++++++++++++++++ project/js/app.ui.js | 245 +++++++++++++++++++++++++++++++++++ project/js/app.ui.templateManager.js | 111 ++++++++++++++++ project/js/main.js | 63 +++++++++ project/templates/bye_popup.tpl | 6 + project/templates/chat_page.tpl | 20 +++ project/templates/choose_page.tpl | 10 ++ project/templates/keyboard_page.tpl | 16 +++ project/templates/left_bubble.tpl | 3 + project/templates/message_popup.tpl | 6 + project/templates/right_bubble.tpl | 3 + project/templates/server_row.tpl | 7 + tizen-app-template.xml | 12 ++ tizen_32.png | Bin 0 -> 4563 bytes tizen_64.png | Bin 0 -> 6849 bytes 34 files changed, 2110 insertions(+) create mode 100644 bluetoothchat-snapshot.png create mode 100755 description.xml create mode 100755 description.xsl create mode 100644 project/.project create mode 100644 project/AUTHORS create mode 100644 project/LICENSE.Flora create mode 100644 project/NOTICE create mode 100644 project/config.xml create mode 100644 project/css/style.css create mode 100644 project/icon.png create mode 100644 project/index.html create mode 100644 project/js/app.client.js create mode 100644 project/js/app.client.model.js create mode 100644 project/js/app.config.js create mode 100644 project/js/app.helpers.js create mode 100644 project/js/app.js create mode 100644 project/js/app.model.js create mode 100644 project/js/app.server.js create mode 100644 project/js/app.server.model.js create mode 100644 project/js/app.ui.events.js create mode 100644 project/js/app.ui.js create mode 100644 project/js/app.ui.templateManager.js create mode 100644 project/js/main.js create mode 100644 project/templates/bye_popup.tpl create mode 100644 project/templates/chat_page.tpl create mode 100644 project/templates/choose_page.tpl create mode 100644 project/templates/keyboard_page.tpl create mode 100644 project/templates/left_bubble.tpl create mode 100644 project/templates/message_popup.tpl create mode 100644 project/templates/right_bubble.tpl create mode 100644 project/templates/server_row.tpl create mode 100755 tizen-app-template.xml create mode 100644 tizen_32.png create mode 100644 tizen_64.png diff --git a/bluetoothchat-snapshot.png b/bluetoothchat-snapshot.png new file mode 100644 index 0000000000000000000000000000000000000000..e972127691c6bd8d1766d4eb23d4f51d6337a165 GIT binary patch literal 10882 zcmeIY_cxpGA3q)%m8ucMXssY6S`@YS-kaE?t=eKmYF8<0t6jS&Dm7lHktn685jCs! zYHUUA%{TAQIp6dB13tfgb53&Socq47bB*WqydKZT;}L79uR%p|p8@~?P-$tZ8WXPx z#P1o1l=vH@r_BNYJk-)sRWc2j-p&sUVeLV$*&`O@$c5f_Q2hbl0R!*EG^xgk@M)(! z!0Ug_tXXzgtIP9{*UEEnaApgxPil3Sk$-MkOE}g1UB_h|=U`n6nM(E0N>?+Mg&Ka< zdJWJ5uMGfDCx=Ey$H}*&0U*+JU0OHXH;z{^1v%B5o9E+un`kuERI`s906;?eT9WWo zJQAG8W<|jn2>{sLcmCa%ZY;w44%Oz(Kjia3t=5GiOPy&>VU}c3QBCo7-mQ$X>K-Y7 z8h$)PE!H?LCKCLE*+Dnc5#Y^APWwO$XR`|8EVKN=kJrOQmbpeiZ6u^=m37BHruWwk zNPYWmf%05vL|SI90rg{Hu7>p~H8(1+uE`{?V|sO;Gayx~F*%==R8$;f<#!~L;Bk$} zEgU=bTMcz}urOV0OfhqEkL^$GpZJWipXWJZ?pD?_aoxr6xauG2qpiUwy88NY#Q|*V zkugaGKR>^ZW7*;1*NRY~a&IZWvycMgV$9~jkiyL=L4o@Anb69&@3Zu=1dWU(NYPR}ep`%eIAA-;h(Gp`rfsXRCcPDEde0}#b zts5J@e6h%Mv^0B|5wwGKHmUHlw_k8bzUmd#>#1d`^7IOst+T5yJ5b>`M_FdthwL%! z1}|JpR9c$wGxC+*)xk?;!8WjK1+6#NVVW?yg|opow{G2Hk?iZ>Ik+ z(o%e*Q=~L#nEJ7(=|Gg0_->ei+SXv;Y@Y` zZRKk#)}B)@XOJ=+0gKn67sng8w#i;qn?&S{U89GkNVbcYmxAx|e@JWVMh^i9#e+m0 zW9|pV$|^Xp(&B5VRx0LU1e7_t$o2jjGYGhUcG=aXT4XqkW}{UpGBhw4dNL%7Wd51zbpX}b_8DJfa<4mjEzFLSkX+YO{ujv+`A zdrN#iTi40k`@a$gG(RJX)w%W+=^f5S6#1QFGxb}h3Nuf7iSX;ZpAhY5fUHTqH6S64ZsjhBcBJ7}v znnRv7zFQnQ%}NoaUntKIYbtv@nS6e6k(+BB6da7URS3J5<%IZP+J23XCnhIT(a;$9 zHv`*eN>U!BI$Az5`$A1+J6Z4SFOogkh_rTaC_z3R&8AnDT*Flt$_DOdI~T;Na`hy0 z=<%d!B(XkAcob*l7Q+PqM0}!qkWg-%T=C3}8@iTL#v$zo0{8d#zuXRLtFHD83CTlU z&!UE$M6$~ZUp-_MWVv_G3~_Y0VX_x6E0i$TV$aVQPi!#LajJ1Ujn}|Xn@q_N(k-^8 zJ62ia1y&omis`L+!=8+)cAf5cL(apKdNOxHK0Yp1czsyT%ae-12+q!N67vIrK=7YK z`@@Xc;}P@0yD~jL)FnJ7dzp1$e=r#R?0$*4FR?PXEqzNI(7il zNrg=WF#^L;JA-MGYmG>(349PMlj57Wn~lBmwsXn*J*v9mJ}G0o8X#4(i?~Ay0JL)~ zG(ge{QwmxJH9kFIro>P1IGNgwzkd@{ABtoj>O5{WeHaLUZf`%jLsAZ!EvWttgoUaz zXaE4p01`krSP>{8tskm3JC$-Vo<8*Fx%z9cH?spZH*mIpg*vtvPOJTOVM$L3)GYQM z{QWFrfg$sLo@-8|p=!13ea??BI^+Ep(7XV!^k;(7%OkI+R+I5ezB8=4ebR)@*Dp4K z@8`GzD=5IES$-MK%lXa~55MI|GHr=I=xQZP3UT84Xz||fZoF|^-Yw#Jux2ty+5~nE zlW9>b*S>e^m!_eredl=v{UV@?4K~*sP#dEbJxINHuYaIs0mZ5K-7#NccUUOm;~X8wB?}pV57`ZRRqgE605PJearP&#D2A?-P0q%n%4-wD%MSjMn{aZ2Y~qC%NWgS@sOl(?cMp>vb8_>f|1M zgks4^+*6^`!zV)pJ1n1SK5y;3lFEAg>z64FwVk&!o!ncy5%g8dLa-<^==bQnv0f9q#zWWV&|{FEm4$*O_-LiR+zsR_d<=>2j*borAN3PwqK<+y;DV{S+Y@cw z&(F_qmJMz+CsdrzFAmNw?|z%i*VG64u}P^Y_w>+{bw+O0*4zTPK`3NidPu}|tGuPQ z&K#ee)vfTp*q)I<&i-3J37Z@r4}9hQUv- zYwL`mwHfp3_j$T}alT`#RDCb%s;giA+(g`R9$G`4t>ClDjkC*soa1mgo16W8eSL~T zhIZ_nk)i_bLKM;Pt&XQIE-nGjMM^ObNq-bGbbOc}o&ADo70A}y3{o8Xb@jMaRK#yk zC_%YMNSYP-b&fmL?B8rn9t@lW~K;4MwNBb*MISID=8vlUuI@zs7jhWw-bxu$45tAv(56X zred}=6&1GFx~hr_VF-m<2}9rV3mqL3A?8n?Vs78EGBLq->=gJ(*ApXB^W*a?96EB? z5I#IQ$~xQ-7e_JCV_|RaPj=0mtVBn66NiZ_eqmh(?@w|t(Pr&=mO%Dq$wR!#?LNt- zP%fQYj@m?>vZ@jo00o1jlWx6Et%Oj$G47Y5S4%6^4z3lmDA~9;SPYwLJT_gO`)pplkLO;#%T5gk6N>Mo{yO|$dq+CI>jPgkP>0Y=qi*!2w|9emq_$ zxz;x9(?!?1?+Dnr3XVG*z^mn>R*zibZ9_j@9G*CE+;pXI_lWAD=BQ{c2@|jWb@q^k zzm~DiGfB@wDSe0#5^MJ!wCz#d;O0tii`p3Zj?5{BXHLV{@A6y8#4B&(My8tqyVi{)*c@w?^5H9r$PWg_h&C zQ2%u<$f0q&8J!w~`7EsLY&X*rZ8%J5=`%=Z6r&;#pj=_eKksvq#9Mf|p>uIee%QX5 zbj;+x>uQU|;mVwD!gmT(-g+%y-+&`tN4`rAS?;vIDi51)*g7+~+)XBeZUbG|&2{}v z`R>4Llc9?t;x_EMM#{U2a*amn!PH|@vmbwA`xYT#U;eprS>UGpEBQe z_?sl-d9g&p!5#T^MZljHp!8u&!lQX9n#FS_um^L@K;9DEOt9!K_F5F6Ky!qaj}fD5 zc%*i7CCeU5IA-fp9j)_NjGFOU@LA7rz+f7_h-R1ZfqvEfHMrbfkUz{1yT`&ZE_ziE zJTD?Gz29F{V8WZkAs?a%j`R>;lh>O5;xmUmc*Cn-fO9=iR{|4ZadmlNkXwjHz)Ae$ zk376{3~3RHHE+mNY9zjE$X_xQ!y6lFh^M}|xcJU2wjL+V2#TJbnZe^#Ml9yqLLVcs zfd@Di8LCcbq-JUYv|vMFW~BC9ZWk+IWi*c_Oc$tV=;AHsYB4@jbqtTpx{7Hh?);i> z+x(53!F(=0Q(jul^(v0=JDiM-bE$Md5MiwYo=O0N8L({lgW`h;zX~_L4+8pPE1@6^ z#!2L!-WW`aorPsqIoS`$vLL`U-|d|47i% zEXFUBs4lbx5x6&TZNCElSpvVc901xh*%fULDgCE9jn@vS+D8-T<6|OYA{5D#P7(eH zdT-`6kG-rDI~qp1J0vip-qnOYkG&wS^k4#}9lgQ-}yH^13KiBUz7H zI2QGF)W5stt$F|2JT0l|ztd0_jFlT+AlH^~?01%_3KBXVGwHJ>n^UINtgcTDLx9qk z<9yeLdl!CXE{W|TR^vn)|^@*&Y{PVDvo9x@-e8sTg zTCO!}?q#doE|gm81KP5t+aF%I(aNQsy=*Vx;v(-F?dY~n72B~e9c@Mq#&K!)W-}qx zfQkT|>eVTK3iv53WwntCpa^ml$L*dEG-(y(>)getllAevh=H3Z<>>=aYx=I^RM?_d zt<_{wyy>_b>y3|}ZpXj^jd%e7KbdrQxlKC{EC@;(=6BL(ux;?FmiGv|6FbDw|0BaU zWuSgIS9?Eucg|inp?9VBz(DrBJX$l!l$0|9b8GF5!K)s=lUXU#OZ;Y=fzfbY~Kmf@@(8adTL`r>rJ`_JBolQDjvd&pz~>QC|J8n6tNk zc_dWDK%sbCRDAZ#?oZ=GWuO|%)Y0VfNY*b4TYSs)dk|N4Q2I_^ife`R>v(}!I%Cmo z#G}kBeeR`=bbj!isjq1ks<3q58R>)8i{!AQ5_*keu6yOi@(++1fftUf> z7h)2Vxss=|7==rif8}0QfpN*WBCzHd4bTy5dhhrNOj`DH!3Q;S`&r#nZq9?;xgG15 z5yf-=b`+2|Z@$G>&pA2sWIO5?NW!zam-n>?S)q|Jsbbl~ZueCrD*3HP9C_67X4Pq= z&z9}%ioQWaelp$x`M;;52=g|v6_OeJ)Z9L(kS7&U92W!zmwLk{f2o7+@LN}_f5sw7 zIrTZ2aL>>_m&&^;_V;Hl#`X~`m8KC>>|rTkeEWhSmku{5Gj>odYk3>)`+W|ncchj^ z-tuGAlD9Xl(_O^8%YL{uV4{0-auaHm{Qf>A^glJpHD;vx)!>qWc0{@#tm&J3wzXCw zt4w+;GSCr!?o->P#)1En5`FhQcjogwo2?8JViA=`9~ol`*|s?jyIe~tnHEVLxOvW# z!SDsSoX}4pLQY$%$PCC=E&!4Gdpzu$<)<^EJAyXFB^iN_z)f+ztV3cv+R)v0J=k7% zlfMR_`YDVGEl z6v#HC&71!`+;EfGa(Ujwr7wG-Q;Cny>NpX(O=!p(VkD)plSy(fEdbD$_${9 zh8^hAcTzHqXEyh;&?>ZmB&g1xqsEnS_qDjfTQ*3>paRu9lGG|jAG^eI!W>yhC?Ww5 z@&r0MVHS$8L2NOm>DR-HWEy9c6#Gqc5!s}cEsCG|fB#Z~EtL+ec3EVS(Gmn5WvQ9q zFE_fI=2v74sy6o!68^L8pw?sdG%__JL8_KwmsJq3Y1TR_e}`09?_#q&n5-deZ(Lb@ z1b0pryY9KTQsk2a&`#B?){icK8LGaR)X69i*{xP=-cq8XXq4_7^_(Z|D~>PtHD5}3 zBSRYOft3;UI{)k&LBY}S?m0900!_-3Yf-LaZvRY7b7o9M)dcNpy51>2)rIL1G&zZL z__1G=8W&JvZ9jxiT!POpL^wB~7&e;be1I?t zX$Sb+{b}>9U7h(S)l3>bz@)`w8hZ1`Q zf5y7;i?IyoBud-#eZUg88f`+V5roQ2+?rO&yxKHJLcz-KJJox5+<5Dqgf(IS?P!GI zxMePt;J7t|2}80lKaJMSao4(mov!IGcni+t=6uq-QaMwND^}E4Fm&r}=i1x&g|MK@ zfe*BIbW%0_qA((8uW%pAjXxy{Y%;>{YT#+GSW-ne)L1(L2d7ZYsDQq!`v3yqwC5sz zL;9uMFi=Cf;YdwQF5q_(BZ!tFy-gG(yPu8(U|W=RPkNr`fKcG z8kUU9F7o zrs!ii|eE-xY2UTfi?j2R%?z>7uNo(0d_2pI1FODoZ9*enxU^15;f7~A|u z9E@*L*s(P}nm+Sc9r}@q{drTzLZJ2bw)G?G{DIKp+*_wPzeBkqV9NO+z|%)Drpw3g zYhRsBA6@=2_y^#()X8ZT`-B-L50l+5GAKAL*La-%wyQ=qsHjTIev0mNv&2L!9Uydj z;j&|xe8H#*h3b}gB?QyydIkcdzw_w8IwGg$np6wtW%lYr={NEYN@<$pj%_agdhdCA z?P%J2nx8D=c|}wRPJtGp$iK~;-h}?)c)1Gh(6iRJV-o%u4dRQITu9YuuE;(NqwjP_(v|AZ+G1yOD$jqkoel0q_@eO&h<9DUK74GchFzoK* zg@x0H)+7A+9z0gMMG?b=l@yO}6w!{|c~w8N)IVnXtAc8gAq#S1_SajD7xPA5Q|||* zdoB*>U0dqKEJURqsDd@C7d7eT{*(TS{aoqdqpfMk1P?gAE};>!!!sO$g5&emu+H ztbk8Rsjn+ov)_faA|2nlGOkYk(SeN)aFCP!$Cmy;Te+CaWN>e_T4c~C@Xhb(Pg0b$ z?Oy`avLTPMDAP5A)-q#bbEU%qYx*T1 zP_weetY9*u`6LMw_unBlOzwhaLCT!P#47i&{8;yrz|F)XLOoo84L7=UgpiT~N7#G4 zHfJxXDa7rbcMjUd><6iUydmmCJBeDYiZJE&XBO6ckG+P`%KggEP4a{AINzR*rRFK) znkp}v@vih0Dl0_PS7P)JH)AW+ueR-Lw&e@7%JOo(`0*?G(f1o_)f3aT@NU17R>E-) zS7yEU-kki-dfVkV-k;gvNQLNcM5p|)%J2b`jbgb1zB~?_`0e8C?tLawg;N&18_Oc| zy?lt#PtV1Dlot9ieoyOBK59PH8DVY>&qqC9*_ZLG!PFS5hO6Q~`d?WgH0ep8_fs5J zL=+?Ld`UqG$lC~{TeD!Klj^YvU!f}NHHCoIKJ=ywt14=JjN-cM7J&gxML1a5 zq*N$sjr_rBCvuSkRNpi zs!sxW=`sP(G!&SV6#@cJOpZXb0h9+~@|3Cot=E10Ht*z{(LF65j}&Ugp50Nc%bq=$ zWtu5hi@2ATI!ZzSfzs(B0E4olN67M9vS=_l^ z7=oRS&G~vlE~_2rAN79YiqEmq530K$fz_3Cu<*4Vo*LmJ0c$I`3Wp9RM8JTN@!tZ4 zxxJ+`JO3-zEly|V@h9AQQamJk?HJ9~bT1JWW7aBXMk_*LslB$)=c+ZU+%Cn$C!`Fp z|2(sGbO@j&rM~6;52H|)O@>2|lPLjg)-yKT1?bj3Jxq@_qtTO{0Y4Iy5|MV+0 z`^*Lhxj-mSm&jC9NKgN?*^j?u)&5mIFu=!jM!nvGO88;b~rTRJ+#<>LhEX?*r- zsjsT~*;qwpHQK;*2k_chnQThvtR_db-s)}y+}KierjgOJQHRh%V7>R`#ZuzLPg`s7 zNFC!s%*#I3%E)2+1~btxVH+j2BZ=4h|Es#%nfh*>as>kHVgIKx3rUfE{Wz8UpW6R_ z^Z$Ml6k(D4X!a0BB~}g&`%T$X{s^!8^(Wken&h)0 zIoaWOHhV#HlyRGl7OgT+NtK^Y87u_=kP`B~7I1MwAACsWS1k2BST3WGr3g>N{vs0pa{u zR`x?L(9bVj*v#C#hZ(R3tL-T!K|4U|Hptl*+3EYWC<}bHrW876wMbR*~EvVqobqZALZ&vHLCGB zCiwh7+qQ`R&VR=2>F}WxI*5g7{rvfJ#N`VXi!CjEz@B`oy|n3!c|!^`by;^vFtkSUp`^rt*enK9ZQWE|R8&+}#*?B6Pz(zTQ&H)} zp|@r|WwY>!iHUO|2S16zeBX+1T3VV=@URtS7k=txO%+q#_9X-WFkyVp2*9ygMdVOacsj+Jh!U4T9ARB>-HNZ02o-5PBfxKKeNb0|65d29Uv0m z%FjBZspjV96wdk#h*O%In~R)zwOLWVxwX}T!yWG~cv+fRTHY&7N7?Z+e#T$`AHIGK z@%61UgikiM`tRBeVqJ5}T-$Q!x;Hr8b||w@gZIK3==D^W6NcPPvjm}b=e8Beo^Ec^ zA*Vv6Uoe>d#%&_eYncg;oAPL^sBk4VMO2AOOS^sYq%xyscx)cw**u674Ugkmvw^5t zW*QX8TJkeWc+GzeySWaL|AyW&dp|^n8uOtsMKA!Dez15^0!cl;#l^6Qdl0u;i~nwQ zRTc98e6G%h!e0HI6z&vi^jh$oc`3_YPPFdi;a33AEPQrZ#g=rbAK^!0so;G^(E~;S zUuDf&7pqLd?>l-XFfGMA_gkG0uJ3ABI8JpJ-=iQ~Jr{Gbd0DO5@l=RCnP{77Y-}Xb zxyOfxqT=GXGAwdNBbhw|)+hQiI{LN}nCMgRU{)8*`dn3IOEhQn89%li68%XGJWETg z*Fu|%XwFY385tS0t^e9~DlE3Rm-#NyyCcwUoc1vG#Y`hSjuDzwVS+<#YY zY;U8H**Q5mM1hlrhNgvYVq&6)ut(H)KaOoE7qv@yd3w&b_}4gEs;H>M6$9UNOixc= zU7WO75_6Joa17q;xLfs4UTzs11sPE3X+p+#0laSuNggS4J(-dp3(J~IHltm5VeH`v z8%jqtGb8#313*YxIxeQ6p#kvkZ~ahXLxY&8D1;)4*l3Mit8^BAd}0D$M+wN*CC0mE z>hgVRPbH>!wI9T+=gnddhbVUux1@3rnEI_lEi)&qaEM;n&sKu6lc6G=bAnZ6uV@XA*UEd;*7WX7#!s7Kcs)c{4sMO zMtXcPTso-)p31K?MB9%4aAMK}8Q|ak()kfND8#_b+-FEEH zEEZMfigUwun;RJ!Sz20RHkQ04S*eFS@PH2(%!N@ZQTLi97;_1RE4Iruf1$`y{-3<> z=p-Fufk3Pz33`@1uF&B_dU)hbaWvawk9e|m%Zw|C%TiFlF3}mYo^w<~_VtTTQMG$_ zaR&ZgDtsMhC8VqLq2sla<;xDC7h0r1wG0G8%lSP)sOMQKjHq`ODe~iUcz@m-cVbVO zWx>A?A-X|w#gV=}qFSkDl@?3KPNn)GcFDH}B!XLiMUiAlLItzZ9vP57EqK;mB~fAO z=HXFUS?NJciq)U8@R#my0PDCo)_UyMXYT=vlKMPps0&XbXA0J4c8CN(p~Y~D1Ysp; zu++&h>42MxcNx@Je z)ef<&W78mdxxl0(Y-f}X;PTK3Ac!;1N2#=|kE!9ho2*7|!fSP|oY}l-&L$_I$PfZ2 z0lXEqod9a10z2W%I}gMV*}ua9q+Ia2yvNM%B=~16MK$imeo<^VVl}Uyvk}QIO<%|T zV7>)JnA{;zqy&ogJd1(GK~lDG+92;iQ$3#&AZZTapQ7Sz#iYx9CK%W0*ZbbriZCEd z>vaWRm+3!K5R}VMx>TUZL@6?Y|85NEMS)+64duQX?z#7mj*#TEvS<#GFwp)+jT0*r z`tBa*fgSZQ(?&ytIcrju0-TMYtkufddMIDNrxt{^c{1b5xsX5f9jYJ9R8v&36@U1U zQxVQtvlap@uemjLyWsI?#+wMJx81L zMf33N!KPxxhb@yfC;N}x9rwZm=K}=_qZEJml^PO&64ZvLT?Da)oQR@Yy*kq77WY?boef1KRrh)=&8LvY33$^ z{YADP&7GSqs#o$Qn2;*uPV>7jcF#jxt#9ihI{mF8v4+SD$x5-TX=~ozxbG3P&6#P# p*?f2fQ;w+_W}#XDo&at*wtO1gjD7M7iQZCxmYTk5wer)5{|ASB(}Ms2 literal 0 HcmV?d00001 diff --git a/description.xml b/description.xml new file mode 100755 index 0000000..65570f3 --- /dev/null +++ b/description.xml @@ -0,0 +1,10 @@ + + + + BluetoothChat + 1.0.0 + bluetoothchat-snapshot.png + + A sample application demonstrating the tizen device API usage. + + diff --git a/description.xsl b/description.xsl new file mode 100755 index 0000000..1f4f57f --- /dev/null +++ b/description.xsl @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + +
+ + + +
+ Type: JavaScript +

+ +

+
+ + + + + +
+ + +
+ +
diff --git a/project/.project b/project/.project new file mode 100644 index 0000000..ea56a52 --- /dev/null +++ b/project/.project @@ -0,0 +1,63 @@ + + + BluetoothChat + + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + json.validation.builder + + + + + org.tizen.web.jslint.nature.JSLintBuilder + + + + + org.tizen.web.css.nature.CSSBuilder + + + + + org.eclipse.wst.validation.validationbuilder + + + + + org.tizen.web.project.builder.WebBuilder + + + usedLibraryType + WebUIFramework + + + + + org.tizen.web.privilege.nature.PrivilegeBuilder + + + + + org.tizen.web.editor.css.nature.CSSBuilder + + + + + + json.validation.nature + org.tizen.web.jslint.nature.JSLintNature + org.tizen.web.css.nature.CSSNature + org.eclipse.wst.jsdt.core.jsNature + org.eclipse.wst.common.project.facet.core.nature + org.tizen.web.project.builder.WebNature + org.tizen.web.privilege.nature.PrivilegeNature + org.tizen.web.editor.css.nature.CSSNature + + diff --git a/project/AUTHORS b/project/AUTHORS new file mode 100644 index 0000000..4350a55 --- /dev/null +++ b/project/AUTHORS @@ -0,0 +1,7 @@ +Dariusz Paziewski +Tomasz Lukawski +Pawel Sierszen +Piotr Wronski +Tomasz Paciorek +Artur Kobylinski +Grzegorz Sala diff --git a/project/LICENSE.Flora b/project/LICENSE.Flora new file mode 100644 index 0000000..4a0af40 --- /dev/null +++ b/project/LICENSE.Flora @@ -0,0 +1,206 @@ +Flora License + +Version 1.1, April, 2013 + +http://floralicense.org/license/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, +and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by +the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and +all other entities that control, are controlled by, or are +under common control with that entity. For the purposes of +this definition, "control" means (i) the power, direct or indirect, +to cause the direction or management of such entity, +whether by contract or otherwise, or (ii) ownership of fifty percent (50%) +or more of the outstanding shares, or (iii) beneficial ownership of +such entity. + +"You" (or "Your") shall mean an individual or Legal Entity +exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation source, +and configuration files. + +"Object" form shall mean any form resulting from mechanical +transformation or translation of a Source form, including but +not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, +made available under the License, as indicated by a copyright notice +that is included in or attached to the work (an example is provided +in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, +that is based on (or derived from) the Work and for which the editorial +revisions, annotations, elaborations, or other modifications represent, +as a whole, an original work of authorship. For the purposes of this License, +Derivative Works shall not include works that remain separable from, +or merely link (or bind by name) to the interfaces of, the Work and +Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original +version of the Work and any modifications or additions to that Work or +Derivative Works thereof, that is intentionally submitted to Licensor +for inclusion in the Work by the copyright owner or by an individual or +Legal Entity authorized to submit on behalf of the copyright owner. +For the purposes of this definition, "submitted" means any form of +electronic, verbal, or written communication sent to the Licensor or +its representatives, including but not limited to communication on +electronic mailing lists, source code control systems, and issue +tracking systems that are managed by, or on behalf of, the Licensor +for the purpose of discussing and improving the Work, but excluding +communication that is conspicuously marked or otherwise designated +in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work. + +"Tizen Certified Platform" shall mean a software platform that complies +with the standards set forth in the Tizen Compliance Specification +and passes the Tizen Compliance Tests as defined from time to time +by the Tizen Technical Steering Group and certified by the Tizen +Association or its designated agent. + +2. Grant of Copyright License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the +Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, +use, offer to sell, sell, import, and otherwise transfer the Work +solely as incorporated into a Tizen Certified Platform, where such +license applies only to those patent claims licensable by such +Contributor that are necessarily infringed by their Contribution(s) +alone or by combination of their Contribution(s) with the Work solely +as incorporated into a Tizen Certified Platform to which such +Contribution(s) was submitted. If You institute patent litigation +against any entity (including a cross-claim or counterclaim +in a lawsuit) alleging that the Work or a Contribution incorporated +within the Work constitutes direct or contributory patent infringement, +then any patent licenses granted to You under this License for that +Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the +Work or Derivative Works thereof pursuant to the copyright license +above, in any medium, with or without modifications, and in Source or +Object form, provided that You meet the following conditions: + + 1. You must give any other recipients of the Work or Derivative Works + a copy of this License; and + 2. You must cause any modified files to carry prominent notices stating + that You changed the files; and + 3. You must retain, in the Source form of any Derivative Works that + You distribute, all copyright, patent, trademark, and attribution + notices from the Source form of the Work, excluding those notices + that do not pertain to any part of the Derivative Works; and + 4. If the Work includes a "NOTICE" text file as part of its distribution, + then any Derivative Works that You distribute must include a readable + copy of the attribution notices contained within such NOTICE file, + excluding those notices that do not pertain to any part of + the Derivative Works, in at least one of the following places: + within a NOTICE text file distributed as part of the Derivative Works; + within the Source form or documentation, if provided along with the + Derivative Works; or, within a display generated by the Derivative Works, + if and wherever such third-party notices normally appear. + The contents of the NOTICE file are for informational purposes only + and do not modify the License. You may add Your own attribution notices + within Derivative Works that You distribute, alongside or as an addendum + to the NOTICE text from the Work, provided that such additional attribution + notices cannot be construed as modifying the License. You may add Your own + copyright statement to Your modifications and may provide additional or + different license terms and conditions for use, reproduction, or + distribution of Your modifications, or for any such Derivative Works + as a whole, provided Your use, reproduction, and distribution of + the Work otherwise complies with the conditions stated in this License + and your own copyright statement or terms and conditions do not conflict + the conditions stated in the License including section 3. + +5. Submission of Contributions. Unless You explicitly state otherwise, +any Contribution intentionally submitted for inclusion in the Work +by You to the Licensor shall be under the terms and conditions of +this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify +the terms of any separate license agreement you may have executed +with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade +names, trademarks, service marks, or product names of the Licensor, +except as required for reasonable and customary use in describing the +origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or +agreed to in writing, Licensor provides the Work (and each +Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied, including, without limitation, any warranties or conditions +of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any +risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, +whether in tort (including negligence), contract, or otherwise, +unless required by applicable law (such as deliberate and grossly +negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a +result of this License or out of the use or inability to use the +Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all +other commercial damages or losses), even if such Contributor +has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing +the Work or Derivative Works thereof, You may choose to offer, +and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only +on Your own behalf and on Your sole responsibility, not on behalf +of any other Contributor, and only if You agree to indemnify, +defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Flora License to your work + +To apply the Flora License to your work, attach the following +boilerplate notice, with the fields enclosed by brackets "[]" +replaced with your own identifying information. (Don't include +the brackets!) The text should be enclosed in the appropriate +comment syntax for the file format. We also recommend that a +file or class name and description of purpose be included on the +same "printed page" as the copyright notice for easier +identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Flora License, Version 1.1 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://floralicense.org/license/ + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/project/NOTICE b/project/NOTICE new file mode 100644 index 0000000..092bc04 --- /dev/null +++ b/project/NOTICE @@ -0,0 +1,4 @@ +Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, this software is licensed under Flora License, Version 1.1 +Please, see the LICENSE.Flora file for Flora License, Version 1.1 terms and conditions. + diff --git a/project/config.xml b/project/config.xml new file mode 100644 index 0000000..10ca79d --- /dev/null +++ b/project/config.xml @@ -0,0 +1,14 @@ + + + + + + Bluetooth Chat + + + + + + + + diff --git a/project/css/style.css b/project/css/style.css new file mode 100644 index 0000000..4e74a37 --- /dev/null +++ b/project/css/style.css @@ -0,0 +1,184 @@ +html, body { + overflow: hidden; +} + +.box { + margin: 0px; + padding: 0px; + display: table-cell; + vertical-align: middle; + height: inherit; + width: inherit; +} + +#start-header .ui-btn-back { + width: 34px; +} + +#chat-header .ui-btn-back { + width: 34px; +} + +#chat-header .ui-btn-footer-down { + top: 19px; + right: 0px; +} + +.ui-btn-start { + margin: 10px auto; + padding: 0; + width: 90%; + font-size: 26px; +} + +.ui-btn-start > span { + padding-top: 30px; + padding-bottom: 30px; +} + +/* +#keyboard-text { + width: 100%; + margin: 0px; + padding: 0px; + border: 0px; + border-radius: 0px; + overflow: hidden; + font-size: 24px; + outline: none; +} +*/ + +#keyboard-text { + width: 90%; + margin: 16px auto; +} + +#keyboard-content .ui-scrollview-view { + padding: 0px; + text-align: center; +} + +html { + background: white !important; +} + +#start-content { + background-color: white; +} + +#keyboard-content { + background-color: white; +} + +#keyboard-back-button { + position: absolute; + right: 50px; + bottom: 15px; + width: 40px; +} + +#ui-textArea { + position: absolute; + width: 100%; + height: 160px; + display: -webkit-box; + -webkit-box-orient: horizontal; +} + +#ui-textArea-text { + -webkit-box-flex: 1; +} + +#ui-textArea-button { + width: 100px; + height: 108px; +} + +#text { + background-color: #fff; + color: #555; + position: absolute; + left: 10px; + right: 110px; + top: 10px; + height: 140px; + margin: 0px; + border: 0px solid #000; + border-radius: 5px; + font-size: 22px; + overflow: auto; +} + +#ui-mySend { + float: left; + width: 85px; + margin-top: 10px; + font-size: 22px; +} + +#ui-myCounter { + float: left; + margin-top: 47px; +} + +#ui-myCounter p { + font-size: 20px; +} + +#chat-footer { + height: 164px; +} + +#start-monit { + text-align: center; + width: 100%; +} + +#start-monit a { + font-size: 1.4em; +} + +#chat-header { + min-height: 2.5em; +} + +#chat-header-type { + font-size: 0.5em; + position: absolute; + top: 3px; + left: 3px; + white-space: nowrap; + overflow: hidden !important; + text-overflow: ellipsis; + width: 90%; +} + +#chat-header-name { + font-size: 1em; + position: absolute; + top: 25px; + left: 3px; + white-space: nowrap; + overflow: hidden !important; + text-overflow: ellipsis; + width: 60%; +} + +.server-row-name { + white-space: nowrap; + overflow: hidden !important; + text-overflow: ellipsis; + width: 80%; +} + +#discovering { + right: 8px; + top: 8px; +} + +.focus {} + +.ui-btn-back { + visibility:hidden; +} diff --git a/project/icon.png b/project/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..59347574ba0838cfba30bf3293894f3c750538d0 GIT binary patch literal 15199 zcmV-lJD|jgP)m`jsvn@=bVn)hl)CL{O6^P3hHFU!%5d+tS-_zfJGH z`!4nD*^~P8=|k_m_a61@*N^)5@2_9+8T;`)j(hv}y3_mbzpugS)~y?L?AVdsc;gLf*|H@y zZQ7I?Hf%_B>(-@+hzP1(yEfITRZG9(GxpZGpOif});FWevQGp-r+uiuiVN>#L2 zv0_uIRj+=td5ad*sdH!Q)vFh^YuApNDG3GhYt*O_gBVovv!pt8>S(fkXC4Dk`CR-S z`&+2{>CmBr2Do$Qcc^)bR|xls`^A07HShj)8ypnnw5)+WgLDAM_U+qKx#czS9)kc*7OUq54I5ENXy_(9S6uV$k z-FliC024Nn)g1%K(!mnN%(j66kRUW|5{NDEYl~-Qz?#C-Y#(N1oY%0#nl8$SF zSo--r?g8MoZrxgY)o`#HHfl`4rAsfvbH+8V|A{S0;lhPKsa3o7J*X{!2`7kwlU^!I z1xqJ`$>1?bFeOlOpCtKPa}e<0kR+worX8d$#(lr~>Z{bdcWRB3C5?C5pT9_bBCP?daZ5Sb}Fvx z>>bq%s(g56411K!NK-;>(g_f7K9%b8T~ULy;>80d*Hg?!Iu8#I z8wN5nL2^{v91#Yd)vlRH!1n+W5(?=o+oTPZi#$YOn{QF&t+%P_wmVc~`(3J|fUT#1 zt?|jU7@#t+z6OkqOix(e7X!<2G!IrAxKQoPpJK%Vrhsp84Vts7X zlEBF@MF#V1Hzl*AMA(=w)h(Q%((ewTptZkInf1R>*$p?T!X^pq9Sv-?Ayf5la34~2 z%VdMJ-O>Z*?@Y;*z%j{W2>|3l&4BV}R>zGSH=zn ziQRIG!nfU~>I&FuN>cF~fWyfJNz&nxKuf1her8}Lh|+0dXOKa(5spFf1w2p!5d}WR zHITd|4hjxlgZLBfJG=EPr7WSWu6Wcl*!&s5O3*p$!>W?)Cxg!%$gV(Xd-lR%fAhC)DPt|cMt6vjT23BURWClqR@0Y;ZDnjfm*-Q^hFFu2B zuc!eV6kHm>#<|2Mfa++bn2$;dB*E9HWS}M3rpm&5n^fStu&^*HSFRkDEnAjCyA7j^ zi?2|&udh(AlNXTRx`*o8L3AFkzlJw6XDu7cV{?QiX~N0A=D4$u>j+%3iO0aDI3OQZg6&IaC3t z!NVdc;k?U~F7h&E`|2{iq=3z}^eW|Bew7NYyiSFc#1>z3gGzquNNk7#7r=(OpyD2+ zjg%mA8qy}A@;gcFh1-%O=6fEv5>zP&DD6RGfUlmo@QU;2&)*l!zzD+)@y+>CH(Y#X zM@f!kshXu)20=nW05xdjO7cvWDbu1$l$C*9<^b#e%{3~#$^dr5Z&YE> zWUab!J)39CDj4>S-^*B49wUEadc~$Kmic1o)teH_1b)_6gQP%#0{#C{Kvm#er$)`1 z4^hNsr-gH$JnBrTwFTxft0bAg(h3{M5?Xu6bn;9(Pf2Emm63 zj{xfD=a;)mc=$EsaB%~iG&gTj#-^q{VIX-FoA!;FqvKCyLmPMKMxKeM$uspFC7X4Q zo||)?QqH@efla4?%^2wbn|+C+it`F!i@Cs-d4Hll9|oGOg@r%c^1J*U4^G=}7@WYMxJpe$us#BJtcrmHv1f^q3OLAez||vuYt#l&pN1Eh%`szFkuiPWDE%@dr;x<>|cgxzI^#UY3%mw zNYJFDN)MQ&)GQjy!niGO%7j4xDXmns8dV;)iaZ}5p@bt3(=%gZ0vm7YX-Y8t3?-U* z)(fnk0yeFd*o%}|dB)jXV2kw`?{$=H-H04No7peZHgXmT&%%z5t`NC|L2es3GPIGY zMHvam5Jz@xU{D~`%9AI5&%Xpv6uPUv{PI0WDPKf_DFNhsCxhn8KG~cK`8^l~r>13_ zHz{Js67uxjM@c^2PtT4%LQjulU{48P&w7DP?n-RhFP&Ic1FKYVvEJkKIdQ*S5#rn| zu7|<^Y`7%sGYJC&gmVEzj-i<(z#tw(5?C|g&%z*07z+u5i}s(Y)vDc0o;>-Be;U+) z5+#-+q0XZRph{0y##d4r&E6x<4#_&Hv}Mw%fcgc41`X&>J;#1Up6)v-*~dRn;?MR| z!cnfoPKYV7&$tqsRH@?>@Qf9(X!L5Y}%Y!wtj<}b?QY;J9ejrt=^#OwIdz@7rZj1og)DWGz$hxFN2KZURO~^ zKtRA(e+tmF$~f1oSxb9i97BQFaWK%2Q<8EDH8$L#%)gyXel!&Y)t2o4IQ1M&EP0RuFR965?ckN%t%d@+KS&Yn!~kB_7p<91N$VM>d9c95PK zb5z~a&y;=U399kg0;eUn#6-DdTt)oqwHq*8(o9M!!?X+n5 zItm-Qh2kl*;OVDm=phw$9aUl1&*Yh)2HAu&?epb*Cb*!a_3==AB+nogZMMQ6{Rr88&F(7AKxG~qK|v5yJIUb=9Wh_2C;)%)q0 zx7L%V^EOKKks4sb4^V>7k2>aH(k~Qm3QWOS6>goQM6=J6XXZspG5;c!?>RyPs{}=P z^+B3ADvZ!0}N;Co8`5rEyR?5v}XS!&tN z#@9)T)8zl=$GW&aapD9rw}%fO(w#eZymb5aZ7r_*0fp3p zz*nharO>e8u!qgg8E`34qGZ(X0#tceMIdETN~M~WH({z(=>SOA-Ry3+5q=9$VTZBS6&uNA(+o8a!yO2_KU8f~BnG*^oVoxvtcXI^sy}_!E?Ra1>Q+ z{2IOf`s>;j&73*&5l~~>0QiFk4>V~&R~}Z^kEBGM*HNlL-|Oq*n$NiLvj^U|>#!wO zpt9;m+#Fp^x=Q)JzDR-X`)h5aYs2al{AHUewVVuVq=|#=$M*`SC!cLsxNzYqEnBtn z>Ug}`>ZN9@r?1#kdceL~ML>8Mj7I!s?%cVwfB$~Ebm=nPzkgRVw%%u3$x~+mW$d+) zQuoR72krH&J;uqW~GgY;65X~cD2I6Y8ZlO|16=ee&z0${&q+jLOb z;oB#r|!8gJP zJS3d6B}OOSm5{p+oJl;O>#^i<2GlpZ#H0Gu@?rNf1ky0#qN zcjB4RRU}9$Do8rBwe*TEGN40)D@Vce_EAvX=3XZ%I5=3VSJQuC$4L@eaw>#{-2`5b zMKoKsY;QJf)JOwj+D~aiIbUhkOwH1it!>gI1{k1X#A4#qnl)?a{Q2{A>((u=3dFW< z-#INcDci52^gY&7nqHeIP47*Vx!Xbtt5H`^xI!qx0|ocYpyFJxmuy3Qfy~zf&<&v- zYJW*D^xjB*%AO}zgC~iy<(%PqYErb6ve%8wR_ghVlp+tUOM+;-S>e`sqi#^CwZH1( zefdo{DYVBh4J-)u7CbOP}GUgivK&fZAJ z$gFzsG=EOwj~+dmcJACsSFc{xOgC*^kJ&$vr^Y{N_+?XXLU0JYX;Y zan3Pg#?WuS{iYot5CHZC^8New^mRroJ*2ObPF*9d8aOGH>V3{lf@syNY_}t&PK=z$ zwWW~KvxCr+HuAV?{d zzy|hOO-ZXvpuoCsXmyJ=5L;dqqa4l%2Fms8*S#Js$OiJQTelrMy7w%38ZM;g-dsr; zdTyXpO7*4~2nXp$ZMPGA{*$A6T`5IzA<3-h!a{m)iZWVC3w`5sV?avFxV=+oihKFH zJ5+1OU8=MGJe7aFijL z1lVR0LdK|Og26VQhV3aN?VE4Dp$iu-Xz4M*gcM=hcl4CLE&zoMHVX%QUOYS`b=0U) zTJo=5yQYZ&W@3;Z+`XkfU!yYb&eCc=bJuURdWTa6Z#$`0y@#~wmEjZTo>S^DCc0>^ zt3)iNO7)hAif&;=Z*urnr!P5T=RIn$`yMsfbDv%wFh)x%?5vs40Tyy181TyW(o1jq z1T`QaU2VQ@2>AVN3)M8L)Wzq zs2?Z?NyWyxurTU~j)~bpO5i3Nk{e-+Q`1#pj4P#ZkkG#BNGW=fZz(CgO*MBoQ$sN4 zr}^Fo^y&f9yai9qgoG(%DD@RBT6BdkOcRHNRlE)4&4h#LBtc5UTD7C<{YOyQIt?|j zP@T95u2$eZjx~X`Ex>`}bo-||@6@SN>Bx~I8aTNDU^q08UVNuj=#A^tL4_?CWEcu{>aJqQ$q6(2NdC3Oy!i5WUnG4|%is8Wx+fusT-|DzHnf7`Q#8ADQY)IxN z8xY34z+sGA%S9MdWR=rw9<=UP-H%*BNof^VO7%o8Na>FcsA<#*iWo3DMp8mbtCUm> zW(?f&6)N2J*k-GzNt32x9d&?ghT;>*_z9#WnqE6ddfsP?y$`AGS9>UY(0B@|*Uan1 zG0;pnj|_Qa@*0DHvnyYH^_BK|0boqE8!e@r?SW(=jR(*;uWH88Y*Rn`>@$5{CIHOD zAY(AW;e*qK0Rb->ac-4}M)Xp*xlY0Xp$t?nyj~@xPO`y~Qa>T32xFY?#%ta%hMUaG zZFHm*bA2GCwU-{GT0)DwIzorZ18j{-J}h=&AllxFq~fjqKtLHbPNO}tJkkz zucgo?rJTOQ_W%@<1!+V0BL|Yqbm5+{@6%5|)dPTYyG#HW_8Ww72%1W!H`%L3GNbV8 z11RALWlzT))Ad{}r8C@=;9RE(j=L_h8_5POrE6U&-S{h2nX`k!`;Meajb71%9NGcb zfx{;=c@hK0!Ndp-Q_h^Z`#l0`@qmEU_)->prETQ|1Wz5T^7ebw@Q3>v%m@W0yf>&4 zcyciQ@aifo`j&sMt4b*f5>IM{=GM^#GVb#`lff_}px@f%HNhgYm%)TGMkww^BT1PoIV@ zb;B5z(u|9ulMVSe*|6G?(vTV7QP>CLsZ!lW`kZj`a9*^7;yqL;`!Etz#zPkAB>}f$ z#fq(Z1k{j_(5twRS;aSFBR1A$D=Wuj`z>t`YA8T4(HHR+z=T%^6@yU;ryxjqd!@cS zNTmi&qo7uusf-I~i~@AoP+gS)gKf@{FDZrkgtP%1*g!rng8`|9dIo4GPoAV-e)&Zc z0A`R^tXQF?0}h+?oK24!o;lPpzRS{cDkYd19ma60YGxs&{>v{@;P|yvzRxJC()3mB zTj2Lt0}*vv)TyzLlP@y&3o=6)TZRdE;J!o4mc0@KP{cVZKJ|7Sn5`LRe99`|y8l$)dQOXX8~Sd!TCQ?;g9A~$;NLe2`%GQ&4;6wC`r5- zt8)ZEA*BEmQVKvZ5CG1eJ$v+dpb0>n6lYKo`y%xS0>B{b12ds!eWg0(e(uLbl;Hnr zUy48G1bJp%B)B`k3g83<*+S022Xr2?eMIQ>h<- z3HyS~3Pv&7H_>>VYsLY3q3;|jQKJ#foH9v4dB>-evf5=Sh1%uXC!`J%IDPtbZ<1WM zpSbFG=+L1WK$E~|X-7>UWdR%K<4y(!1AGa1e>%N1D3bDZ{6s|qj>H2)w%keYM#~C+n+#`S@9}MTnOl8UjF`hyx3BW>SqQzzY{P{F)%oqx<<}_bp()By< zyrY4Hjh5$>U5mbwG9a0bl|Xw}o^fXZN?VKjQ8-2?A@b(SH==(123Gqi!y1#cZJoW# zv72ju(>YD3T7U_U4_TCaE3WE{3g);VZbQpvmc^H}LxF@h+BuQ@et!OWO83q*@A7eY z=)r>r>y{D#Y;%sJl(H&i0&@T?t1GMxEWh8hX_I$aqf~L6uH+&%96V06fPok=OP4N< z5l3G;cZyce{({P=<2hjN{yTi2v9L-^5)Gu+zV=<)Tz;VHtofY*p{ zAo-kglw{IRnt3Q}V?6|fINUypMIF&kbo}^nEv4Lg0x5;sWhrGsZxPM~MuD+NeBgYL z*aZs~cpI^q+3b7nEEnl(}MnsS2JyZ6I@DBFXDmEsJ9+Gc+e`PAY_KPc^iat zA#^}k!d@u$LlRAi#I<1$5&vTFKs!K7zy!b)FsNLEg+q7v@L^pE;zT?EGi|giV%Vlw zNJ*758>D|D)vv?{=PX{lcyz_4L}1_noKS`sX25G!V>o$${l%wjb5-p%ofZR_kj@u1 zn3rRyT7Zet6k0fuTEl!81n^HQdTQ!vO510yx7CAdqL5U0kpQJfj~+U^_?~s|%dDMv~>Df{HDKOZ{JmLH@yTh*l6k!DxnSvzaGnfPk9yxNP z1`g6_da}~t!1)0t8r+sGTjm`Q02I;>TkQ)}IBybEY>?vZ+qdh1!KE{^E5rYOUdT6ycdrkR54o9ap0C5(Eg)i!O~=(X+v zG%_=IwS^1JJPb&vS_~3XZ39%!Ix(p5wjT#7Z0*sbM|E!%K;>+iucZ=fs#zu+q((F= zG^Pq>)2Q&f>IGGOxQj0(kWy03QNohSBMrwEn({rRTIhr*j@`WA*iC>b>?T@1&?OL0 zgQ@6?Uv$r`1L$E&GHfqpYCp!C^0ReX*a!@P$jz z5>$j+vNQ;g;gKUdh0un*XS4f~9VFQfYC5F8;!`P15-WZ!UAoL&ks=I<;SiY)62CXY z9XXOJ^!St#VAYfb7ozPZgX!8$R5YG)B@?wsR65WSf}ULfif%x37NqRI!CNHeZgv}E zV7ItnfLFGW%ut>6^6^`o7oN2*P)$i?P?3AKfr|I|e%rQfy3ALiL-Cevl+xhG8Q0W;|3t5((oJK7=PBSWP~zD!?PfeJnWuHbGi+!4 z2`6-WCA!+DTzxcJ11w z8Onn~uaKq&ru;q6L_>%Jje{5#0B_v5F$SnmsV1nfpH73?{TRgufDP%!+#IaR%}r#S zVl|y6Ta0RU4VtAkDains`R@$&;Aop#JRsl#$7&`?QMZA~C)Sc&sS2f>eU?0v&gzLu z(O~}Kg88$qMWS;6>Nb%E)R9i~)B5$_MycQ1Lg~A&qs*NbX;3+KWFWB*K#m_jUdO4B zEHm){LJpXLmoX?9%~FhKf^?%|f?6h=EQC7FG>wT`mHGk|VT}nYfX1=AckiZY)24Y% z1EkI71IUgNS&fknk(>u>YEJ0^V}D?&QqkV83R(}y8Yd&qBt<^93Awnrh|Ybj+aIndoH4R6opnNj&_3?r?Xc^Lz5^w@o)@r|q>-_wr`w@-2B9FQR;*HFTE+ z?gxMH1J4rmR?hkQN)dvPH~^TqF9s8i(I=mLLUZQK@$LuX!BE7){D(qF!b5`Lr6Mc)%;n`$l_QEHxAFU<)_ohGwcL;K0Btp+Gin|3QV+u08I4yXxpizGnE1q zJ+*1NuB8NRmXoJJq@snCvej4AX7CK1Fh6(tlr`@w(}X6lx_8IDPYetsE#&v;SX6^q zGaZ1-m=KcG++A;x|Gf$Tw`kE^=cA)`{G>3w`$$(mBp2~2?h73ps0^`PH9Ib4sA8sH z%?Z#lHZ|=mg9`kBV{}44Z~g@gDyv%Ap&)Im6n8nLp7-hX(yf z2?p+_WJ)rV_uWQ`du*nsJFV3-**pywQ@kdNsKC3csLl8tG-tyJx_I?B_>^?}7Fsr= zD>P36EdEUcATT3}6)UFgt|`r^2mx4tUfNB@%aD%Kj7V-ER6?Qy(w(%?94g%>ih9r5 zLu-FLqtvd5S?}M`_qKQMUT?P}OokjdQX-}ID;*{Yn)HCBq_O})6W}*_^XHGw{l1hl z=LlRtI!pWm`CgJdsU*EZncGFs;FZ?Yc-TTJHFO>28ls$_e!J-DcQ(_r?Z2h8Z?C5O zJ-($%A8(@GbN14*?@!aM+c8J~gL`+pjb^g+24LZp%1R9bi;2WsyM#pGx$w}RfByL+ zph8WuisbOa*6jh}aOuVHHz-|)l@zb#Qu5SWNb#FQQjs2OsN>Y#v}*TRJrI>5rc)a2G};U>p^x9a!u7N!NK0b0pYYE z*Cu(|g#?qkAK+}s*j7%WmT@hZ2x-gu#yCo^Oa+{|42sey`yU@>qn!@u z?@tolxkSf)*g_*dA4@^5P3KwU45}Hb*ht2sQj@Y{%P~4SS2AVF)X58Ks#K|}mRCUd za+XYWD^;+}OPcL3NT4Hy2g#`sQJ+Q({gBozm_i4)e@oZS9;aK^FVgLsH?)d1JxLp| z+;rxvSkCikWITv_#6!c`VIa9riD#65`Q?|I=?tzpV;;|n?}`SLq*Q${1!JowICq-f z+f3<{Uy!QXdh)bX05|)Z>Wth@yZ7v)?O)HJ7O%DON~=t-O8%MxBApIdwkZ z=mizMEg>PHUIQ%kw=JR1&XKKv&Ox=T=pbzdaCI+jo7Oa9#0bquOo9Sap-v%*zJTQp z2wOKH0}J(vG@G8@Sm?hFo8JgYw02_c}&L|S_aAHs$K`gm;?OLr80S*9@#b?gcn7v9S zus8=#voJgHxJL=aaZc3B-e2zf#lXOQan6|s1*=|wnz8*@J@o>s#9%=YG3)@svVol!$_ooKTRgby(`}?mp zMc$S+5=LepfZ>eNbbzvKHuA90wZpqRY1NvbdPi{pUbBcNu@nzbJr<|j=Tnq3lRRYw-rCFo#0 zLIi+{?@%_IG-;CVM}msf6O}B$vVE1n;vR82ytjLLixvz(y)A*T<^ZJc$C`^T9zXH)#(AlyC-zwt+5i z%tL-JQ-3CSwp1>A?b)(rd$dD8Wy+Klv9_)Rl~s{BQdo*vHP{l*47T^Lx|PZ=QFV9-ZB+7H#}-XWq@opD6xkhpAQ153R`#9*Cy1 zBz+vy&Prf`8}NGsRJA2h7rV_s$te;%iejs;O39SuYeKSY=YZD=M+(hhP|cY6hLu^M zDt*mn*7bR8Ri=1yPN;O# z`LSh*q%?ZHTtQrg0&Z47v1QDdu>(%dL9H$5m1H$@c0D9@Z@6c`ljtscpQj;x0HO2tavi^6#9Yd$zCIR6H- zqX5R8V=PG$SYPBTs5bZ8z~z-Q^@1FjwA`W%*L5nTdUpz? z?)(L%d3z$I?KpwbwI5Fz+Kr_QZO2f$)}zR;-Vpk9(Po{OwSnn#9i?k$sP|{%DEaWs z^!$9M?+T4{=!`_m4mv&1RF_iIdELjHVs116d>#OvY3HfPr0?_qW3}mvOg^(0&h=z| zkNpa-*jH!4mLWriwq?qMcy%_X&rJPp3wum2Sx!`Xl02vPZ@=8p%BFy`Ldgd#(+fC0 zKi828sJo}IkcRRyu?_&^TUF%o9 z{l+hiT(4&uVCo1O)UljSCYSUiuSlmY7VAAo@NvJO1amG?x%WQTykaNLEMJ;~p9i;@ z#Al%bPM#-O@eEt8T)C#2sz6Goc@Zh8zH*tS4V5;<%rkQ)2euM+(Z616J$(ZV1cNa0 zq0(Th;D{iMK&uP_eq?o!wnHv9)q7hhUAJ`_)KM#cvH~f=M971cVWv!(6661I^u*l_F zTp=uag;@zXUBZ$8Ib6_RazW3o0ME4e3gw@^Ppe)D&Lc^AMeM(@{gj{OzCa~ti4!L- z_QarKQwBIn*6SExQ#z$8mNA#Dk4g3r`$}kIKRaoV)Iy&}=_wsx5+nes4Ymu82)s;$ z5Qq)qc~$Ts-4Kp;8T3A-?XljG)NhV@f#l2-JYggvuqq3tUi9zZU&pv8@Sq2&4>u_~8egZp17%E;s;4 zo901w4B!@<`GcP2hiRLjLcHvOOZaC<2EKp`e4$!RHLs+Enn?xe1erYM&uj`~)J}iT zmN#$S%_ZClg)OKzRfD`Z-+;8owwPAh6dVIE3l}a-g~IFT3Cv&?qyXv-b}Qo|AI_3g z!6Od2c2%k1-kZtOYzfWX^s@#Pi3g+#QCCHC7|MT`1&6Q+aj^{iZ3JKg!@{Y=nj3mf zF77cvy~lJ;%+JM2EJa-c@EZI@C-rm5NWzp%$v<1v>;Uarwt3;W^zy`h6g-Wk;R-VBsW>^*h zgulB-mwXFS3mIp{eKWdgrBslvp-;(Orohe36vb-6i`%!Gs~nPyxovmx9d zZW0~@pcX7xkb;KH(F_AaFw&vI0IK6GUDn}(*IAnBI!jYe>jkSYHwP+Mhc?Qt#_znI z^7Qytfq9YcT)&{_u42OSkRd~~W5$0BZ_9c6l2%s5WkxO4E74$SAuM2mWfDMG)eQF! z!lEX{8oeF^R5O`l0xE%(uh^e6XU;$OzckpACQX`0-M~FtX2S-iE&So?yxb>k6+R;t zg_H&~e@idh1IA#aLyf^k?#6$ZC8~F#)6MJnXc{X&$^z8$yNZ>^VV9bJaik~ zymW?s*ttVbP)64U?i1cEDoM5$5u0Z!_rtaZC_YqJdR#9xgtZ2-LQVNi&ay-0+yzcT zqb^gyB1Ip`2-!X}*`(C|wq-R~IP$8{y z3kHSgC49h?GVV$*uvG=MUA?Nq1;l|FT@M&(Id5iZnj5cT;+3+ih*y(;yqi32H&Bl` zyXnG#tu%S^WWAOI0)I5a@toWzA)EBVLk_AIp%(?ieS<2yRB4N|6j8|Nuf0-gIzA?U zn5Q;7igRSilBL&Q0;szsRZKr-1Iip_vbfBliF{>ZX@+z{T2W%Vpr!cR`Oln#>Abh02X`O1Re zU$EdI&tLhkjMz|FR~L9F!7?S#W?yX~4l@krfE|UTmhV4Cuc%p7F#=1F!%hXWT~*Ff zffd58x*l+}U3Dg8u?LJvSc%a_(t97(9JzrOOc_HF^_}GcP*k@~1mpYim1OtjwR3Yo z^?Bdv1vl$_e^)QjduyA z1klzHF56(Z7mCw>K@m-<{;qo(RE%(_E!ZP%S6yexpPeO6LM(LFkw6l{$t<1Kv+Q(O zGyWKPK0ZjvKHN(~#!jQK@M_+_Sn)M+SCY(SKaOxLoTgIc!l>T1>w4W@P3n27e7@Lg zYUF^oNvn)cO(zt5|62fcw?s+}|HzVR2E}|6QabUs<~^Umfz20BlH;)_S?zCO_V%CVL)GXzR`~%#qEGvZ}Skq@aBH^6&Nho&QOW4c@Q< z<2qj);KbH-0M)9(B2Bq-=k~tOlP8aUtu=3*W<-PC_cf^16{v7H;7KA(U}ve2>nwSb z5XxD?TJ@ZSz>1!piKi8yKU1)`j_3Mg-B(xjmIMnIMe-PyTCE(}-Hg zT~c8E=G5viQPaH-^xDDra{xFT>@0=4&QgF#LLiBr@Rf8hUu89g*StsWxWyNe8-I3EkXwDFVSW9VSRvJFQKMD+sNtFuRCo1psa{fUoHtzrxoVB0w&fHJ=rtPJilYgKblXg+jG3%+^ z;5k&|-GNlIaSQLC1t2MJ>#*>(t_4?&lRKsRg4&PkvTldcDZKB`f;v6%XVq$o##pLGdJH zf@pJw_*rewEv-Gm*@l`)3sXDD`F~q`wk^r(4Sn1eFLUP1eU%-3C~Yi2 zHOXdUZ7Q1?VC#MLMbd`aN^7z81)28OSBHm`KE6-0z|GIYz6IM*_4-ip3DXbb%**}V z8xjO^5oTv@RCjneazO5J`zl*K3Xoe)dY^SuJZkFu^_!HL{{h=*c zvShgn6e#c`+YkA`(y5Zn@THE;IL}mXu}PDy&C-mcZO2IM;VTVl8>nVjC!arm{``CY zvDDw+xFyVzCCdo)&<`0zn_aa@t5m;cVV>=iuckNC4nL{n+UmoS%zHIsbW=jb?;d8$ zmTjcx?@rGDlUvG^DJvd&-&W_8F{_Q{qVl4{oUdZm5$l_BE$ z!oECt@@)RwT2KBjZO=ddd=&-m8p$AARw}malvLNh#}hWytLgZdIc&t&9B;~Flw__^ z&k-Kiy!_W~m~EFmd-f@cNjIfb`bs(alIGt-zT!&>Bm>AAg~2RXu;5MHZ{oy>i^etY z{x57PGGxfmPN}j@$V|l+3)(6|f0m@3G{Y3!5AF;1=XufzzyED9H!M<-Hf`FDIdbG! z;qUK%3q8WD0$CkmADY3@I}B0*z9zKH_#!@rf1{hpeV_Xlu8;djm@r|MxaP_K+Lrja z=bo#SF=NJlO6`54K)C`i7!W48kKao&k1>CT^Wyxt4zB0<7gtdJCpSnk926x*9WrOm z{HX#XQaLRfbLY-|KuP2UMVA#w4_pa;fX|99DiwM}N#AB1kKf_ + + + + + + + + Bluetooth chat + + + + + + + + + +
+
+

Bluetooth chat

+
+ +
+
+ + + + +
+
+
+ + \ No newline at end of file diff --git a/project/js/app.client.js b/project/js/app.client.js new file mode 100644 index 0000000..10dd388 --- /dev/null +++ b/project/js/app.client.js @@ -0,0 +1,112 @@ +/*jslint plusplus: true, sloppy: true, todo: true, vars: true, browser: true, devel: true, maxerr: 999 */ +/*global $, tizen, app, ClientModel */ +/** + * @class Client + */ + +function Client(adapter, serviceUUID) { + 'use strict'; + this.adapter = adapter; + this.serviceUUID = serviceUUID; + this.globalSocket = null; + this.init(); + this.discovering = false; + this.chatServerDevice = null; +} + +(function () { // strict mode wrapper + 'use strict'; + + Client.prototype = { + /** + * @type clientModel + */ + model: null, + + /** + * Initialisation function + */ + init: function Client_init() { + this.model = new ClientModel(this); + return this; + }, + + setDiscovering: function Client_setDiscovering(boolean) { + this.discovering = boolean; + app.ui.setDiscoveringProgress(boolean); + }, + + getDiscovering: function Client_getDiscovering() { + return this.discovering; + }, + + searchServer: function Client_searchServer() { + this.model.searchServer(); + }, + + addDeviceToList: function Client_addDeviceToList(device) { + app.ui.addDeviceToList(device); + }, + + stopServerSearching: function Client_stopServerSearching(address) { + if (address !== undefined) { + this.model.stopServerSearching(this.startBonding.bind(this, address, this.connectToService.bind(this))); + } else { + this.model.stopServerSearching(); + } + }, + + startBonding: function Client_startBonding(address, callback) { + this.model.startBonding(address, callback); + }, + + connectToService: function Client_connectToService(device) { + this.model.connectToService(device, this.serviceUUID, this.connectToServiceSuccess.bind(this, device), this.connectToServiceError.bind(this)); + }, + + connectToServiceSuccess: function Client_connectToServiceSuccess(device, socket) { + this.globalSocket = socket; + socket.onmessage = function () { + var data, recvmsg = '', i, len, messageObj; + data = socket.readData(); + len = data.length; + for (i = 0; i < len; i += 1) { + recvmsg += String.fromCharCode(data[i]); + } + messageObj = JSON.parse(recvmsg); + app.ui.displayReceivedMessage(messageObj.name, messageObj.text, messageObj.ping, messageObj.bye); + }; + socket.onerror = function (e) { + console.error('Client onerror'); + socket.close(); + }; + socket.onclose = function () { + this.globalSocket = null; + app.setConnection(false); + }; + app.setConnection(true); + app.ui.showChatPage(device.name); + this.sendPing(); + }, + + connectToServiceError: function Client_connectToServiceError(error) { + console.error('Client_connectToServiceError: ' + error.message); + }, + + sendPing: function Client_sendPing() { + this.model.sendPing(this.adapter.name, this.globalSocket); + }, + + sendMessage: function Client_sendMessage(message, callback) { + this.model.sendMessage(this.adapter.name, this.globalSocket, message, callback); + }, + + sendBye: function Client_sendBye() { + this.model.sendBye(this.adapter.name, this.globalSocket); + }, + + destroyBonding: function Client_destroyBonding() { + this.model.destroyBonding(this.chatServerDevice, app.restartBluetooth.bind(app), app.ui.showStartButtons); + } + }; +}()); diff --git a/project/js/app.client.model.js b/project/js/app.client.model.js new file mode 100644 index 0000000..8b5960e --- /dev/null +++ b/project/js/app.client.model.js @@ -0,0 +1,141 @@ +/*jslint plusplus: true, sloppy: true, todo: true, vars: true, browser: true, devel: true, maxerr: 999 */ +/*global $, tizen, app */ +/** + * @class Model + */ +function ClientModel(parent) { + 'use strict'; + this.client = parent; + this.init(); +} + +(function () { // strict mode wrapper + 'use strict'; + ClientModel.prototype = { + + /** + * API module initialisation + */ + init: function ClientModel_init() {}, + + searchServer: function ClientModel_searchServer() { + var discoverDevicesSuccessCallback = { + onstarted: function () { + this.client.setDiscovering(true); + }.bind(this), + ondevicefound: function (device) { + this.client.addDeviceToList(device); + }.bind(this), + ondevicedisappeared: function (address) {}, + onfinished: function (devices) { + this.client.setDiscovering(false); + }.bind(this) + }; + + this.client.adapter.discoverDevices(discoverDevicesSuccessCallback, function (e) { this.client.setDiscovering(false); }); + }, + + stopServerSearching: function ClientModel_stopServerSearching(callback) { + if (this.client.getDiscovering()) { + this.client.adapter.stopDiscovery(function () { + this.client.setDiscovering(false); + if (typeof callback === 'function') { + callback(); + } + }.bind(this), function (e) { + console.error("Error while stopDiscovery:" + e.message); + }); + } else if (typeof callback === 'function') { + callback(); + } + }, + + startBonding: function ClientModel_startBonding(address, callback) { + this.client.adapter.createBonding(address, function (device) { callback(device); }, function (error) { console.error('bondError: ' + error.message); }); + }, + + connectToService: function ClientModel_connectToService(device, serviceUUID, successCallback, errorCallback) { + this.client.chatServerDevice = device; + try { + device.connectToServiceByUUID(serviceUUID, successCallback, errorCallback); + } catch (error) { + console.error('connectToServiceByUUID ERROR: ' + error.message); + } + }, + + sendPing: function ClientModel_sendPing(name, socket) { + var sendTextMsg, messageObj, messageObjToString, i, len; + sendTextMsg = []; + messageObj = {name: encodeURIComponent(name), text: '', ping: true, bye: false}; + messageObjToString = JSON.stringify(messageObj); + len = messageObjToString.length; + + for (i = 0; i < len; i += 1) { + sendTextMsg[i] = messageObjToString.charCodeAt(i); + } + try { + if (socket !== null && socket.state === "OPEN") { + socket.writeData(sendTextMsg); + } + } catch (error) { + console.error('sendPing: ' + error.message); + } + }, + + sendMessage: function ClientModel_sendMessage(name, socket, message, callback) { + var sendTextMsg = [], messageObj, messageObjToString, i, len; + name = encodeURIComponent(name); + message = encodeURIComponent(message); + messageObj = {name: name, text: message, ping: false, bye: false}; + messageObjToString = JSON.stringify(messageObj); + len = messageObjToString.length; + for (i = 0; i < len; i += 1) { + sendTextMsg[i] = messageObjToString.charCodeAt(i); + } + try { + if (socket !== null && socket.state === "OPEN") { + socket.writeData(sendTextMsg); + callback(message); + } + } catch (error) { + console.error('sendMessage: ' + error.message); + } + }, + + sendBye: function ClientModel_sendBye(name, socket) { + var sendTextMsg = [], messageObj, messageObjToString, i, len; + name = encodeURIComponent(name); + messageObj = {name: name, text: '', ping: false, bye: true}; + messageObjToString = JSON.stringify(messageObj); + len = messageObjToString.length; + for (i = 0; i < len; i += 1) { + sendTextMsg[i] = messageObjToString.charCodeAt(i); + } + try { + if (socket !== null && socket.state === "OPEN") { + socket.writeData(sendTextMsg); + } + } catch (error) { + console.error('sendBye: ' + error.message); + } + }, + + destroyBonding: function ClientModel_destroyBonding(device, restartCallback, showStartButtonsCallback) { + if (device !== null) { + if (device.isBonded) { + this.client.adapter.destroyBonding(device.address, function () { + device = null; + restartCallback(); + }, function (error) { console.error('ClientModel_destroyBonding: ' + error); }); + } else { + device = null; + restartCallback(); + } + } else { + this.stopServerSearching(); + showStartButtonsCallback(); + } + } + + }; +}()); diff --git a/project/js/app.config.js b/project/js/app.config.js new file mode 100644 index 0000000..c40c601 --- /dev/null +++ b/project/js/app.config.js @@ -0,0 +1,29 @@ +/*jslint plusplus: true, sloppy: true, todo: true, vars: true, browser: true, devel: true, maxerr: 999 */ +/*global $, tizen, app */ +/** + * @class Config + */ +function Config() { + 'use strict'; +} + +(function () { // strict mode wrapper + 'use strict'; + Config.prototype = { + + properties: { + 'templateDir': 'templates', + 'templateExtension': '.tpl' + }, + + /** + * Returns config value + */ + get: function (value, defaultValue) { + if (this.properties.hasOwnProperty(value)) { + return this.properties[value]; + } + return defaultValue; + } + }; +}()); diff --git a/project/js/app.helpers.js b/project/js/app.helpers.js new file mode 100644 index 0000000..0437bc6 --- /dev/null +++ b/project/js/app.helpers.js @@ -0,0 +1,19 @@ +/*jslint plusplus: true, sloppy: true, todo: true, vars: true, browser: true, devel: true, maxerr: 999 */ +/*global $, tizen, app */ +/** + * @class Helpers + */ +function Helpers() { + 'use strict'; +} + +(function () { // strict mode wrapper + 'use strict'; + Helpers.prototype = { + + checkStringLength: function Helpers_checkStringLength(value) { + return value.length > 0 ? true : false; + } + + }; +}()); diff --git a/project/js/app.js b/project/js/app.js new file mode 100644 index 0000000..c02479e --- /dev/null +++ b/project/js/app.js @@ -0,0 +1,213 @@ +/*global $, tizen, app, Config, Helpers, Model, Ui, Server, Client */ +var App = null; + +(function () { // strict mode wrapper + 'use strict'; + + /** + * Creates a new application object + * + * @class Application + */ + App = function App() {}; + + App.prototype = { + /** + * @type Array + */ + requires: ['js/app.config.js', + 'js/app.helpers.js', + 'js/app.model.js', + 'js/app.ui.js', + 'js/app.ui.templateManager.js', + 'js/app.ui.events.js', + 'js/app.client.js', + 'js/app.client.model.js', + 'js/app.server.js', + 'js/app.server.model.js' + ], + + /** + * @type Model + */ + model: null, + + /** + * @type Ui + */ + ui: null, + + /** + * @type Config + */ + config: null, + + /** + * @type Helpers + */ + helpers: null, + + /** + * @type Client + */ + client: null, + + /** + * @type Server + */ + server: null, + + /** + * @type String + */ + currentName: '', + + /** + * @type Boolean + */ + doNotSendBye: false, + + /** + * @type Boolean + */ + connection: false, + + /** + * Initialisation function + */ + init: function App_init() { + this.config = new Config(); + this.helpers = new Helpers(); + this.model = new Model(); + this.ui = new Ui(this.initModel.bind(this)); + }, + + initModel: function App_initModel() { + this.model.init(this.checkPowerState.bind(this)); + }, + + /** + * exit application action + */ + exit: function App_exit() { + tizen.application.getCurrentApplication().exit(); + }, + + isConnection: function App_isConnection() { + return this.connection; + }, + + setConnection: function App_setConnection(bool) { + this.connection = bool; + }, + + getDoNotSendBye: function App_getDoNotSendBye() { + return this.doNotSendBye; + }, + + setDoNotSendBye: function App_setDoNotSendBye(bool) { + this.doNotSendBye = bool; + }, + + getCurrentName: function App_getCurrentName() { + return this.currentName; + }, + + getApplicationMode: function App_getApplicationMode() { + var mode = 'start'; + if (this.client !== null) { + mode = 'client'; + } else if (this.server !== null) { + mode = 'server'; + } + return mode; + }, + + resetApplicationMode: function App_resetApplicationMode() { + this.client = null; + this.server = null; + }, + + checkPowerState: function App_checkPowerState() { + this.ui.setContentStartAttributes( + this.model.checkPowerState.bind( + this.model, + this.ui.showPowerOnButton, + this.ui.showStartButtons + ) + ); + }, + + powerOn: function App_powerOn() { + this.model.powerOn(this.ui.showStartButtons); + }, + + powerOff: function App_powerOff() { + this.model.powerOff(this.exit); + }, + + restartBluetooth: function App_restartBluetooth() { + this.model.restartBluetooth(this.powerOn.bind(this)); + }, + + startServer: function App_startServer() { + this.server = new Server(this.model.adapter, this.model.serviceUUID); + this.showKeyboardPage(); + }, + + startClient: function App_startClient() { + this.client = new Client(this.model.adapter, this.model.serviceUUID); + this.showKeyboardPage(); + }, + + showKeyboardPage: function App_showKeyboardPage() { + this.ui.showKeyboardPage(); + }, + + setUserName: function App_setUserName(value) { + this.currentName = value; + }, + + setAdapterName: function App_setAdapterName() { + var changeName = false, mode = this.getApplicationMode(); + if (this.model.adapter.name !== this.currentName) { + changeName = true; + } + if (mode === 'server') { + this.model.setAdapterName(changeName, this.server.registerServer.bind(this.server)); + } else if (mode === 'client') { + this.model.setAdapterName(changeName, this.client.searchServer.bind(this.client)); + } + }, + + isBluetoothVisible: function App_isBluetoothVisible() { + return this.model.adapter.visible; + }, + + clearListOfServers: function App_clearListOfServers() { + this.ui.clearListOfServers(); + }, + + displaySentMessage: function App_displaySentMessage(message) { + this.ui.displaySentMessage(message); + }, + + sendMessage: function App_sendMessage(message) { + var mode = this.getApplicationMode(); + if (mode === 'server') { + this.server.sendMessage(message, this.displaySentMessage.bind(this)); + } else if (mode === 'client') { + this.client.sendMessage(message, this.displaySentMessage.bind(this)); + } + }, + + sendBye: function App_sendBye() { + var mode = this.getApplicationMode(); + if (mode === 'server') { + this.server.sendBye(); + } else if (mode === 'client') { + this.client.sendBye(); + } + } + }; +}()); diff --git a/project/js/app.model.js b/project/js/app.model.js new file mode 100644 index 0000000..9cf77a4 --- /dev/null +++ b/project/js/app.model.js @@ -0,0 +1,85 @@ +/*jslint plusplus: true, sloppy: true, todo: true, vars: true, browser: true, devel: true, maxerr: 999 */ +/*global $, tizen, app */ +/** + * @class Model + */ +function Model() { + 'use strict'; + this.adapter = null; + this.serviceUUID = '5BCE9431-6C75-32AB-AFE0-2EC108A30860'; +} + +(function () { // strict mode wrapper + 'use strict'; + Model.prototype = { + + /** + * API module initialisation + */ + init: function Model_init(callback) { + try { + console.log('getDefaultAdapter'); + var time = new Date().getTime(); + this.adapter = tizen.bluetooth.getDefaultAdapter(); + console.log('getDefaultAdapter OK: ' + (new Date().getTime() - time) + ' milliseconds.'); + callback(); + } catch (error) { + app.ui.showMessagePopup('Problem with bluetooth device. Application can\'t work properly: ' + error.message); + tizen.application.getCurrentApplication().exit(); + } + }, + + checkPowerState: function Model_checkPowerState(showPowerOnButtonCallback, showStartButtonsCallback) { + if (!this.adapter.powered) { + showPowerOnButtonCallback(); + } else { + showStartButtonsCallback(); + } + }, + + powerOn: function Model_powerOn(callback) { + if (!this.adapter.powered) { + try { + this.adapter.setPowered(true, + function () { + setTimeout(function () { callback(); }, 500); + } + ); + } catch (error) { + app.ui.showMessagePopup(error.message); + app.ui.showPowerOnButton(); + } + } else { + callback(); + } + }, + + powerOff: function Model_powerOff(callback) { + var app = tizen.application.getCurrentApplication(); + if (this.adapter.powered) { + this.adapter.setPowered(false, function () { callback(); }, function () { callback(); }); + } else { + callback(); + } + }, + + restartBluetooth: function Model_restartBluetooth(callback) { + if (this.adapter.powered) { + this.adapter.setPowered(false, function () { setTimeout(function () { callback(); }, 500); }, function () {}); + } else { + callback(); + } + }, + + setAdapterName: function Model_setAdapterName(changeName, callback) { + if (changeName) { + this.adapter.setName(app.currentName, function () { + callback(); + }, function () { + }); + } else { + callback(); + } + } + }; +}()); diff --git a/project/js/app.server.js b/project/js/app.server.js new file mode 100644 index 0000000..6cf5c5a --- /dev/null +++ b/project/js/app.server.js @@ -0,0 +1,93 @@ +/*global $, tizen, app, ServerModel */ +/** + * @class Server + */ + +function Server(adapter, serviceUUID) { + 'use strict'; + this.adapter = adapter; + this.serviceUUID = serviceUUID; + this.numberOfClients = 0; + this.globalRecordHandler = null; + this.globalSocket = null; + this.init(); +} + +(function () { // strict mode wrapper + 'use strict'; + + Server.prototype = { + /** + * @type clientModel + */ + model: null, + + /** + * Initialisation function + */ + init: function Server_init() { + this.model = new ServerModel(this); + return this; + }, + + getNumberOfClients: function Server_getNumberOfClients() { + return this.numberOfClients; + }, + + registerServer: function Server_registerServer() { + this.model.registerServer(this.adapter, this.serviceUUID, this.registerServerSuccess.bind(this)); + }, + + registerServerSuccess: function Server_registerServerSuccess(recordHandler) { + this.globalRecordHandler = recordHandler; + recordHandler.onconnect = function (socket) { + this.numberOfClients += 1; + this.globalSocket = socket; + socket.onmessage = function () { + var data, recvmsg = '', i, len, messageObj; + data = socket.readData(); + len = data.length; + for (i = 0; i < len; i += 1) { + recvmsg += String.fromCharCode(data[i]); + } + messageObj = JSON.parse(recvmsg); + app.ui.displayReceivedMessage(messageObj.name, messageObj.text, messageObj.ping, messageObj.bye); + }; + socket.onerror = function (e) { + console.error('Server onerror'); + socket.close(); + }; + socket.onclose = function () { + this.globalSocket = null; + app.setConnection(false); + }; + app.setConnection(true); + }.bind(this); + app.ui.showChatPage(); + }, + + unregisterChatServer: function Server_unregisterChatServer() { + this.model.unregisterChatServer(this.globalRecordHandler, this.unregisterChatServerSuccess.bind(this), this.unregisterChatServerError.bind(this), app.ui.showStartButtons); + }, + + unregisterChatServerSuccess: function Server_unregisterChatServerSuccess() { + this.globalRecordHandler = null; + this.numberOfClients = 0; + app.restartBluetooth(); + }, + + unregisterChatServerError: function Server_unregisterChatServerError() { + console.error('Server_unregisterChatServerError'); + this.numberOfClients = 0; + app.restartBluetooth(); + }, + + sendMessage: function Server_sendMessage(message, callback) { + this.model.sendMessage(this.adapter.name, this.globalSocket, message, callback); + }, + + sendBye: function Server_sendBye() { + this.model.sendBye(this.adapter.name, this.globalSocket); + } + }; +}()); diff --git a/project/js/app.server.model.js b/project/js/app.server.model.js new file mode 100644 index 0000000..771353e --- /dev/null +++ b/project/js/app.server.model.js @@ -0,0 +1,81 @@ +/*global $, tizen, app */ +/** + * @class Model + */ +function ServerModel(parent) { + 'use strict'; + this.server = parent; + this.init(); +} + +(function () { // strict mode wrapper + 'use strict'; + ServerModel.prototype = { + + /** + * API module initialisation + */ + init: function ServerModel_init() {}, + + registerServer: function ServerModel_registerServer(adapter, serviceUUID, callback) { + if (this.server.getNumberOfClients() === 0) { + try { + adapter.registerRFCOMMServiceByUUID(serviceUUID, 'Chat service', callback, function (error) { console.error(error.message); }); + } catch (error) { + console.error(error.message); + } + } + }, + + unregisterChatServer: function ServerModel_unregisterChatServer(globalRecordHandler, successCallback, errorCallback, showButtonsCallback) { + try { + if (globalRecordHandler !== null) { + globalRecordHandler.unregister(successCallback, errorCallback); + } else { + showButtonsCallback(); + } + } catch (error) { + errorCallback(); + } + }, + + sendMessage: function ServerModel_sendMessage(name, socket, message, callback) { + var sendTextMsg = [], messageObj, messageObjToString, i, len; + name = encodeURIComponent(name); + message = encodeURIComponent(message); + messageObj = {name: name, text: message, ping: false, bye: false}; + messageObjToString = JSON.stringify(messageObj); + len = messageObjToString.length; + for (i = 0; i < len; i += 1) { + sendTextMsg[i] = messageObjToString.charCodeAt(i); + } + try { + if (socket !== null && socket.state === "OPEN") { + socket.writeData(sendTextMsg); + callback(message); + } + } catch (error) { + console.error('sendMessage: ' + error.message); + } + }, + + sendBye: function ServerModel_sendBye(name, socket) { + var sendTextMsg = [], messageObj, messageObjToString, i, len; + name = encodeURIComponent(name); + messageObj = {name: name, text: '', ping: false, bye: true}; + messageObjToString = JSON.stringify(messageObj); + len = messageObjToString.length; + for (i = 0; i < len; i += 1) { + sendTextMsg[i] = messageObjToString.charCodeAt(i); + } + try { + if (socket !== null && socket.state === "OPEN") { + socket.writeData(sendTextMsg); + } + } catch (error) { + console.error('sendBye: ' + error.message); + } + } + + }; +}()); diff --git a/project/js/app.ui.events.js b/project/js/app.ui.events.js new file mode 100644 index 0000000..f9ae99f --- /dev/null +++ b/project/js/app.ui.events.js @@ -0,0 +1,214 @@ +/*global $, tizen, app */ +/** + * @class UiEvents + */ +function UiEvents(parent) { + 'use strict'; + this.ui = parent; +} + +(function () { // strict mode wrapper + 'use strict'; + UiEvents.prototype = { + + /** + * Initialization + */ + init: function UiEvents_init() { + this.addPageEvents(); + }, + + /** + * Bind events to pages + */ + addPageEvents: function UiEvents_addPageEvents() { + var self = this; + + $('#start-header .ui-btn-back').on('click', function (event) { + event.preventDefault(); + event.stopPropagation(); + app.powerOff(); + }); + + $('#choose-footer').on('click', '.ui-btn-back', function (event) { + event.preventDefault(); + event.stopPropagation(); + app.setDoNotSendBye(true); + $.mobile.changePage('#start'); + }); + + $('#chat-header').on('click', '.ui-btn-back', function (event) { + event.preventDefault(); + event.stopPropagation(); + if (!app.isConnection()) { + app.setDoNotSendBye(true); + } + $.mobile.changePage('#start'); + }); + + $('#chat-header').on('click', '.ui-btn-back', function (event) { + event.preventDefault(); + }); + + $('#start').on('pagebeforeshow', function () { + self.ui.hideStartButtons(); + self.ui.clearChatDialog(); + if (!app.getDoNotSendBye()) { + app.sendBye(); + } else { + app.setDoNotSendBye(false); + } + if (app.getApplicationMode() === 'server') { + app.server.unregisterChatServer(); + } else if (app.getApplicationMode() === 'client') { + app.client.destroyBonding(); + } + }); + + $('#turnOnButton').on('click', function (event) { + self.ui.hideStartButtons(); + app.powerOn(); + }); + + $('#serverButton').on('click', function (event) { + app.resetApplicationMode(); + app.startServer(); + }); + + $('#clientButton').on('click', function (event) { + app.resetApplicationMode(); + app.startClient(); + }); + + $('#keyboard').on('pagebeforeshow', function () { + $('#keyboard-text').val('').attr('placeholder', 'Type ' + app.getApplicationMode() + ' name'); + $('#keyboard-header > h1').html('Type ' + app.getApplicationMode() + ' name'); + }); + + $('#keyboard').on('pageshow', function () { + setTimeout(function () { $('#keyboard-text').focus(); }, 500); + }); + + $('#keyboard-ok-button').on('click', function (event) { + event.preventDefault(); + var value = $('#keyboard-text').val(), mode; + if (value.length !== 0) { + app.setUserName(value); + mode = app.getApplicationMode(); + if (mode === 'server') { + app.setAdapterName(); + } else if (mode === 'client') { + $.mobile.changePage('#choose'); + } + } + }); + + $('#choose').on('pagebeforeshow', function () { + app.setAdapterName(); + }); + + $('#choose').on('pagehide', function () { + app.clearListOfServers(); + app.client.stopServerSearching(); + }); + + $('#choose-content').on('click', 'ul.ui-listview li', function () { + app.client.stopServerSearching($(this).attr('address')); + }); + + $('#chat').on('pagebeforeshow', function () { + $('#chat-header-type').html(app.getApplicationMode()); + $('#chat-header-name').html(app.getCurrentName()); + if ($(this).data('serverName') !== undefined) { + $('#chat-header-type').append(' - connected to ' + $(this).data('serverName')); + $(this).removeData('serverName'); + } + self.ui.checkSendButtonState(); + }); + + $('#chat').on('pageshow', function () { + if (app.getApplicationMode() === 'server' && !app.isBluetoothVisible()) { + setTimeout(function () { app.ui.showMessagePopup('Please make your Bluetooth visible in Settings.'); }, 500); + } + }); + + $('#chat').on('pagehide', function () { + $('#text').val(''); + app.setConnection(false); + }); + + $('#text').on('input', function () { + self.ui.checkSendButtonState(); + }); + + $('#text').on('focus', function () { + var content = $('#chat-content'); + if (self.ui.scrolltimeout !== null) { + clearTimeout(self.ui.scrolltimeout); + } + self.ui.scrolltimeout = setTimeout(function () { + self.ui.scrolltimeout = null; + self.ui.scrollToBottom(content); + }, 1000); + }); + + $('#text').on('blur', function () { + var content = $('#chat-content'); + if (self.ui.scrolltimeout !== null) { + clearTimeout(self.ui.scrolltimeout); + } + self.ui.scrolltimeout = setTimeout(function () { + self.ui.scrolltimeout = null; + self.ui.scrollToBottom(content); + }, 700); + }); + + $('#ui-mySend').on('click', function (event) { + event.stopPropagation(); + var message = $('#text').val(); + $('#text').val(''); + self.ui.disableSendButton(); + app.sendMessage(message); + }); + + $('body').on('click', '#byeOK', function () { + self.ui.hideByePopup(); + $('#keyboard-back-button').trigger('click'); + }); + + $('body').on('touchstart', '#byePopup-screen', function () { + $('#byeOK').trigger('click'); + }); + + $('body').on('click', '#messageOK', function () { + self.ui.hideMessagePopup(); + }); + + $('body').on('touchstart', '#messagePopup-screen', function () { + $('#messageOK').trigger('click'); + }); + + $('#chat-content').on('touchstart', function () { + if (self.ui.scrolltimeout !== null) { + clearTimeout(self.ui.scrolltimeout); + self.ui.scrolltimeout = null; + } + }); + + window.addEventListener('tizenhwkey', function(e) { + if (e.keyName == "back") { + event.preventDefault(); + app.setDoNotSendBye(true); + if ($.mobile.activePage.attr('id') === 'start') { + tizen.application.getCurrentApplication().exit(); + } else if ($.mobile.activePage.attr('id') === 'chat') { + $.mobile.changePage('#start'); + } else { + history.back(); + } + } + }); + + } + }; +}()); diff --git a/project/js/app.ui.js b/project/js/app.ui.js new file mode 100644 index 0000000..9bd9d99 --- /dev/null +++ b/project/js/app.ui.js @@ -0,0 +1,245 @@ +/*global $, tizen, app, UiEvents, TemplateManager, document, window, setTimeout */ +/** + * @class Ui + */ + +function Ui(callback) { + 'use strict'; + this.init(callback); +} + +(function () { // strict mode wrapper + 'use strict'; + Ui.prototype = { + + templateManager: null, + + /** + * UI object for UI events + */ + uiEvents: null, + + /** + * Timeout for chat scroll. + */ + scrolltimeout: null, + + /** + * UI module initialisation + */ + init: function Ui_init(callback) { + this.templateManager = new TemplateManager(); + this.uiEvents = new UiEvents(this); + $.mobile.tizen.disableSelection(document); + + $(document).ready(this.domInit.bind(this, callback)); + }, + + /** + * When DOM is ready, initialise it (bind events) + */ + domInit: function Ui_domInit(callback) { + var templates = [ + 'keyboard_page', + 'chat_page', + 'choose_page', + 'server_row', + 'left_bubble', + 'right_bubble', + 'bye_popup', + 'message_popup' + ]; + + this.templateManager.loadToCache(templates, this.initPages.bind(this, callback)); + }, + + initPages: function Ui_initPages(callback) { + var pages = [], body = $('body'); + + body.append(this.templateManager.get('bye_popup')) + .append(this.templateManager.get('message_popup')) + .trigger('create'); + + pages.push(this.templateManager.get('keyboard_page')); + pages.push(this.templateManager.get('chat_page')); + pages.push(this.templateManager.get('choose_page')); + body.append(pages.join('')); + + this.uiEvents.init(); + this.fixContentHeight(); + callback(); + }, + + setContentStartAttributes: function Ui_setContentStartAttributes(callback) { + var contentStart, contentStartHeight; + contentStart = $('#start-content'); + if (contentStart.height() > $(window).height()) { + contentStartHeight = $(window).height() - $('#start-header').height() + - parseInt(contentStart.css('padding-top'), 10) - parseInt(contentStart.css('padding-bottom'), 10); + } else { + contentStartHeight = contentStart.height(); + } + setTimeout(function () { // workaround (setTimeout with 0 delay) + contentStart + .css('height', contentStartHeight + 'px') + .css('min-height', 'auto') + .css('width', contentStart.width() + 'px'); + $('#start').css('min-height', 'auto'); + callback(); + }, 0); + }, + + showChatPage: function Ui_showChatPage(serverName) { + if (serverName !== undefined) { + $('#chat').data('serverName', serverName); + } + $.mobile.changePage('#chat'); + }, + + showKeyboardPage: function Ui_showKeyboardPage() { + $.mobile.changePage('#keyboard'); + }, + + clearChatDialog: function Ui_clearChatDialog() { + $('#chat-content .ui-listview').empty(); + }, + + showPowerOnButton: function Ui_showPowerOnButton() { + $('#start-monit').hide(); + $('#serverButton').hide(); + $('#clientButton').hide(); + $('#turnOnButton').show(); + }, + + showStartButtons: function Ui_showStartButtons() { + $('#start-monit').hide(); + $('#turnOnButton').hide(); + $('#serverButton').show(); + $('#clientButton').show(); + }, + + hideStartButtons: function Ui_hideStartButtons() { + $('#serverButton').hide(); + $('#clientButton').hide(); + $('#turnOnButton').hide(); + $('#start-monit').show(); + }, + + addDeviceToList: function Ui_addDeviceToList(device) { + var listElement, address, sub2, ul = $('#choose-content ul.ui-listview'); + + listElement = this.templateManager.get('server_row', { + 'deviceAddress': device.address, + 'deviceName': device.name + }); + + ul.append(listElement); + ul.listview('refresh'); + }, + + clearListOfServers: function Ui_clearListOfServers() { + $('#choose-content ul.ui-listview').empty(); + }, + + showByePopup: function Ui_showByePopup(name) { + var mode = app.getApplicationMode(), message = $('#byeMessage'); + if (mode === 'server') { + message.html('Client name "' + name + '" is unavailable.\nYour bluetooth device will be automatically restarted.'); + } else if (mode === 'client') { + message.html('Server name "' + name + '" is unavailable.\nYour bluetooth device will be automatically restarted.'); + } + $('#byePopup').popup('open', {'positionTo': 'window'}); + }, + + hideByePopup: function Ui_hideByePopup() { + $('#byePopup').popup('close'); + }, + + showMessagePopup: function Ui_showMessagePopup(message) { + var messagePopup = $('#messagePopup'); + messagePopup.find('.ui-popup-text').text(message); + messagePopup.popup('open', {'positionTo': 'window'}); + }, + + hideMessagePopup: function Ui_hideMessagePopup() { + $('#messagePopup').popup('close'); + }, + + displayReceivedMessage: function Ui_displayReceivedMessage(name, text, ping, bye) { + var listElement, span, ul; + text = decodeURIComponent(text); + name = decodeURIComponent(name); + if (bye) { + this.showByePopup(name); + } else if (ping) { + app.setConnection(true); + $('#chat-header-type').append(' - connected with ' + name); + this.checkSendButtonState(); + } else { + listElement = this.templateManager.get('left_bubble', { + 'text': text + }); + ul = $('#chat-content > .ui-scrollview-view > ul'); + ul.append(listElement); + ul.listview('refresh'); + } + }, + + enableSendButton: function Ui_enableSendButton() { + $('#ui-mySend') + .css({'pointer-events': 'auto', 'color': '#000'}) + .removeClass('ui-disabled'); + }, + + disableSendButton: function Ui_disableSendButton() { + setTimeout( function() { + $('#ui-mySend') + .css({'pointer-events': 'none', 'color': '#bbb'}) + .addClass('ui-disabled'); + }, + 0 + ); + }, + + checkSendButtonState: function Ui_checkSendButtonState() { + if (app.helpers.checkStringLength($('#text').val().trim()) && app.isConnection()) { + this.enableSendButton(); + } else { + this.disableSendButton(); + } + }, + + scrollToBottom: function Ui_scrollToBottom(element) { + var bottom = element.children().first().outerHeight(true) - element.height(); + element.scrollview('scrollTo', 0, -Math.max(0, bottom), 0); + }, + + displaySentMessage: function Ui_displaySentMessage(message) { + var listElement, span, ul, content, self = this; + message = decodeURIComponent(message); + listElement = this.templateManager.get('right_bubble', { + 'text': message + }); + content = $('#chat-content'); + ul = content.find('ul'); + ul.append(listElement); + ul.listview('refresh'); + this.checkSendButtonState(); + this.scrolltimeout = setTimeout(function () { + self.scrolltimeout = null; + self.scrollToBottom(content); + }, 700); + }, + + setDiscoveringProgress: function Ui_setDiscoveringProgress(boolean) { + $('#discovering').progress('hide', !boolean).progress('running', boolean); + }, + + fixContentHeight: function Ui_fixContentHeight() { + var contentHeight = screen.availHeight - $('div[data-role="header"]').outerHeight() - $('div[data-role="footer"]').outerHeight(); + $('div[data-role="content"]').css('height', contentHeight); + } + + }; + +}()); diff --git a/project/js/app.ui.templateManager.js b/project/js/app.ui.templateManager.js new file mode 100644 index 0000000..68c6678 --- /dev/null +++ b/project/js/app.ui.templateManager.js @@ -0,0 +1,111 @@ +/*global tizen, $, app */ +/** + * @class TemplateManager + */ +function TemplateManager() { + 'use strict'; + this.init(); +} + +(function () { // strict mode wrapper + 'use strict'; + TemplateManager.prototype = { + + /** + * Template cache + */ + cache: {}, + + /** + * UI module initialisation + */ + init: function init() { + }, + + /** + * Returns template html (from cache) + * @param {string} tplName + * @param {string} tplParams + */ + get: function TemplateManager_get(tplName, tplParams) { + if (this.cache[tplName] !== undefined) { + return this.getCompleted(this.cache[tplName], tplParams); + } + return ''; + }, + + /** + * Load templates to cache + * @param {string} tplNames + * @param {function} onSuccess + */ + loadToCache: function TemplateManager_loadToCache(tplNames, onSuccess) { + var self = this, + cachedTemplates = 0, + tplName, + tplPath; + + if ($.isArray(tplNames)) { + + // for each template + $.each(tplNames, function (index, fileName) { + + // cache template html + if (self.cache[fileName] === undefined) { + tplName = [fileName, app.config.get('templateExtension')].join(''); + tplPath = [app.config.get('templateDir'), tplName].join('/'); + + $.ajax({ + url: tplPath, + cache: true, + dataType: 'html', + async: true, + success: function (data) { + // increase counter + cachedTemplates += 1; + + // save to cache + self.cache[fileName] = data; + + // if all templates are cached launch callback + if (cachedTemplates >= tplNames.length && typeof onSuccess === 'function') { + onSuccess(); + } + }, + error: function (jqXHR, textStatus, errorThrown) { + console.error('templateManagerError: ' + errorThrown); + } + }); + } else { + // template is already cached + cachedTemplates += 1; + // if all templates are cached launch callback + if (cachedTemplates >= tplNames.length && typeof onSuccess === 'function') { + onSuccess(); + } + } + }); + + } + }, + + /** + * Returns template completed by specified params + * @param {string} tplHtml + * @param {string} tplParams + */ + getCompleted: function TemplateManager_getCompleted(tplHtml, tplParams) { + var tplParam, replaceRegExp; + + for (tplParam in tplParams) { + if (tplParams.hasOwnProperty(tplParam)) { + replaceRegExp = new RegExp(['%', tplParam, '%'].join(''), 'g'); + tplHtml = tplHtml.replace(replaceRegExp, tplParams[tplParam]); + } + } + + return tplHtml; + } + }; + +}()); \ No newline at end of file diff --git a/project/js/main.js b/project/js/main.js new file mode 100644 index 0000000..1a2870e --- /dev/null +++ b/project/js/main.js @@ -0,0 +1,63 @@ +/* + * Copyright 2013 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*global $, tizen, App */ +var app = null; + +(function () { // strict mode wrapper + 'use strict'; + + ({ + /** + * Loader init - load the App constructor + */ + init: function init() { + var self = this; + $.getScript('js/app.js') + .done(function () { + app = new App(); + self.loadLibs(); + }) + .fail(this.onGetScriptError); + }, + + /** + * Load dependencies + */ + loadLibs: function loadLibs() { + var loadedLibs = 0; + if ($.isArray(app.requires)) { + $.each(app.requires, function (index, filename) { + $.getScript(filename) + .done(function () { + loadedLibs += 1; + if (loadedLibs >= app.requires.length) { + app.init(); + } + }) + .fail(this.onGetScriptError); + }); + } + }, + + /** + * Handle ajax errors + */ + onGetScriptError: function onGetScriptError(e, jqxhr, setting, exception) { + console.error('An error occurred: ' + e.message); + } + }).init(); // run the loader +}()); diff --git a/project/templates/bye_popup.tpl b/project/templates/bye_popup.tpl new file mode 100644 index 0000000..69bc1bf --- /dev/null +++ b/project/templates/bye_popup.tpl @@ -0,0 +1,6 @@ +
+
+
+ Ok +
+
diff --git a/project/templates/chat_page.tpl b/project/templates/chat_page.tpl new file mode 100644 index 0000000..57ae3aa --- /dev/null +++ b/project/templates/chat_page.tpl @@ -0,0 +1,20 @@ +
+
+

+
+ +
+
    +
    + + +
    \ No newline at end of file diff --git a/project/templates/choose_page.tpl b/project/templates/choose_page.tpl new file mode 100644 index 0000000..102d358 --- /dev/null +++ b/project/templates/choose_page.tpl @@ -0,0 +1,10 @@ +
    +
    +

    Choose your server

    +
    +
    + +
    +
      +
      +
      \ No newline at end of file diff --git a/project/templates/keyboard_page.tpl b/project/templates/keyboard_page.tpl new file mode 100644 index 0000000..1722089 --- /dev/null +++ b/project/templates/keyboard_page.tpl @@ -0,0 +1,16 @@ +
      +
      +

      +
      + +
      + +
      +
      +
      + +
      +
      +
      \ No newline at end of file diff --git a/project/templates/left_bubble.tpl b/project/templates/left_bubble.tpl new file mode 100644 index 0000000..2d20b1b --- /dev/null +++ b/project/templates/left_bubble.tpl @@ -0,0 +1,3 @@ +
    • + %text% +
    • \ No newline at end of file diff --git a/project/templates/message_popup.tpl b/project/templates/message_popup.tpl new file mode 100644 index 0000000..d69aafd --- /dev/null +++ b/project/templates/message_popup.tpl @@ -0,0 +1,6 @@ +
      +
      +
      + OK +
      +
      diff --git a/project/templates/right_bubble.tpl b/project/templates/right_bubble.tpl new file mode 100644 index 0000000..507e30f --- /dev/null +++ b/project/templates/right_bubble.tpl @@ -0,0 +1,3 @@ +
    • + %text% +
    • \ No newline at end of file diff --git a/project/templates/server_row.tpl b/project/templates/server_row.tpl new file mode 100644 index 0000000..7780cc4 --- /dev/null +++ b/project/templates/server_row.tpl @@ -0,0 +1,7 @@ +
    • + +
      %deviceName%
      + %deviceAddress% + +
      +
    • \ No newline at end of file diff --git a/tizen-app-template.xml b/tizen-app-template.xml new file mode 100755 index 0000000..9bad27d --- /dev/null +++ b/tizen-app-template.xml @@ -0,0 +1,12 @@ + + + BluetoothChat + TIZEN + + description.xml + + + + + + diff --git a/tizen_32.png b/tizen_32.png new file mode 100644 index 0000000000000000000000000000000000000000..61f35c0507d8a7275c92019e8dcc399148d7e1d9 GIT binary patch literal 4563 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 literal 0 HcmV?d00001 diff --git a/tizen_64.png b/tizen_64.png new file mode 100644 index 0000000000000000000000000000000000000000..b1880832b1ee1bf80498667f1dde9b8b744761ec GIT binary patch literal 6849 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 literal 0 HcmV?d00001 -- 2.7.4