MucPage.qml 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. import QtQuick 1.1
  2. import "main.js" as Engine
  3. MyPage {
  4. id: mucPage
  5. /************************************************************/
  6. colorPage: "white"
  7. property string avatarPic: ""
  8. //property string resourceJid: ""
  9. Connections {
  10. target: muc
  11. onParticipantChanged: {
  12. console.log("QML: XmppMuc::onParticipantChanged(): " + nickName)
  13. }
  14. onParticipantAdded: {
  15. console.log("QML: XmppMuc::onParticipantAdded(): " + nickName)
  16. listModelParticipants.append( { jid:nickName } )
  17. }
  18. onParticipantRemoved: {
  19. console.log("QML: XmppMuc::onParticipantRemoved(): " + nickName)
  20. for( var x=0; x<listModelParticipants.count; x++)
  21. {
  22. var name = listModelParticipants.get(x).jid
  23. if( name == nickName ) {
  24. listModelParticipants.remove( x )
  25. break
  26. }
  27. }
  28. }
  29. }
  30. Component.onCompleted: {
  31. /* разблокировка ориентации */
  32. main.appOrientation = main.orAuto
  33. /* инициализация muc объекта текущим jid-ом комнаты */
  34. muc.jidRoom = xmppClient.chatJid
  35. /* открываем чат и инициализируем список сообщениями
  36. * которые были ранее с этим собеседником */
  37. xmppClient.openChat( xmppClient.chatJid )
  38. /* запрашиваем его аватарку */
  39. //avatarPic = xmppClient.getAvatarByJid( xmppClient.chatJid )
  40. /* если последнее сообщение было от собеседника чата
  41. * то инициализируем ресурс mucPage.resourceJid
  42. * ресурсом его последнего сообщения */
  43. /*if( xmppClient.bareJidLastMsg == xmppClient.chatJid ) {
  44. mucPage.resourceJid = xmppClient.resourceLastMsg
  45. }*/
  46. var listParticipants = muc.getParticipants( )
  47. listModelParticipants.clear();
  48. /* инициализация списка собеседников чата */
  49. for( var z=0; z<listParticipants.length; z++ )
  50. {
  51. //console.log( "Participant:["+listParticipants[z]+"]" )
  52. if( listParticipants[z] == "" ) { continue; }
  53. listModelParticipants.append( { jid:listParticipants[z] } )
  54. }
  55. }
  56. /**-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**/
  57. Component {
  58. id: componentWrapperItem
  59. Rectangle {
  60. id: wrapper
  61. border.color: msgResource === muc.nickName ? "blue" : Engine.getNameColor( msgResource )
  62. color: msgResource === muc.nickName ? "white" : "lightblue"
  63. radius: 10
  64. property string text: msgText
  65. clip: true
  66. anchors.horizontalCenter: parent.horizontalCenter
  67. MouseArea {
  68. id: maMsg
  69. anchors.fill: parent
  70. onPressAndHold: {
  71. // цитирование
  72. animCit.start()
  73. txtMessage.text += "> \"" + mainSmiles.htmlToPlainText( wrapper.text ) + "\"\n"
  74. //txtMessage.text += "> \"" + wrapper.text + "\"<br/>"
  75. }
  76. onClicked: {
  77. wrapper.ListView.view.currentIndex = index
  78. }
  79. }
  80. ListView.onAdd: ParallelAnimation {
  81. NumberAnimation {
  82. target: wrapper
  83. property: "opacity"
  84. from: 0; to: 1
  85. duration: 100
  86. easing.type: Easing.InOutQuad
  87. }
  88. NumberAnimation {
  89. target: wrapper;
  90. property: "scale";
  91. duration: 200;
  92. from: 0.1; to: 1
  93. easing.type: Easing.InOutQuad
  94. }
  95. }
  96. Image {
  97. id: imgDlr
  98. //anchors.left: parent.left;
  99. //anchors.leftMargin: 10
  100. anchors.bottom: parent.bottom; anchors.bottomMargin: 10
  101. source: msgResource === muc.nickName ? "qrc:/qml/images/msg_recv.png" : ( msgDlr === true ? "qrc:/qml/images/msg_dlr.png" : "qrc:/qml/images/msg_sent.png")
  102. height: 32
  103. width: 32
  104. smooth: true
  105. Component.onCompleted: {
  106. if( msgResource === muc.nickName ) {
  107. imgDlr.anchors.right = parent.right
  108. imgDlr.anchors.rightMargin = 10
  109. } else {
  110. imgDlr.anchors.left = parent.left
  111. imgDlr.anchors.leftMargin = 10
  112. }
  113. }
  114. }
  115. Image {
  116. id: imgAvatar
  117. smooth: true
  118. height: 32
  119. width: 32
  120. anchors.top: parent.top; anchors.topMargin: 10
  121. //source: msgMy === true ? "qrc:/qml/images/avatar.png" : (main.chatAvatar === "" ? "qrc:/qml/images/avatar.png" : main.chatAvatar)
  122. source: msgResource === muc.nickName ? "qrc:/qml/images/avatar.png" : (avatarPic === "" ? "qrc:/qml/images/avatar.png" : avatarPic)
  123. Image {
  124. anchors.centerIn: parent
  125. height: parent.height
  126. width: parent.width
  127. smooth: true
  128. source: msgResource === muc.nickName ? "qrc:/qml/images/meego_frame_32w.png" : "qrc:/qml/images/meego_frame_32b.png"
  129. }
  130. Component.onCompleted: {
  131. if( msgResource === muc.nickName ) {
  132. imgAvatar.anchors.right = parent.right
  133. imgAvatar.anchors.rightMargin = 10
  134. } else {
  135. imgAvatar.anchors.left = parent.left
  136. imgAvatar.anchors.leftMargin = 10
  137. }
  138. }
  139. }
  140. Text {
  141. id: txtHeader
  142. anchors.top: parent.top; anchors.topMargin: 10
  143. anchors.left: msgResource === muc.nickName ? parent.left : imgDlr.right; anchors.leftMargin: 10
  144. text: msgResource === muc.nickName ? "[" + msgDateTime + "] :" : "[" + msgDateTime + "] " + /*xmppClient.chatJid + "/" + */msgResource + ":"
  145. font.pixelSize: 16
  146. opacity: 0.8
  147. color: msgResource === muc.nickName ? "blue" : Engine.getNameColor( msgResource )
  148. font.italic: true
  149. visible: (msgResource !== muc.nickName) && ( msgResource == "" ) ? false : true
  150. }
  151. Text {
  152. id: text_field
  153. anchors.left: msgResource === muc.nickName ? parent.left : imgDlr.right; anchors.leftMargin: 10
  154. anchors.right: msgResource === muc.nickName ? imgDlr.left : parent.right; anchors.rightMargin: 10
  155. anchors.top: txtHeader.bottom; anchors.topMargin: 5
  156. anchors.bottom: parent.bottom; anchors.bottomMargin: 10
  157. text: wrapper.text
  158. wrapMode: Text.WrapAtWordBoundaryOrAnywhere
  159. font.pixelSize: 20
  160. textFormat: Text.RichText
  161. onLinkActivated: {
  162. Qt.openUrlExternally (link)
  163. }
  164. font.bold: (msgResource !== muc.nickName) && ( msgResource == "" ) ? true : false
  165. }
  166. width: listViewMessages.width - 10
  167. //height: text_field.paintedHeight + text_field.anchors.topMargin + text_field.anchors.bottomMargin + txtHeader.height + txtHeader.anchors.topMargin
  168. height: text_field.paintedHeight + text_field.anchors.topMargin + text_field.anchors.bottomMargin + txtHeader.height + txtHeader.anchors.topMargin <
  169. imgDlr.height+imgDlr.anchors.bottomMargin + imgAvatar.height + imgAvatar.anchors.topMargin ?
  170. imgDlr.height+imgDlr.anchors.bottomMargin + imgAvatar.height + imgAvatar.anchors.topMargin :
  171. text_field.paintedHeight + text_field.anchors.topMargin + text_field.anchors.bottomMargin + txtHeader.height + txtHeader.anchors.topMargin
  172. SequentialAnimation {
  173. id: animCit
  174. NumberAnimation { target: wrapper; property: "rotation"; to: 0.8; duration: 35 }
  175. NumberAnimation { target: wrapper; property: "rotation"; to: -0.8; duration: 70 }
  176. NumberAnimation { target: wrapper; property: "rotation"; to: 0; duration: 30 }
  177. loops: 3
  178. alwaysRunToEnd: true
  179. }
  180. Component.onCompleted: {
  181. // парсинг на смайлы в сообщении
  182. wrapper.text = mainSmiles.parseMsgString( wrapper.text )
  183. }
  184. states: State {
  185. name: "Current"
  186. when: (wrapper.ListView.isCurrentItem )
  187. //PropertyChanges { target: posGr1; position: 0 }
  188. }
  189. transitions: Transition {
  190. //NumberAnimation { properties: "position"; duration: 300 }
  191. }
  192. }
  193. } //Component
  194. /**-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**/
  195. /* --------------------( ресурсы jid )-------------------- */
  196. ListModel {
  197. id: listModelParticipants
  198. }
  199. /*--------------------(верхняя панелька с отображение информации о jid)--------------------*/
  200. property bool flSendMsg: false
  201. /* ------------( подписка на сигналы muc объекта )------------ */
  202. Connections {
  203. target: muc
  204. /*onMessageReceived: {
  205. }*/
  206. }
  207. function strTopPanel( isTyping, showTyping )
  208. {
  209. var ret = xmppClient.chatJid
  210. /*if(mucPage.resourceJid != "") {
  211. ret += "/" + mucPage.resourceJid
  212. }*/
  213. return ret;
  214. }
  215. /* панелька с надписью jid */
  216. Rectangle {
  217. id: topPanelChat
  218. z: 11
  219. width: parent.width
  220. height: 40
  221. color: "black"
  222. anchors.top: parent.top;
  223. anchors.left: parent.left;
  224. visible: main.inPortrait
  225. gradient: gr1
  226. Gradient {
  227. id: gr1
  228. GradientStop { position: 0; color: "#3f3f3f" }
  229. GradientStop { position: 1; color: "#000000" }
  230. }
  231. Gradient {
  232. id: gr2
  233. GradientStop { position: 0; color: "#000000" }
  234. GradientStop { position: 1; color: "#3f3f3f" }
  235. }
  236. Image {
  237. id: imgPresence
  238. anchors.left: parent.left; anchors.leftMargin: 10
  239. anchors.verticalCenter: parent.verticalCenter
  240. height: topPanelChat.height - 10
  241. width: height
  242. source: "qrc:/qml/images/muc.png"
  243. }
  244. Text {
  245. id: txtPresence
  246. anchors.left: imgPresence.right; anchors.leftMargin: 10
  247. anchors.verticalCenter: parent.verticalCenter
  248. color: "white"
  249. font.pixelSize: parent.height/2.5
  250. text: strTopPanel( false, false )
  251. }
  252. Image {
  253. id: imgDownArrow
  254. source: "qrc:/qml/images/small_arrow_black.png"
  255. anchors.right: parent.right; anchors.rightMargin: 15
  256. smooth: true
  257. rotation: -90
  258. }
  259. MouseArea {
  260. anchors.fill: parent
  261. onClicked: {
  262. if(panelListResources.state == "hidden") {
  263. panelListResources.state = "visible"
  264. } else {
  265. panelListResources.state = "hidden"
  266. }
  267. }
  268. onPressedChanged: {
  269. if(pressed) {
  270. topPanelChat.gradient = gr2
  271. } else {
  272. topPanelChat.gradient = gr1
  273. }
  274. }
  275. }
  276. }
  277. /* -----------------( выпадающая панелька с участниками чата )----------------- */
  278. Rectangle {
  279. id: panelListResources
  280. z: 10
  281. clip: true
  282. anchors.left: parent.left
  283. width: parent.width
  284. height: 350
  285. color: "black"
  286. opacity: 0.8
  287. state: "hidden"
  288. states: [
  289. State {
  290. name: "hidden"
  291. AnchorChanges{ target: panelListResources; anchors.bottom: mucPage.top }
  292. PropertyChanges { target: imgDownArrow ; rotation: -90 }
  293. },
  294. State {
  295. name: "visible"
  296. AnchorChanges{ target: panelListResources; anchors.top: topPanelChat.bottom }
  297. PropertyChanges { target: imgDownArrow ; rotation: 90 }
  298. }
  299. ]
  300. transitions: Transition {
  301. ParallelAnimation {
  302. AnchorAnimation { duration: 400; easing.type: Easing.InOutQuad }
  303. PropertyAnimation { duration: 400; property: "rotation" }
  304. }
  305. }
  306. ListView {
  307. id: listViewResources
  308. anchors.top: parent.top
  309. anchors.left: parent.left
  310. width: parent.width
  311. height: parent.height - bottomPanel.height
  312. model: listModelParticipants
  313. clip: true
  314. delegate: Component {
  315. Rectangle {
  316. id: itemResource
  317. height: 70
  318. width: panelListResources.width
  319. color: "transparent"
  320. border.color: "gray"
  321. radius: 5
  322. Text {
  323. id: textResource
  324. text: jid
  325. font.pixelSize: itemResource.height/2
  326. anchors.horizontalCenter: parent.horizontalCenter
  327. anchors.verticalCenter: parent.verticalCenter
  328. color: "white"
  329. font.bold: false
  330. }
  331. states: State {
  332. name: "Current"
  333. when: itemResource.ListView.isCurrentItem
  334. PropertyChanges { target: itemResource; color: "gray" }
  335. }
  336. MouseArea {
  337. anchors.fill: parent
  338. onClicked: {
  339. itemResource.ListView.view.currentIndex = index
  340. txtMessage.text = jid + ": " + txtMessage.text
  341. panelListResources.state = "hidden"
  342. } //onClicked
  343. } //MouseArea
  344. }
  345. } //Component
  346. }
  347. Rectangle {
  348. id: bottomPanel
  349. anchors.left: parent.left
  350. anchors.bottom: parent.bottom
  351. width: parent.width
  352. height: 25
  353. gradient: Gradient {
  354. GradientStop { position: 0; color: "gray" }
  355. GradientStop { position: 0.5; color: "black" }
  356. GradientStop { position: 1; color: "gray" }
  357. }
  358. MouseArea {
  359. anchors.fill: parent
  360. onClicked: {
  361. panelListResources.state = "hidden"
  362. }
  363. }
  364. }
  365. }
  366. /* --------------------(список сообщений)-------------------- */
  367. ListView {
  368. id: listViewMessages
  369. anchors.top: main.inPortrait == true ? topPanelChat.bottom : parent.top
  370. anchors.topMargin: 5
  371. anchors.bottom: panelWriteText.top; anchors.bottomMargin: 5
  372. anchors.left: parent.left;// anchors.leftMargin: 5
  373. anchors.right: parent.right;// anchors.rightMargin: 5
  374. clip: true
  375. model: xmppClient.messages
  376. delegate: componentWrapperItem
  377. spacing: 5
  378. onCountChanged: {
  379. listViewMessages.positionViewAtIndex(count - 1, ListView.Beginning)
  380. }
  381. onHeightChanged: {
  382. listViewMessages.positionViewAtIndex(count - 1, ListView.Beginning)
  383. }
  384. }
  385. /*--------------------(панелька с вводом текста)--------------------*/
  386. Rectangle {
  387. id: panelWriteText
  388. height: 100
  389. anchors.bottom: main.inPortrait == true ? toolBar.top : parent.bottom;
  390. anchors.left: parent.left;
  391. anchors.right: parent.right;
  392. color: "gray"
  393. Rectangle {
  394. id: wrapperTextEdit
  395. anchors.bottom: parent.bottom; anchors.bottomMargin: 5
  396. anchors.left: parent.left; anchors.leftMargin: 5
  397. anchors.right: screen.orientationString == "Landscape" || screen.orientationString == "LandscapeInverted" ? wrapperImgSmiles.left : wrapperImgSend.left
  398. anchors.top: parent.top; anchors.topMargin: 5
  399. //border.color: "blue"
  400. //border.width: 2
  401. color: "transparent"
  402. radius: 8
  403. clip: true
  404. Flickable {
  405. id: flickMsg
  406. anchors.fill: parent
  407. contentHeight: txtMessage.height
  408. contentWidth: txtMessage.width
  409. flickableDirection: Flickable.VerticalFlick
  410. clip: true
  411. function ensureVisible(r)
  412. {
  413. if (contentX >= r.x)
  414. contentX = r.x;
  415. else if (contentX+width <= r.x+r.width)
  416. contentX = r.x+r.width-width;
  417. if (contentY >= r.y)
  418. contentY = r.y;
  419. else if (contentY+height <= r.y+r.height)
  420. contentY = r.y+r.height-height;
  421. }
  422. MyTextEdit2 {
  423. //MyTextEdit {
  424. id: txtMessage
  425. wrapMode: TextEdit.Wrap
  426. font.pixelSize: 22
  427. textFormat: TextEdit.PlainText
  428. //textFormat: TextEdit.RichText
  429. width: flickMsg.width
  430. height: flickMsg.height
  431. //onCursorRectangleChanged: flickMsg.ensureVisible( cursorRectangle )
  432. onTextChanged: {
  433. }
  434. }
  435. }
  436. } //wrapperTextEdit
  437. /* кнопка смайлов для вертикальной ориентации */
  438. Rectangle {
  439. id: wrapperImgSmiles
  440. visible: screen.orientationString == "Landscape" || screen.orientationString == "LandscapeInverted" ? true : false
  441. height: 100
  442. width: 100
  443. anchors.right:wrapperImgSend.left
  444. anchors.verticalCenter: parent.verticalCenter
  445. color: "transparent"
  446. Image {
  447. id: imgFramePressSmiles
  448. source: "qrc:/qml/images/bar_glow.png"
  449. width: imgSmilesMsg.width + 2
  450. height: imgSmilesMsg.height + 2
  451. anchors.centerIn: parent
  452. smooth: true
  453. opacity: 0
  454. Behavior on opacity { NumberAnimation { duration: 150 } }
  455. }
  456. Image {
  457. id: imgSmilesMsg
  458. anchors.centerIn: parent
  459. source: "qrc:/qml/images/bar_smiles.png"
  460. height: 96
  461. width: 96
  462. smooth: true
  463. MouseArea {
  464. anchors.fill: parent
  465. onClicked: {
  466. dlgSmiles.dlgShowHide()
  467. }
  468. onPressedChanged: {
  469. if( pressed ) {
  470. imgFramePressSmiles.opacity = 1
  471. } else {
  472. imgFramePressSmiles.opacity = 0
  473. }
  474. }
  475. }
  476. }
  477. } //wrapperImgSend
  478. /* копка отправки сообщения */
  479. Rectangle {
  480. id: wrapperImgSend
  481. height: 100
  482. width: 100
  483. anchors.right:parent.right
  484. //anchors.rightMargin: 5
  485. anchors.verticalCenter: parent.verticalCenter
  486. color: "transparent"
  487. Image {
  488. id: imgFramePress
  489. source: "qrc:/qml/images/bar_glow.png"
  490. width: imgSendMsg.width + 2
  491. height: imgSendMsg.height + 2
  492. anchors.centerIn: parent
  493. smooth: true
  494. opacity: 0
  495. Behavior on opacity { NumberAnimation { duration: 150 } }
  496. }
  497. Image {
  498. id: imgSendMsg
  499. anchors.centerIn: parent
  500. source: "qrc:/qml/images/msg_send.png"
  501. MouseArea {
  502. anchors.fill: parent
  503. onClicked: {
  504. var ret = muc.sendMessage( txtMessage.text )
  505. if( ret ) {
  506. flSendMsg = true
  507. txtMessage.text = ""
  508. flSendMsg = false
  509. //notify.notifyMessageSent() //TODO:
  510. }
  511. }
  512. onPressedChanged: {
  513. if( pressed ) {
  514. imgFramePress.opacity = 1
  515. } else {
  516. imgFramePress.opacity = 0
  517. }
  518. }
  519. }
  520. }
  521. } //wrapperImgSend
  522. } //panelWriteText
  523. /********************************( Toolbar )************************************/
  524. ToolBar {
  525. id: toolBar
  526. visible: main.inPortrait
  527. /****/
  528. ToolButton {
  529. id: toolBarButtonRoster
  530. icon: "qrc:/qml/images/bar_roster.png"
  531. anchors.left: parent.left
  532. anchors.leftMargin: (0.5*(parent.width/4) - 0.5*toolBarButtonRoster.width)
  533. onClicked: {
  534. mucPage.closePage( "qrc:/qml/RosterPage.qml" )
  535. xmppClient.resetUnreadMessages( xmppClient.chatJid ) //сброс непрочитанных сообщ.
  536. }
  537. pauseAnim: 500
  538. }
  539. ToolButton {
  540. id: toolBarButtonChats
  541. icon: "qrc:/qml/images/bar_open_chats.png"
  542. anchors.left: parent.left
  543. anchors.leftMargin: (1.5*(parent.width/4) - 0.5*toolBarButtonChats.width)
  544. onClicked: {
  545. mucPage.closePage( "qrc:/qml/ChatsPage.qml" )
  546. xmppClient.resetUnreadMessages( xmppClient.chatJid ) //сброс непрочитанных сообщ.
  547. }
  548. pauseAnim: 600
  549. }
  550. ToolButton {
  551. id: toolBarButtonSmiles
  552. icon: "qrc:/qml/images/bar_smiles.png"
  553. anchors.left: parent.left
  554. anchors.leftMargin: (2.5*(parent.width/4) - 0.5*toolBarButtonSmiles.width)
  555. onClicked: {
  556. dlgSmiles.dlgShowHide()
  557. }
  558. pauseAnim: 700
  559. }
  560. ToolButton {
  561. id: toolBarButtonOptions
  562. icon: "qrc:/qml/images/bar_options.png"
  563. anchors.left: parent.left
  564. anchors.leftMargin: (3.5*(parent.width/4) - 0.5*toolBarButtonOptions.width)
  565. onClicked: {
  566. dlgMsgOptions.dlgShowHide()
  567. }
  568. pauseAnim: 800
  569. }
  570. }
  571. /*********************************************************************/
  572. /*-------------------( смайлы )-------------------*/
  573. DialogSmiles {
  574. id: dlgSmiles
  575. title: "Smiles"
  576. smilesModel: mainSmiles.smilesModel
  577. onSmileSelected: {
  578. txtMessage.text += dlgSmiles.selectedSmile
  579. }
  580. }
  581. /*----------------------( опции чата )----------------------*/
  582. DialogMucOptions {
  583. id: dlgMsgOptions
  584. onItemClicked: {
  585. if( itemSelected == "clearChat" ) {
  586. xmppClient.clearChat( xmppClient.chatJid )
  587. } else if( itemSelected == "" ) {
  588. }
  589. }
  590. }
  591. }