2020-05-20 01:39:57 +00:00
|
|
|
import QtGraphicalEffects 1.0
|
|
|
|
import QtQuick 2.7
|
|
|
|
import QtQuick.Controls 2.4
|
|
|
|
import QtQuick.Controls.Material 2.0
|
|
|
|
import QtQuick.Layouts 1.3
|
2020-05-20 02:39:01 +00:00
|
|
|
|
2020-05-20 20:49:00 +00:00
|
|
|
import "../opaque" as Opaque
|
2020-05-20 02:39:01 +00:00
|
|
|
import "../opaque/theme"
|
2020-06-23 23:42:51 +00:00
|
|
|
import "../const"
|
2020-05-20 01:39:57 +00:00
|
|
|
|
|
|
|
ColumnLayout {
|
|
|
|
id: root
|
|
|
|
|
|
|
|
property alias dualPane: myprof.dualPane
|
2020-06-23 23:42:51 +00:00
|
|
|
property real logscale: 4 * Math.log10(gcd.themeScale + 1)
|
2020-05-20 01:39:57 +00:00
|
|
|
|
|
|
|
spacing: 10
|
|
|
|
|
|
|
|
MouseArea {
|
|
|
|
anchors.fill: parent
|
|
|
|
|
|
|
|
onClicked: {
|
|
|
|
forceActiveFocus()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MyProfile { // CURRENT PROFILE INFO AND CONTROL BAR
|
|
|
|
id: myprof
|
|
|
|
}
|
|
|
|
|
2020-11-13 00:42:03 +00:00
|
|
|
function filterContact(displayName, handle) {
|
|
|
|
return searchAddText.text == "" || displayName.toLowerCase().includes(searchAddText.text.toLowerCase()) || handle.toLowerCase().startsWith(searchAddText.text.toLowerCase())
|
|
|
|
}
|
|
|
|
|
2020-06-23 23:42:51 +00:00
|
|
|
function removeContact(model, handle) {
|
|
|
|
for(var i = 0; i < model.count; i++){
|
|
|
|
if(model.get(i)["_handle"] == handle) {
|
|
|
|
model.remove(i)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-05-20 01:39:57 +00:00
|
|
|
|
2020-05-20 20:49:00 +00:00
|
|
|
Opaque.IconTextField {
|
2020-05-26 18:21:27 +00:00
|
|
|
id: searchAddText
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
2020-05-20 01:39:57 +00:00
|
|
|
|
2020-05-26 18:21:27 +00:00
|
|
|
Layout.minimumWidth: parent.width - 60
|
|
|
|
Layout.maximumWidth: parent.width - 60
|
2020-05-20 01:39:57 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-05-26 18:21:27 +00:00
|
|
|
//: ex: "... paste an address here to add a contact ..."
|
2020-11-13 00:42:03 +00:00
|
|
|
//placeholderText: qsTr("paste-address-to-add-contact")
|
2020-05-26 18:21:27 +00:00
|
|
|
horizontalAlignment: TextInput.AlignHCenter
|
2020-11-20 19:06:41 +00:00
|
|
|
icon: gcd.assetPath + "core/search-24px.webp"
|
2020-05-20 01:39:57 +00:00
|
|
|
|
|
|
|
|
2020-05-26 18:21:27 +00:00
|
|
|
onTextChanged: {
|
2020-11-13 00:42:03 +00:00
|
|
|
// TODO: detect peer or group address and insert a contactRow that asks to add the corresponding group or peer
|
|
|
|
/*if (text != "") {
|
2020-11-20 19:42:29 +00:00
|
|
|
gcd.importString(text)
|
|
|
|
text = ""
|
2020-11-13 00:42:03 +00:00
|
|
|
}*/
|
2020-05-20 01:39:57 +00:00
|
|
|
}
|
2020-05-26 18:21:27 +00:00
|
|
|
}
|
2020-05-20 01:39:57 +00:00
|
|
|
|
|
|
|
|
2020-08-24 22:01:00 +00:00
|
|
|
Opaque.Flickable { // THE ACTUAL CONTACT LIST
|
2020-05-20 01:39:57 +00:00
|
|
|
id: sv
|
2020-08-24 22:01:00 +00:00
|
|
|
|
2020-05-20 01:39:57 +00:00
|
|
|
Layout.minimumHeight: 100
|
|
|
|
Layout.fillHeight: true
|
|
|
|
Layout.minimumWidth: parent.width
|
|
|
|
Layout.maximumWidth: parent.width
|
2020-06-23 23:42:51 +00:00
|
|
|
contentWidth: parent.width
|
2020-05-20 01:39:57 +00:00
|
|
|
contentHeight: colContacts.height
|
2020-06-23 23:42:51 +00:00
|
|
|
|
2020-05-20 01:39:57 +00:00
|
|
|
ColumnLayout {
|
|
|
|
id: colContacts
|
|
|
|
width: root.width
|
|
|
|
spacing: 0
|
|
|
|
|
|
|
|
Connections { // ADD/REMOVE CONTACT ENTRIES
|
|
|
|
target: gcd
|
|
|
|
|
2020-06-23 23:42:51 +00:00
|
|
|
onAddContact: function(handle, displayName, image, badge, status, authorization, loading, lastMsgTs) {
|
|
|
|
var model = contactsModel
|
|
|
|
if (authorization == Const.auth_blocked) {
|
|
|
|
model = blockedContactsModel
|
|
|
|
}
|
2020-05-20 01:39:57 +00:00
|
|
|
|
2020-11-13 00:42:03 +00:00
|
|
|
// If contact already in model, skip
|
2020-06-23 23:42:51 +00:00
|
|
|
for (var i = 0; i < model.count; i++) {
|
|
|
|
if (model.get(i)["_handle"] == handle) {
|
2020-05-20 01:39:57 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-23 23:42:51 +00:00
|
|
|
// Sort order: [unknown,authed][most recent message]
|
|
|
|
var index = model.count
|
|
|
|
for (var i = 0; i < model.count; i++) {
|
|
|
|
var contact = model.get(i)
|
|
|
|
|
|
|
|
if (contact["_authorization"] == authorization) {
|
|
|
|
if (contact["_lastMsgTs"] < lastMsgTs) {
|
|
|
|
index = i
|
|
|
|
break
|
|
|
|
}
|
|
|
|
} else if (authorization == Const.auth_unknown) {
|
2020-05-20 01:39:57 +00:00
|
|
|
index = i
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var newContact = {
|
|
|
|
"_handle": handle,
|
2020-06-23 23:42:51 +00:00
|
|
|
"_displayName": displayName,
|
2020-05-20 01:39:57 +00:00
|
|
|
"_image": image,
|
|
|
|
"_badge": badge,
|
|
|
|
"_status": status,
|
2020-06-23 23:42:51 +00:00
|
|
|
"_authorization": authorization,
|
2020-05-20 01:39:57 +00:00
|
|
|
"_loading": loading,
|
|
|
|
"_loading": loading,
|
|
|
|
"_lastMsgTs": lastMsgTs
|
|
|
|
}
|
|
|
|
|
2020-06-23 23:42:51 +00:00
|
|
|
model.insert(index, newContact)
|
2020-05-20 01:39:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
onRemoveContact: function(handle) {
|
2020-06-23 23:42:51 +00:00
|
|
|
var removed = root.removeContact(contactsModel, handle)
|
|
|
|
if (!removed) {
|
|
|
|
root.removeContact(blockedContactsModel, handle)
|
2020-05-20 01:39:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onIncContactUnreadCount: function(handle) {
|
|
|
|
var ts = Math.round((new Date()).getTime() / 1000);
|
|
|
|
for(var i = 0; i < contactsModel.count; i++){
|
|
|
|
if(contactsModel.get(i)["_handle"] == handle) {
|
|
|
|
var contact = contactsModel.get(i)
|
|
|
|
contact["_lastMsgTs"] = ts
|
|
|
|
contactsModel.move(i, 0, 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onResetProfile: function() {
|
|
|
|
contactsModel.clear()
|
2020-06-23 23:42:51 +00:00
|
|
|
blockedContactsModel.clear()
|
2020-05-20 01:39:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ListModel { // CONTACT OBJECTS ARE STORED HERE ...
|
|
|
|
id: contactsModel
|
|
|
|
}
|
|
|
|
|
|
|
|
Repeater {
|
2020-06-23 23:42:51 +00:00
|
|
|
id: contactRepeater
|
2020-05-20 01:39:57 +00:00
|
|
|
model: contactsModel // ... AND DISPLAYED HERE
|
|
|
|
delegate: ContactRow {
|
|
|
|
handle: _handle
|
|
|
|
displayName: _displayName
|
|
|
|
image: _image
|
|
|
|
badge: _badge
|
|
|
|
status: _status
|
2020-06-23 23:42:51 +00:00
|
|
|
authorization: _authorization
|
2020-05-20 01:39:57 +00:00
|
|
|
loading: _loading
|
2020-06-23 23:42:51 +00:00
|
|
|
rowColor: (_authorization == Const.auth_unknown) ? Theme.backgroundHilightElementColor : Theme.backgroundMainColor
|
|
|
|
Layout.fillWidth: true
|
2020-11-13 00:42:03 +00:00
|
|
|
visible: filterContact(displayName, handle)
|
2020-05-20 01:39:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-06-23 23:42:51 +00:00
|
|
|
Item {
|
|
|
|
id: blockItem
|
|
|
|
height: blockedToggle.height
|
|
|
|
Layout.fillWidth: true
|
|
|
|
visible: blockedContactsModel.count > 0
|
2020-05-20 01:39:57 +00:00
|
|
|
|
2020-06-23 23:42:51 +00:00
|
|
|
MouseArea {
|
|
|
|
anchors.fill: blockItem
|
|
|
|
|
|
|
|
hoverEnabled: true
|
|
|
|
|
|
|
|
onClicked: {
|
|
|
|
blockedToggle.showing = !blockedToggle.showing
|
|
|
|
blockedContacts.visible = blockedToggle.showing
|
|
|
|
if (blockedToggle.showing) {
|
|
|
|
gcd.storeSetting(Const.show_blocked, "true")
|
|
|
|
} else {
|
|
|
|
gcd.storeSetting(Const.show_blocked, "false")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onEntered: {
|
|
|
|
blockedBG.color = Theme.backgroundPaneColor
|
|
|
|
}
|
|
|
|
|
|
|
|
onExited: {
|
|
|
|
blockedBG.color = Theme.backgroundMainColor
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Rectangle {
|
|
|
|
id: blockedBG
|
|
|
|
property bool isHover: false
|
|
|
|
|
|
|
|
anchors.fill: blockItem
|
|
|
|
color: Theme.backgroundMainColor
|
2020-05-20 01:39:57 +00:00
|
|
|
|
2020-08-24 22:01:00 +00:00
|
|
|
Connections {
|
2020-06-23 23:42:51 +00:00
|
|
|
target: Theme
|
2020-05-20 01:39:57 +00:00
|
|
|
|
2020-06-23 23:42:51 +00:00
|
|
|
onThemeChanged: {
|
|
|
|
blockedBG.color = Theme.backgroundMainColor
|
|
|
|
}
|
2020-08-24 22:01:00 +00:00
|
|
|
}
|
2020-06-23 23:42:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Row {
|
|
|
|
id: blockedToggle
|
|
|
|
property bool showing: true
|
|
|
|
|
|
|
|
leftPadding: 32 * logscale
|
|
|
|
topPadding: 16 * logscale
|
|
|
|
bottomPadding: 8 * logscale
|
|
|
|
spacing: 5 * logscale
|
|
|
|
|
|
|
|
Opaque.ScalingLabel {
|
|
|
|
id: blockLbl
|
|
|
|
|
|
|
|
text: qsTr("blocked")
|
|
|
|
size: Theme.chatMetaTextSize
|
|
|
|
color: Theme.portraitBlockedTextColor
|
|
|
|
}
|
2020-05-20 01:39:57 +00:00
|
|
|
|
2020-06-23 23:42:51 +00:00
|
|
|
Opaque.ScalingLabel {
|
|
|
|
id: blockBtn
|
|
|
|
|
|
|
|
text: blockedToggle.showing ? "▲" : "▼"
|
|
|
|
size: Theme.chatMetaTextSize
|
|
|
|
color: Theme.portraitBlockedTextColor
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Connections {
|
2020-08-24 22:01:00 +00:00
|
|
|
target: gcd
|
2020-06-23 23:42:51 +00:00
|
|
|
|
2020-08-24 22:01:00 +00:00
|
|
|
onUpdateMyProfile: function(_nick, _onion, _image, _tag, _showBlocked) {
|
|
|
|
blockedToggle.showing = (_showBlocked == "true")
|
|
|
|
blockedContacts.visible = (_showBlocked == "true")
|
|
|
|
}
|
2020-06-23 23:42:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ListModel {
|
|
|
|
id: blockedContactsModel
|
|
|
|
}
|
|
|
|
|
2020-08-24 22:01:00 +00:00
|
|
|
ColumnLayout {
|
2020-06-23 23:42:51 +00:00
|
|
|
id: blockedContacts
|
|
|
|
Layout.fillWidth: true
|
|
|
|
spacing: 0
|
|
|
|
|
|
|
|
Repeater {
|
|
|
|
id: blockedContactsRepeater
|
|
|
|
model: blockedContactsModel // ... AND DISPLAYED HERE
|
|
|
|
delegate: ContactRow {
|
|
|
|
handle: _handle
|
|
|
|
displayName: _displayName
|
|
|
|
image: _image
|
|
|
|
badge: _badge
|
|
|
|
status: _status
|
|
|
|
authorization: _authorization
|
|
|
|
loading: _loading
|
|
|
|
Layout.fillWidth: true
|
2020-11-13 00:42:03 +00:00
|
|
|
visible: filterContact(displayName, handle)
|
2020-06-23 23:42:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|