2016-09-15 07:07:13 -04:00
|
|
|
/*
|
|
|
|
* RetroShare Android QML App
|
2017-03-17 12:22:58 -04:00
|
|
|
* Copyright (C) 2016-2017 Gioacchino Mazzurco <gio@eigenlab.org>
|
2016-09-15 07:07:13 -04:00
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License as
|
|
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Affero General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
import QtQuick 2.0
|
2017-03-24 07:02:13 -04:00
|
|
|
import QtQuick.Controls 2.0
|
2016-12-08 15:57:26 -05:00
|
|
|
import QtQuick.Dialogs 1.2
|
2017-03-24 07:02:13 -04:00
|
|
|
import QtQml.Models 2.2
|
2016-09-15 07:07:13 -04:00
|
|
|
import org.retroshare.qml_components.LibresapiLocalClient 1.0
|
|
|
|
|
|
|
|
Item
|
|
|
|
{
|
2016-12-08 09:56:23 -05:00
|
|
|
id: contactsView
|
|
|
|
property string own_gxs_id: ""
|
|
|
|
property string own_nick: ""
|
2017-03-24 07:02:13 -04:00
|
|
|
property bool searching: false
|
|
|
|
property var unreadMessages: ({})
|
2016-09-15 07:07:13 -04:00
|
|
|
|
2016-12-08 09:56:23 -05:00
|
|
|
Component.onCompleted: refreshOwn()
|
2016-09-15 07:07:13 -04:00
|
|
|
|
2017-03-17 12:22:58 -04:00
|
|
|
function refreshData()
|
|
|
|
{
|
|
|
|
function refreshCallback(par)
|
|
|
|
{
|
2017-03-24 07:02:13 -04:00
|
|
|
gxsIdsModel.json = par.response
|
2017-03-17 12:22:58 -04:00
|
|
|
if(contactsView.own_gxs_id == "") refreshOwn()
|
|
|
|
}
|
|
|
|
rsApi.request("/identity/*/", "", refreshCallback)
|
|
|
|
}
|
2016-12-08 09:56:23 -05:00
|
|
|
function refreshOwn()
|
2016-09-15 07:07:13 -04:00
|
|
|
{
|
2016-12-08 09:56:23 -05:00
|
|
|
rsApi.request("/identity/own", "", function(par)
|
2016-12-10 14:23:30 -05:00
|
|
|
{
|
|
|
|
var json = JSON.parse(par.response)
|
|
|
|
if(json.data.length > 0)
|
|
|
|
{
|
|
|
|
contactsView.own_gxs_id = json.data[0].gxs_id
|
|
|
|
contactsView.own_nick = json.data[0].name
|
|
|
|
}
|
|
|
|
else createIdentityDialog.visible = true
|
|
|
|
})
|
2016-09-15 07:07:13 -04:00
|
|
|
}
|
2017-03-17 12:22:58 -04:00
|
|
|
function startChatCallback(par)
|
|
|
|
{
|
|
|
|
var chId = JSON.parse(par.response).data.chat_id
|
2017-03-24 07:02:13 -04:00
|
|
|
stackView.push("qrc:/qml/ChatView.qml", {'chatId': chId})
|
2017-03-17 12:22:58 -04:00
|
|
|
}
|
2016-09-15 07:07:13 -04:00
|
|
|
|
2017-03-24 07:02:13 -04:00
|
|
|
function refreshUnread()
|
|
|
|
{
|
|
|
|
rsApi.request("/chat/unread_msgs", "", function(par)
|
|
|
|
{
|
|
|
|
var jsonData = JSON.parse(par.response).data
|
|
|
|
var dataLen = jsonData.length
|
|
|
|
if(JSON.stringify(unreadMessages) != JSON.stringify(jsonData))
|
|
|
|
{
|
|
|
|
unreadMessages = {}
|
|
|
|
for ( var i=0; i<dataLen; ++i)
|
|
|
|
{
|
|
|
|
var el = jsonData[i]
|
|
|
|
if(el.is_distant_chat_id)
|
|
|
|
unreadMessages[el.remote_author_id] = el.unread_count
|
|
|
|
}
|
|
|
|
|
|
|
|
visualModel.resetSorting()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/** This must be equivalent to
|
|
|
|
p3GxsTunnelService::makeGxsTunnelId(...) */
|
|
|
|
function getChatId(from_gxs, to_gxs)
|
|
|
|
{
|
|
|
|
return from_gxs < to_gxs ? from_gxs + to_gxs : to_gxs + from_gxs
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-12-08 09:56:23 -05:00
|
|
|
onFocusChanged: focus && refreshData()
|
|
|
|
|
2016-09-15 07:07:13 -04:00
|
|
|
JSONListModel
|
|
|
|
{
|
2017-03-24 07:02:13 -04:00
|
|
|
id: gxsIdsModel
|
2016-09-15 07:07:13 -04:00
|
|
|
query: "$.data[*]"
|
|
|
|
}
|
|
|
|
|
2017-03-24 07:02:13 -04:00
|
|
|
DelegateModel
|
2016-09-15 07:07:13 -04:00
|
|
|
{
|
2017-03-24 07:02:13 -04:00
|
|
|
/* More documentation about this is available at:
|
|
|
|
* http://doc.qt.io/qt-5/qml-qtqml-models-delegatemodel.html
|
|
|
|
* http://doc.qt.io/qt-5/qtquick-tutorials-dynamicview-dynamicview4-example.html
|
|
|
|
* http://imaginativethinking.ca/use-qt-quicks-delegatemodelgroup/
|
|
|
|
*/
|
|
|
|
id: visualModel
|
|
|
|
model: gxsIdsModel.model
|
2016-12-08 09:56:23 -05:00
|
|
|
|
2017-03-24 07:02:13 -04:00
|
|
|
property var lessThan:
|
|
|
|
[
|
|
|
|
function(left, right)
|
|
|
|
{
|
|
|
|
var lfun = unreadMessages.hasOwnProperty(left.gxs_id) ?
|
|
|
|
unreadMessages[left.gxs_id] : 0
|
|
|
|
var rgun = unreadMessages.hasOwnProperty(right.gxs_id) ?
|
|
|
|
unreadMessages[right.gxs_id] : 0
|
|
|
|
if( lfun !== rgun ) return lfun > rgun
|
|
|
|
if(left.name !== right.name) return left.name < right.name
|
|
|
|
return left.gxs_id < right.gxs_id
|
|
|
|
},
|
|
|
|
function(left, right)
|
2016-12-08 09:56:23 -05:00
|
|
|
{
|
2017-03-24 07:02:13 -04:00
|
|
|
if(searchText.length > 0)
|
2016-12-08 09:56:23 -05:00
|
|
|
{
|
2017-03-24 07:02:13 -04:00
|
|
|
var mtc = searchText.text.toLowerCase()
|
|
|
|
var lfn = left.name.toLowerCase()
|
|
|
|
var rgn = right.name.toLowerCase()
|
|
|
|
var lfml = lfn.indexOf(mtc)
|
|
|
|
var rgml = rgn.indexOf(mtc)
|
|
|
|
if ( lfml !== rgml )
|
2016-12-08 09:56:23 -05:00
|
|
|
{
|
2017-03-24 07:02:13 -04:00
|
|
|
lfml = lfml >= 0 ? lfml : Number.MAX_VALUE
|
|
|
|
rgml = rgml >= 0 ? rgml : Number.MAX_VALUE
|
|
|
|
return lfml < rgml
|
2016-12-08 09:56:23 -05:00
|
|
|
}
|
|
|
|
}
|
2017-03-24 07:02:13 -04:00
|
|
|
return lessThan[0](left, right)
|
|
|
|
}
|
|
|
|
]
|
2017-03-21 09:47:34 -04:00
|
|
|
|
2017-03-24 07:02:13 -04:00
|
|
|
property int sortOrder: contactsView.searching ? 1 : 0
|
|
|
|
onSortOrderChanged: resetSorting()
|
|
|
|
|
|
|
|
property bool isSorting: false
|
|
|
|
|
|
|
|
function insertPosition(lessThan, item)
|
|
|
|
{
|
|
|
|
var lower = 0
|
|
|
|
var upper = items.count
|
|
|
|
while (lower < upper)
|
|
|
|
{
|
|
|
|
var middle = Math.floor(lower + (upper - lower) / 2)
|
|
|
|
var result = lessThan(item.model, items.get(middle).model);
|
|
|
|
if (result) upper = middle
|
|
|
|
else lower = middle + 1
|
|
|
|
}
|
|
|
|
return lower
|
|
|
|
}
|
|
|
|
|
|
|
|
function resetSorting() { items.setGroups(0, items.count, "unsorted") }
|
|
|
|
|
|
|
|
function sort()
|
|
|
|
{
|
|
|
|
while (unsortedItems.count > 0)
|
|
|
|
{
|
|
|
|
var item = unsortedItems.get(0)
|
|
|
|
var index = insertPosition(lessThan[visualModel.sortOrder],
|
|
|
|
item)
|
|
|
|
item.groups = ["items"]
|
|
|
|
items.move(item.itemsIndex, index)
|
2016-12-08 09:56:23 -05:00
|
|
|
}
|
2017-03-21 09:47:34 -04:00
|
|
|
}
|
2017-03-24 07:02:13 -04:00
|
|
|
|
|
|
|
items.includeByDefault: false
|
|
|
|
|
|
|
|
groups:
|
|
|
|
[
|
|
|
|
DelegateModelGroup
|
|
|
|
{
|
|
|
|
id: unsortedItems
|
|
|
|
name: "unsorted"
|
|
|
|
|
|
|
|
includeByDefault: true
|
|
|
|
onChanged: visualModel.sort()
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
|
|
|
delegate: GxsIdentityDelegate {}
|
|
|
|
}
|
|
|
|
|
|
|
|
ListView
|
|
|
|
{
|
|
|
|
id: locationsListView
|
|
|
|
width: parent.width
|
|
|
|
height: contactsView.searching ?
|
|
|
|
parent.height - searchBox.height : parent.height
|
|
|
|
model: visualModel
|
|
|
|
anchors.top: contactsView.searching ? searchBox.bottom : parent.top
|
|
|
|
}
|
|
|
|
|
|
|
|
Rectangle
|
|
|
|
{
|
|
|
|
id: searchBox
|
|
|
|
visible: contactsView.searching
|
|
|
|
|
|
|
|
height: searchText.height
|
|
|
|
width: searchText.width
|
|
|
|
anchors.right: parent.right
|
|
|
|
anchors.top: parent.top
|
|
|
|
|
|
|
|
Image
|
|
|
|
{
|
|
|
|
id: searchIcon
|
|
|
|
height: searchText.height - 4
|
|
|
|
width: searchText.height - 4
|
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
source: "qrc:/qml/icons/edit-find.png"
|
|
|
|
}
|
|
|
|
|
|
|
|
TextField
|
|
|
|
{
|
|
|
|
id: searchText
|
|
|
|
anchors.left: searchIcon.right
|
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
onTextChanged: visualModel.resetSorting()
|
|
|
|
}
|
2016-09-15 07:07:13 -04:00
|
|
|
}
|
|
|
|
|
2017-03-21 09:47:34 -04:00
|
|
|
Text
|
|
|
|
{
|
2016-12-08 09:56:23 -05:00
|
|
|
id: selectedOwnIdentityView
|
|
|
|
color: "green"
|
|
|
|
anchors.bottom: parent.bottom
|
|
|
|
anchors.left: parent.left
|
|
|
|
width: parent.width
|
|
|
|
text: "Open Chat as: " + contactsView.own_nick + " " + contactsView.own_gxs_id
|
|
|
|
}
|
|
|
|
|
|
|
|
Timer
|
|
|
|
{
|
|
|
|
id: refreshTimer
|
|
|
|
interval: 5000
|
|
|
|
repeat: true
|
2017-03-24 07:02:13 -04:00
|
|
|
triggeredOnStart: true
|
|
|
|
onTriggered:
|
|
|
|
if(contactsView.visible)
|
|
|
|
{
|
|
|
|
contactsView.refreshUnread()
|
|
|
|
contactsView.refreshData()
|
|
|
|
}
|
2016-12-08 09:56:23 -05:00
|
|
|
Component.onCompleted: start()
|
|
|
|
}
|
2016-12-08 15:57:26 -05:00
|
|
|
|
|
|
|
Dialog
|
|
|
|
{
|
|
|
|
id: createIdentityDialog
|
|
|
|
visible: false
|
|
|
|
title: "You need to create a GXS identity to chat!"
|
|
|
|
standardButtons: StandardButton.Save
|
|
|
|
|
|
|
|
onAccepted: rsApi.request("/identity/create_identity", JSON.stringify({"name":identityNameTE.text, "pgp_linked": !psdnmCheckBox.checked }))
|
|
|
|
|
|
|
|
TextField
|
|
|
|
{
|
|
|
|
id: identityNameTE
|
|
|
|
width: 300
|
|
|
|
}
|
|
|
|
|
|
|
|
Row
|
|
|
|
{
|
|
|
|
anchors.top: identityNameTE.bottom
|
|
|
|
Text { text: "Pseudonymous: " }
|
|
|
|
CheckBox { id: psdnmCheckBox; checked: true; enabled: false }
|
|
|
|
}
|
|
|
|
}
|
2017-03-21 09:47:34 -04:00
|
|
|
|
2017-03-24 07:02:13 -04:00
|
|
|
Popup
|
2017-03-21 09:47:34 -04:00
|
|
|
{
|
|
|
|
id: fingerPrintDialog
|
|
|
|
visible: false
|
|
|
|
property string nick
|
|
|
|
property string gxs_id
|
2017-03-24 07:02:13 -04:00
|
|
|
width: fingerPrintText.contentWidth + 20
|
|
|
|
height: fingerPrintText.contentHeight + 20
|
|
|
|
x: parent.x + parent.width/2 - width/2
|
|
|
|
y: parent.y + parent.height/2 - height/2
|
|
|
|
|
2017-03-21 09:47:34 -04:00
|
|
|
Text
|
|
|
|
{
|
|
|
|
id: fingerPrintText
|
|
|
|
anchors.centerIn: parent
|
|
|
|
text: "<pre>" +
|
|
|
|
fingerPrintDialog.gxs_id.substring(1, 9) + "<br/>" +
|
|
|
|
fingerPrintDialog.gxs_id.substring(9, 17) + "<br/>" +
|
|
|
|
fingerPrintDialog.gxs_id.substring(17, 25) + "<br/>" +
|
|
|
|
fingerPrintDialog.gxs_id.slice(-8) + "<br/>" +
|
|
|
|
"</pre>"
|
|
|
|
}
|
|
|
|
}
|
2016-09-15 07:07:13 -04:00
|
|
|
}
|