ChatsPage.qml 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. import QtQuick 1.0
  2. MyPage {
  3. id: pageOpenChats
  4. height: mytheme.displayHeight
  5. width: mytheme.displayWidth
  6. color: "white"
  7. anchors.fill: parent
  8. radius: mytheme.radiusMainWin
  9. clip: true
  10. property string clickedItem
  11. Text {
  12. id: txtBanner
  13. color: "gray"
  14. font.pixelSize: 40
  15. text: "Nothing open yet"
  16. anchors.centerIn: parent
  17. visible: xmppClient.openChats.count() === 0 ? true : false
  18. smooth: true
  19. }
  20. Component.onCompleted: {
  21. /* блокировка ориентации */
  22. main.appOrientation = main.orPortrait
  23. }
  24. Connections {
  25. target: xmppClient
  26. onChatOpened: {
  27. //console.log("*** onChatOpened:" + bareJid + "; " + isMuc);
  28. }
  29. onChatClosed: {
  30. //console.log("*** onChatClosed: " + bareJid + "; " + isMuc);
  31. if( isMuc ) {
  32. muc.leaveChat();
  33. }
  34. }
  35. }
  36. Component {
  37. id: componentDelegate
  38. Item {
  39. id: delegateItem
  40. width: gridView.cellWidth
  41. height: gridView.cellHeight
  42. property alias pic: delegateImage.source
  43. property bool currentChat: false
  44. function animBack() {
  45. itemAnimBack.start()
  46. }
  47. SequentialAnimation {
  48. id:animClose
  49. ParallelAnimation {
  50. NumberAnimation {
  51. from: 1
  52. to: 0
  53. property: "scale"
  54. duration: 250
  55. target: delegateItem
  56. }
  57. NumberAnimation {
  58. from: 1
  59. to: 0.2
  60. property: "opacity"
  61. duration: 250
  62. target: delegateItem
  63. }
  64. }
  65. ScriptAction {
  66. script: {
  67. if( contactItemType == 1 ) {
  68. muc.jidRoom = contactJid
  69. }
  70. xmppClient.closeChat( contactJid )
  71. }
  72. }
  73. }
  74. states: [
  75. State {
  76. name: "view"
  77. PropertyChanges { target: imgClose; visible: false }
  78. PropertyChanges { target: wrapper; scale: 1.0 }
  79. PropertyChanges { target: imgClose; opacity: 0 }
  80. PropertyChanges { target: pageOpenChats; stateChatClose: false }
  81. PropertyChanges { target: curtain; opacity: 0 }
  82. },
  83. State {
  84. name: "close"
  85. PropertyChanges { target: imgClose; visible: true }
  86. PropertyChanges { target: wrapper; scale: 0.95 }
  87. PropertyChanges { target: imgClose; opacity: 1.0 }
  88. PropertyChanges { target: pageOpenChats; stateChatClose: true }
  89. PropertyChanges { target: curtain; opacity: 0.5 }
  90. }
  91. ]
  92. state: "view"
  93. transitions: Transition {
  94. NumberAnimation { properties: "scale, opacity"; duration: 300 }
  95. }
  96. Rectangle {
  97. id: wrapper
  98. border.color: "gray"
  99. border.width: currentChat ? 2 : 1
  100. color: "lightgray"
  101. radius: 5
  102. width: gridView.cellWidth - 10
  103. height: gridView.cellHeight - 10
  104. anchors.centerIn: parent
  105. //clip: true
  106. Rectangle {
  107. id: curtain
  108. z: 4
  109. anchors.fill: parent
  110. color: "black"
  111. radius: wrapper.radius
  112. }
  113. Image {
  114. id: imgClose
  115. z: 5
  116. source: "qrc:/qml/images/app_close.png"
  117. anchors.right: parent.right
  118. anchors.rightMargin: -10
  119. anchors.top: parent.top
  120. anchors.topMargin: - 10
  121. opacity: 1.0
  122. MouseArea {
  123. anchors.fill: parent
  124. onClicked: {
  125. animClose.running = true
  126. }
  127. }
  128. }
  129. Image {
  130. id: imgPresence
  131. source: contactPicStatus //TODO: in case MUC change it to my status
  132. anchors.top: parent.top; anchors.topMargin: 5
  133. anchors.left: parent.left; anchors.leftMargin: 5
  134. z: 2
  135. Text {
  136. id: txtUnreadMsg
  137. text: contactUnreadMsg
  138. font.pixelSize: 22
  139. anchors.centerIn: parent
  140. visible: contactUnreadMsg != 0
  141. z: 1
  142. }
  143. Image {
  144. id: imgNewMsg
  145. source: "qrc:/qml/images/message.png"
  146. anchors.centerIn: parent
  147. smooth: true
  148. scale: 0.8
  149. visible: contactUnreadMsg != 0
  150. SequentialAnimation {
  151. running: contactUnreadMsg != 0
  152. loops: Animation.Infinite
  153. NumberAnimation {
  154. target: imgNewMsg
  155. property: "opacity"
  156. from: 1; to: 0.4
  157. duration: 1300
  158. easing.type: Easing.InOutQuad
  159. }
  160. NumberAnimation {
  161. target: imgNewMsg
  162. property: "opacity"
  163. from: 0.4; to: 1
  164. duration: 1300
  165. easing.type: Easing.InOutQuad
  166. }
  167. }
  168. }
  169. }
  170. Image {
  171. id: imgFrame
  172. anchors.centerIn: parent
  173. smooth: true
  174. source: "qrc:/qml/images/chat_frame.png"
  175. z:1
  176. }
  177. Image {
  178. id: delegateImage
  179. z: 0
  180. source: contactItemType == 0 ? (contactPicAvatar === "" ? "qrc:/qml/images/avatar.png" : contactPicAvatar) : "qrc:/qml/images/muc.png"
  181. anchors.centerIn: parent
  182. smooth: true
  183. width: 120
  184. height: 120
  185. Rectangle {
  186. z: -1
  187. color: "white"
  188. height: 160
  189. width: 160
  190. radius: 80
  191. anchors.centerIn: parent
  192. }
  193. }
  194. Text {
  195. id: txtNameOrJid
  196. z: 1
  197. anchors.horizontalCenter: parent.horizontalCenter
  198. anchors.bottom: parent.bottom
  199. anchors.bottomMargin: contactName === "" ? 20 : 30
  200. text: contactName === "" ? contactJid : contactName
  201. font.pixelSize: 20
  202. color: "blue"
  203. Component.onCompleted: {
  204. if( delegateItem.width < txtNameOrJid.width ) {
  205. var nName = txtNameOrJid.text;
  206. var pos = nName.indexOf("@");
  207. if( pos > 1 )
  208. {
  209. var xName = nName.substring(0, pos+1);
  210. xName += "\n";
  211. xName += nName.substring(pos+1);
  212. txtNameOrJid.text = xName;
  213. txtNameOrJid.anchors.bottomMargin = 16
  214. txtNameOrJid.font.pixelSize = 18
  215. if( delegateItem.width < txtNameOrJid.width ) {
  216. txtNameOrJid.font.pixelSize = 16
  217. txtNameOrJid.wrapMode = TextEdit.WrapAtWordBoundaryOrAnywhere
  218. }
  219. }
  220. else
  221. {
  222. txtNameOrJid.font.pixelSize = 16
  223. txtNameOrJid.wrapMode = TextEdit.WrapAtWordBoundaryOrAnywhere
  224. }
  225. }
  226. }
  227. }
  228. Text {
  229. z: 1
  230. anchors.horizontalCenter: parent.horizontalCenter
  231. anchors.bottom: parent.bottom
  232. anchors.bottomMargin: 7
  233. text: contactJid
  234. visible: contactName === "" ? false : true
  235. font.pixelSize: 16
  236. color: "gray"
  237. font.italic: true
  238. }
  239. transform: [
  240. Rotation {
  241. id: plateRotation
  242. angle: -90
  243. axis { x: 0; y: 1; z: 0 }
  244. origin.x: -250 //-200
  245. origin.y: -10 //50
  246. },
  247. Rotation {
  248. id: plateFlip
  249. angle: 0
  250. axis { x: 1; y: 0; z: 0 }
  251. origin.x: 50
  252. origin.y: 50
  253. }
  254. ]
  255. /* itemAnim - вперед: вход на страницу */
  256. SequentialAnimation {
  257. id: itemAnim
  258. PauseAnimation { duration: Math.random()*600 }
  259. ParallelAnimation {
  260. NumberAnimation {
  261. target: plateRotation
  262. properties: "angle"
  263. easing.type: Easing.InOutCubic //Easing.OutCubic
  264. from: -90
  265. to: 0
  266. duration: 800
  267. }
  268. NumberAnimation {
  269. target: delegateItem
  270. properties: "opacity"
  271. easing.type: Easing.InOutCubic
  272. from: 0.3
  273. to: 1
  274. duration: 800
  275. }
  276. }
  277. }
  278. /* itemAnimBack - назад: уход со страницы */
  279. ParallelAnimation {
  280. id: itemAnimBack
  281. property int __timeAnim: 700 //длительность всей анимации
  282. SequentialAnimation {
  283. PauseAnimation {
  284. duration: delegateItem.currentChat ? (gridView.count == 1 ? 100 : itemAnimBack.__timeAnim) : Math.random()*itemAnimBack.__timeAnim
  285. }
  286. ParallelAnimation {
  287. NumberAnimation {
  288. target: plateRotation
  289. properties: "angle"
  290. easing.type: Easing.OutCubic
  291. from: 0
  292. to: -90
  293. duration: 500
  294. }
  295. NumberAnimation {
  296. target: delegateItem
  297. properties: "opacity"
  298. easing.type: Easing.InOutCubic
  299. from: 1
  300. to: 0.3
  301. duration: 500
  302. }
  303. }
  304. }
  305. SequentialAnimation {
  306. id: shakeAnim
  307. //PauseAnimation { duration: Math.random()*50 }
  308. NumberAnimation { target: delegateItem; property: "rotation"; to: 2; duration: 50 }
  309. NumberAnimation { target: delegateItem; property: "rotation"; to: -2; duration: 100 }
  310. NumberAnimation { target: delegateItem; property: "rotation"; to: 0; duration: 50 }
  311. loops: delegateItem.currentChat ? 7 : 0
  312. alwaysRunToEnd: true
  313. }
  314. ScriptAction {
  315. script: {
  316. if( delegateItem.currentChat ) {
  317. xmppClient.chatJid = contactJid
  318. __pageNextPause = gridView.count == 1 ? 400 : itemAnimBack.__timeAnim + 300
  319. if( contactItemType == 0 ) {
  320. __pageNext = "qrc:/qml/MessagesPage.qml"
  321. } else {
  322. __pageNext = "qrc:/qml/MucPage.qml"
  323. }
  324. xmppClient.resetUnreadMessages( contactJid ) //сброс непрочитанных сообщ.
  325. animClosePage.running = true //запуск анимации закрытия окна
  326. }
  327. }
  328. }
  329. } //ParallelAnimation
  330. MouseArea {
  331. id: delegateMouseArea
  332. hoverEnabled: true
  333. anchors.fill: parent
  334. }
  335. Component.onCompleted: {
  336. itemAnim.start()
  337. }
  338. }
  339. } //Item
  340. } //Component { componentDelegate }
  341. Rectangle {
  342. id: panelHeader
  343. z: 1
  344. width: parent.width
  345. height: 15
  346. anchors.top: parent.top
  347. anchors.left: parent.left
  348. gradient: Gradient {
  349. GradientStop { position: 0; color: pageOpenChats.color }
  350. GradientStop { position: 0.5; color: pageOpenChats.color }
  351. GradientStop { position: 1; color: "transparent" }
  352. }
  353. }
  354. Rectangle {
  355. id: panelFooter
  356. z: 1
  357. width: parent.width
  358. height: 15
  359. anchors.bottom: toolBar.top
  360. anchors.left: parent.left
  361. gradient: Gradient {
  362. GradientStop { position: 0; color: "transparent" }
  363. GradientStop { position: 0.5; color: pageOpenChats.color }
  364. GradientStop { position: 1; color: pageOpenChats.color }
  365. }
  366. }
  367. property bool stateChatClose: false
  368. GridView {
  369. id: gridView
  370. model: xmppClient.openChats
  371. anchors.top: panelHeader.bottom
  372. anchors.bottom: panelFooter.top
  373. width: parent.width
  374. height: parent.height
  375. cellHeight: 240
  376. cellWidth: 240
  377. delegate: componentDelegate
  378. focus: true
  379. MouseArea {
  380. id: ma
  381. enabled: !stateChatClose
  382. anchors.fill: parent
  383. onPressAndHold: {
  384. for( var L=0; L<gridView.count; L++ ) {
  385. gridView.currentIndex = L
  386. if( gridView.currentItem.state == "view" ) {
  387. gridView.currentItem.state = "close"
  388. } else {
  389. gridView.currentItem.state = "view"
  390. }
  391. }
  392. }
  393. onClicked: {
  394. var currItem = gridView.indexAt( ma.mouseX , ma.mouseY )
  395. if( currItem >= 0 )
  396. {
  397. for( var L=0; L<gridView.count; L++ ) {
  398. if( L !== currItem ) {
  399. gridView.currentIndex = L
  400. gridView.currentItem.currentChat = false
  401. gridView.currentItem.animBack()
  402. } else {
  403. gridView.currentIndex = L
  404. panelHeader.visible = false
  405. panelFooter.visible = false
  406. gridView.currentItem.border
  407. gridView.currentItem.currentChat = true
  408. gridView.currentItem.animBack()
  409. }
  410. }
  411. }
  412. } //onClicked
  413. } //MouseArea
  414. } //GridView
  415. /*****************************************************************************/
  416. property string __pageNext: "qrc:/qml/RosterPage.qml"
  417. property int __pageNextPause: 1000
  418. SequentialAnimation {
  419. id: animClosePage
  420. running: false
  421. PauseAnimation { duration: __pageNextPause }
  422. ScriptAction {
  423. script: {
  424. //main.loadPage = __pageNext
  425. pageOpenChats.closePage( __pageNext )
  426. }
  427. }
  428. }
  429. ToolBar {
  430. id: toolBar
  431. z: 5
  432. ToolButton {
  433. id: toolBarButtonDialog
  434. icon: "qrc:/qml/images/bar_roster.png"
  435. anchors.left: parent.left
  436. anchors.leftMargin: 30
  437. onClicked: {
  438. for( var L=0; L<gridView.count; L++ ) {
  439. gridView.currentIndex = L
  440. gridView.currentItem.animBack()
  441. }
  442. if( xmppClient.openChats.count() === 0 ) {
  443. __pageNextPause = 100
  444. } else {
  445. __pageNextPause = 1200 //1600
  446. }
  447. __pageNext = "qrc:/qml/RosterPage.qml"
  448. animClosePage.running = true
  449. }
  450. visible: !stateChatClose
  451. pauseAnim: 500
  452. }
  453. ToolButton {
  454. id: toolBarButtonNormalState
  455. icon: "qrc:/qml/images/bar_ok.png"
  456. //anchors.left: parent.left
  457. //anchors.leftMargin: 100
  458. anchors.horizontalCenter: parent.horizontalCenter
  459. onClicked: {
  460. for( var L=0; L<gridView.count; L++ ) {
  461. gridView.currentIndex = L
  462. gridView.currentItem.state = "view"
  463. }
  464. stateChatClose = false
  465. }
  466. visible: stateChatClose
  467. }
  468. /*ToolButton {
  469. id: toolBarButtonCloseAll
  470. icon: "qrc:/qml/images/bar_close.png"
  471. anchors.right: parent.right
  472. anchors.rightMargin: 100
  473. onClicked: {
  474. for( var L=0; L<gridView.count; L++ ) {
  475. gridView.currentIndex = L
  476. gridView.currentItem.state = "view"
  477. //cppMyXmppClient.closeChat( contactJid )
  478. }
  479. stateChatClose = false
  480. }
  481. visible: stateChatClose
  482. }*/
  483. }
  484. }