2020-06-17 19:18:31 +00:00
|
|
|
|
import QtQuick 2.13
|
|
|
|
|
import QtQuick.Controls 2.13
|
|
|
|
|
import QtQuick.Layouts 1.13
|
2021-09-28 15:04:06 +00:00
|
|
|
|
|
2022-03-21 15:33:14 +00:00
|
|
|
|
import StatusQ.Core 0.1
|
2021-10-26 14:21:08 +00:00
|
|
|
|
import StatusQ.Components 0.1
|
2021-10-25 19:37:44 +00:00
|
|
|
|
import StatusQ.Controls 0.1
|
|
|
|
|
import StatusQ.Core.Theme 0.1
|
|
|
|
|
|
2021-09-28 15:04:06 +00:00
|
|
|
|
import utils 1.0
|
2021-10-26 14:21:08 +00:00
|
|
|
|
|
2021-10-27 21:27:49 +00:00
|
|
|
|
import shared.views 1.0
|
|
|
|
|
import shared.panels 1.0
|
|
|
|
|
import shared.popups 1.0
|
|
|
|
|
import shared.controls 1.0
|
2022-07-06 19:27:04 +00:00
|
|
|
|
import shared.views.chat 1.0
|
2021-10-06 09:16:39 +00:00
|
|
|
|
|
2021-12-31 12:29:51 +00:00
|
|
|
|
import "../stores"
|
2021-10-06 09:16:39 +00:00
|
|
|
|
import "../panels"
|
|
|
|
|
import "../popups"
|
2020-05-27 21:28:25 +00:00
|
|
|
|
|
2022-05-07 11:45:15 +00:00
|
|
|
|
SettingsContentBase {
|
2021-10-06 09:16:39 +00:00
|
|
|
|
id: root
|
2022-07-27 18:32:47 +00:00
|
|
|
|
onWidthChanged: { contentItem.width = contentWidth; }
|
2022-06-03 15:32:03 +00:00
|
|
|
|
onHeightChanged: { contentItem.height = height; }
|
2021-12-31 12:29:51 +00:00
|
|
|
|
property ContactsStore contactsStore
|
2021-10-06 09:16:39 +00:00
|
|
|
|
|
2020-07-24 11:27:26 +00:00
|
|
|
|
property alias searchStr: searchBox.text
|
2020-09-17 08:47:14 +00:00
|
|
|
|
property bool isPending: false
|
2022-03-28 14:42:26 +00:00
|
|
|
|
|
2022-05-07 11:45:15 +00:00
|
|
|
|
headerComponents: [
|
|
|
|
|
StatusButton {
|
|
|
|
|
text: qsTr("Send contact request to chat key")
|
|
|
|
|
onClicked: {
|
|
|
|
|
sendContactRequest.open()
|
2022-03-28 14:42:26 +00:00
|
|
|
|
}
|
2022-03-07 20:34:59 +00:00
|
|
|
|
}
|
2022-05-07 11:45:15 +00:00
|
|
|
|
]
|
|
|
|
|
|
2022-07-06 19:27:04 +00:00
|
|
|
|
|
|
|
|
|
function openContextMenu(publicKey, name, icon) {
|
|
|
|
|
contactContextMenu.selectedUserPublicKey = publicKey
|
|
|
|
|
contactContextMenu.selectedUserDisplayName = name
|
|
|
|
|
contactContextMenu.selectedUserIcon = icon
|
|
|
|
|
contactContextMenu.popup()
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-03 15:32:03 +00:00
|
|
|
|
Item {
|
|
|
|
|
id: contentItem
|
2022-03-07 20:34:59 +00:00
|
|
|
|
|
2022-07-06 19:27:04 +00:00
|
|
|
|
MessageContextMenuView {
|
|
|
|
|
id: contactContextMenu
|
|
|
|
|
store: ({contactsStore: root.contactsStore})
|
|
|
|
|
isProfile: true
|
|
|
|
|
|
|
|
|
|
onOpenProfileClicked: function (pubkey, state) {
|
|
|
|
|
Global.openProfilePopup(pubkey, null, state)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onCreateOneToOneChat: function (communityId, chatId, ensName) {
|
|
|
|
|
root.contactsStore.joinPrivateChat(chatId)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-14 20:09:07 +00:00
|
|
|
|
SearchBox {
|
|
|
|
|
id: searchBox
|
2022-06-03 15:32:03 +00:00
|
|
|
|
anchors.left: parent.left
|
|
|
|
|
anchors.right: parent.right
|
2022-07-22 10:28:04 +00:00
|
|
|
|
placeholderText: qsTr("Search by a display name or chat key")
|
2020-07-21 21:03:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-05-23 11:45:29 +00:00
|
|
|
|
StatusTabBar {
|
2022-03-15 15:55:18 +00:00
|
|
|
|
id: contactsTabBar
|
2022-06-03 15:32:03 +00:00
|
|
|
|
anchors.left: parent.left
|
|
|
|
|
anchors.right: parent.right
|
|
|
|
|
anchors.top: searchBox.bottom
|
|
|
|
|
anchors.topMargin: (2 * Style.current.padding)
|
2022-05-23 11:45:29 +00:00
|
|
|
|
|
2022-03-15 15:55:18 +00:00
|
|
|
|
StatusTabButton {
|
|
|
|
|
id: contactsBtn
|
2022-05-23 11:45:29 +00:00
|
|
|
|
width: implicitWidth
|
|
|
|
|
text: qsTr("Contacts")
|
2021-01-14 20:09:07 +00:00
|
|
|
|
}
|
2022-03-15 15:55:18 +00:00
|
|
|
|
StatusTabButton {
|
|
|
|
|
id: pendingRequestsBtn
|
2022-05-23 11:45:29 +00:00
|
|
|
|
width: implicitWidth
|
2022-03-24 20:55:22 +00:00
|
|
|
|
enabled: root.contactsStore.receivedContactRequestsModel.count > 0 ||
|
|
|
|
|
root.contactsStore.sentContactRequestsModel.count > 0
|
2022-05-23 11:45:29 +00:00
|
|
|
|
text: qsTr("Pending Requests")
|
2022-05-16 15:02:03 +00:00
|
|
|
|
badge.value: root.contactsStore.receivedContactRequestsModel.count
|
2022-03-15 15:55:18 +00:00
|
|
|
|
}
|
2022-04-08 20:17:16 +00:00
|
|
|
|
// Temporary commented until we provide appropriate flags on the `status-go` side to cover all sections.
|
2022-05-07 11:45:15 +00:00
|
|
|
|
// StatusTabButton {
|
|
|
|
|
// id: rejectedRequestsBtn
|
2022-05-23 11:45:29 +00:00
|
|
|
|
// width: implicitWidth
|
2022-05-07 11:45:15 +00:00
|
|
|
|
// enabled: root.contactsStore.receivedButRejectedContactRequestsModel.count > 0 ||
|
|
|
|
|
// root.contactsStore.sentButRejectedContactRequestsModel.count > 0
|
|
|
|
|
// btnText: qsTr("Rejected Requests")
|
|
|
|
|
// }
|
2022-03-15 15:55:18 +00:00
|
|
|
|
StatusTabButton {
|
|
|
|
|
id: blockedBtn
|
2022-05-23 11:45:29 +00:00
|
|
|
|
width: implicitWidth
|
2022-03-15 15:55:18 +00:00
|
|
|
|
enabled: root.contactsStore.blockedContactsModel.count > 0
|
2022-05-23 11:45:29 +00:00
|
|
|
|
text: qsTr("Blocked")
|
2021-01-14 20:09:07 +00:00
|
|
|
|
}
|
2020-07-24 11:27:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-15 15:55:18 +00:00
|
|
|
|
StackLayout {
|
|
|
|
|
id: stackLayout
|
2022-06-03 15:32:03 +00:00
|
|
|
|
anchors.left: parent.left
|
|
|
|
|
anchors.right: parent.right
|
|
|
|
|
anchors.top: contactsTabBar.bottom
|
|
|
|
|
anchors.bottom: parent.bottom
|
2022-03-15 15:55:18 +00:00
|
|
|
|
currentIndex: contactsTabBar.currentIndex
|
|
|
|
|
// CONTACTS
|
2022-06-03 15:32:03 +00:00
|
|
|
|
Column {
|
|
|
|
|
ContactsListPanel {
|
|
|
|
|
id: verifiedContacts
|
|
|
|
|
width: parent.width
|
|
|
|
|
height: ((contactsListHeight < (stackLayout.height/2)) ? contactsListHeight :
|
|
|
|
|
(stackLayout.height-mutualContacts.contactsListHeight))
|
|
|
|
|
scrollbarOn: mutualContacts.contactsListHeight > (stackLayout.height/2) ?
|
|
|
|
|
(contactsListHeight > (stackLayout.height/2)) : (contactsListHeight > parent.height)
|
|
|
|
|
title: qsTr("Identity Verified Contacts")
|
|
|
|
|
contactsModel: root.contactsStore.myContactsModel
|
|
|
|
|
searchString: searchBox.text
|
2022-07-06 19:27:04 +00:00
|
|
|
|
onOpenContactContextMenu: function (publicKey, name, icon) {
|
|
|
|
|
root.openContextMenu(publicKey, name, icon)
|
2022-03-15 15:55:18 +00:00
|
|
|
|
}
|
2022-07-06 19:27:04 +00:00
|
|
|
|
contactsStore: root.contactsStore
|
|
|
|
|
panelUsage: Constants.contactsPanelUsage.verifiedMutualContacts
|
2022-06-03 15:32:03 +00:00
|
|
|
|
onSendMessageActionTriggered: {
|
|
|
|
|
root.contactsStore.joinPrivateChat(publicKey)
|
2022-03-15 15:55:18 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-07-21 21:03:22 +00:00
|
|
|
|
|
2022-06-03 15:32:03 +00:00
|
|
|
|
ContactsListPanel {
|
|
|
|
|
id: mutualContacts
|
|
|
|
|
width: parent.width
|
|
|
|
|
height: (contactsListHeight+50)
|
|
|
|
|
scrollbarOn: verifiedContacts.contactsListHeight > (stackLayout.height/2) ?
|
|
|
|
|
(contactsListHeight > (stackLayout.height/2)) : (contactsListHeight > parent.height)
|
|
|
|
|
title: qsTr("Contacts")
|
|
|
|
|
contactsModel: root.contactsStore.myContactsModel
|
|
|
|
|
searchString: searchBox.text
|
2022-07-06 19:27:04 +00:00
|
|
|
|
contactsStore: root.contactsStore
|
|
|
|
|
onOpenContactContextMenu: function (publicKey, name, icon) {
|
|
|
|
|
root.openContextMenu(publicKey, name, icon)
|
2022-06-03 15:32:03 +00:00
|
|
|
|
}
|
2022-07-06 19:27:04 +00:00
|
|
|
|
panelUsage: Constants.contactsPanelUsage.mutualContacts
|
2022-06-03 15:32:03 +00:00
|
|
|
|
|
|
|
|
|
onSendMessageActionTriggered: {
|
|
|
|
|
root.contactsStore.joinPrivateChat(publicKey)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Item {
|
2022-03-15 15:55:18 +00:00
|
|
|
|
width: parent.width
|
2022-06-03 15:32:03 +00:00
|
|
|
|
height: parent.height
|
|
|
|
|
NoFriendsRectangle {
|
|
|
|
|
anchors.centerIn: parent
|
|
|
|
|
visible: root.contactsStore.myContactsModel.count === 0
|
2022-04-04 11:26:30 +00:00
|
|
|
|
text: qsTr("You don’t have any contacts yet")
|
2022-06-03 15:32:03 +00:00
|
|
|
|
}
|
2022-03-15 15:55:18 +00:00
|
|
|
|
}
|
2021-09-17 15:08:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-15 15:55:18 +00:00
|
|
|
|
// PENDING REQUESTS
|
2022-06-03 15:32:03 +00:00
|
|
|
|
Column {
|
|
|
|
|
ContactsListPanel {
|
|
|
|
|
id: receivedRequests
|
|
|
|
|
width: parent.width
|
|
|
|
|
height: ((contactsListHeight < (stackLayout.height/2)) ? contactsListHeight :
|
|
|
|
|
(stackLayout.height-sentRequests.contactsListHeight))
|
|
|
|
|
scrollbarOn: (sentRequests.contactsListHeight > (stackLayout.height/2)) ?
|
|
|
|
|
(contactsListHeight > (stackLayout.height/2)) :
|
|
|
|
|
(contactsListHeight > (stackLayout.height - sentRequests.contactsListHeight))
|
|
|
|
|
title: qsTr("Received")
|
|
|
|
|
searchString: searchBox.text
|
2022-07-06 19:27:04 +00:00
|
|
|
|
contactsStore: root.contactsStore
|
|
|
|
|
onOpenContactContextMenu: function (publicKey, name, icon) {
|
|
|
|
|
root.openContextMenu(publicKey, name, icon)
|
|
|
|
|
}
|
2022-06-03 15:32:03 +00:00
|
|
|
|
contactsModel: root.contactsStore.receivedContactRequestsModel
|
|
|
|
|
panelUsage: Constants.contactsPanelUsage.receivedContactRequest
|
|
|
|
|
|
|
|
|
|
onContactRequestAccepted: {
|
|
|
|
|
root.contactsStore.acceptContactRequest(publicKey)
|
2022-03-24 20:55:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-03 15:32:03 +00:00
|
|
|
|
onContactRequestRejected: {
|
2022-07-13 09:41:09 +00:00
|
|
|
|
root.contactsStore.dismissContactRequest(publicKey)
|
2022-06-03 15:32:03 +00:00
|
|
|
|
}
|
2022-06-28 18:11:18 +00:00
|
|
|
|
|
|
|
|
|
onShowVerificationRequest: {
|
|
|
|
|
try {
|
|
|
|
|
let request = root.contactsStore.getVerificationDetailsFromAsJson(publicKey)
|
|
|
|
|
Global.openPopup(contactVerificationRequestPopupComponent, {
|
|
|
|
|
senderPublicKey: request.from,
|
|
|
|
|
senderDisplayName: request.displayName,
|
|
|
|
|
senderIcon: request.icon,
|
|
|
|
|
challengeText: request.challenge,
|
|
|
|
|
responseText: request.response,
|
|
|
|
|
messageTimestamp: request.requestedAt,
|
|
|
|
|
responseTimestamp: request.repliedAt
|
|
|
|
|
})
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error("Error getting or parsing verification data", e)
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-03 15:32:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ContactsListPanel {
|
|
|
|
|
id: sentRequests
|
|
|
|
|
width: parent.width
|
|
|
|
|
height: (contactsListHeight+50)
|
|
|
|
|
scrollbarOn: (receivedRequests.contactsListHeight > (stackLayout.height/2)) ?
|
|
|
|
|
(contactsListHeight > (stackLayout.height/2)) :
|
|
|
|
|
(contactsListHeight > (stackLayout.height - receivedRequests.contactsListHeight))
|
|
|
|
|
title: qsTr("Sent")
|
|
|
|
|
searchString: searchBox.text
|
2022-07-06 19:27:04 +00:00
|
|
|
|
contactsStore: root.contactsStore
|
|
|
|
|
onOpenContactContextMenu: function (publicKey, name, icon) {
|
|
|
|
|
root.openContextMenu(publicKey, name, icon)
|
|
|
|
|
}
|
2022-06-03 15:32:03 +00:00
|
|
|
|
contactsModel: root.contactsStore.sentContactRequestsModel
|
|
|
|
|
panelUsage: Constants.contactsPanelUsage.sentContactRequest
|
2022-03-24 20:55:22 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-08 20:17:16 +00:00
|
|
|
|
// Temporary commented until we provide appropriate flags on the `status-go` side to cover all sections.
|
2022-05-07 11:45:15 +00:00
|
|
|
|
// // REJECTED REQUESTS
|
|
|
|
|
// Item {
|
|
|
|
|
// Layout.fillWidth: true
|
2022-06-03 15:32:03 +00:00
|
|
|
|
// //Layout.fillHeight: true
|
2022-05-07 11:45:15 +00:00
|
|
|
|
|
|
|
|
|
// ColumnLayout {
|
2022-06-03 15:32:03 +00:00
|
|
|
|
// //anchors.fill: parent
|
2022-05-07 11:45:15 +00:00
|
|
|
|
|
|
|
|
|
// ContactsListPanel {
|
|
|
|
|
// Layout.fillWidth: true
|
|
|
|
|
// Layout.preferredHeight: root.height * 0.5
|
|
|
|
|
// clip: true
|
|
|
|
|
// title: qsTr("Received")
|
|
|
|
|
// searchString: searchBox.text
|
2022-07-06 19:27:04 +00:00
|
|
|
|
// contactsStore: root.contactsStore
|
|
|
|
|
// onOpenContactContextMenu: function (publicKey, name, icon) {
|
|
|
|
|
// root.openContextMenu(publicKey, name, icon)
|
|
|
|
|
// }
|
2022-05-07 11:45:15 +00:00
|
|
|
|
// contactsModel: root.contactsStore.receivedButRejectedContactRequestsModel
|
|
|
|
|
// panelUsage: Constants.contactsPanelUsage.rejectedReceivedContactRequest
|
|
|
|
|
|
|
|
|
|
// onRejectionRemoved: {
|
|
|
|
|
// root.contactsStore.removeContactRequestRejection(publicKey)
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// ContactsListPanel {
|
|
|
|
|
// Layout.fillWidth: true
|
|
|
|
|
// Layout.preferredHeight: root.height * 0.5
|
|
|
|
|
// clip: true
|
|
|
|
|
// title: qsTr("Sent")
|
|
|
|
|
// searchString: searchBox.text
|
2022-07-06 19:27:04 +00:00
|
|
|
|
// contactsStore: root.contactsStore
|
|
|
|
|
// onOpenContactContextMenu: function (publicKey, name, icon) {
|
|
|
|
|
// root.openContextMenu(publicKey, name, icon)
|
|
|
|
|
// }
|
2022-05-07 11:45:15 +00:00
|
|
|
|
// contactsModel: root.contactsStore.sentButRejectedContactRequestsModel
|
|
|
|
|
// panelUsage: Constants.contactsPanelUsage.rejectedSentContactRequest
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// Item {
|
|
|
|
|
// Layout.fillWidth: true
|
|
|
|
|
// Layout.fillHeight: true
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
2021-01-14 20:09:07 +00:00
|
|
|
|
|
2022-03-15 15:55:18 +00:00
|
|
|
|
// BLOCKED
|
2021-10-06 09:16:39 +00:00
|
|
|
|
ContactsListPanel {
|
2022-06-03 15:32:03 +00:00
|
|
|
|
width: parent.width
|
|
|
|
|
height: (contactsListHeight+50)
|
2022-03-24 20:55:22 +00:00
|
|
|
|
searchString: searchBox.text
|
2022-07-06 19:27:04 +00:00
|
|
|
|
contactsStore: root.contactsStore
|
|
|
|
|
onOpenContactContextMenu: function (publicKey, name, icon) {
|
|
|
|
|
root.openContextMenu(publicKey, name, icon)
|
|
|
|
|
}
|
2021-12-31 12:29:51 +00:00
|
|
|
|
contactsModel: root.contactsStore.blockedContactsModel
|
2022-03-24 20:55:22 +00:00
|
|
|
|
panelUsage: Constants.contactsPanelUsage.blockedContacts
|
2021-01-14 20:09:07 +00:00
|
|
|
|
}
|
2020-09-17 08:47:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-01-14 20:09:07 +00:00
|
|
|
|
Component {
|
|
|
|
|
id: loadingIndicator
|
2021-04-26 10:25:01 +00:00
|
|
|
|
StatusLoadingIndicator {
|
2021-01-14 20:09:07 +00:00
|
|
|
|
width: 12
|
|
|
|
|
height: 12
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-16 18:04:56 +00:00
|
|
|
|
|
2022-05-07 11:45:15 +00:00
|
|
|
|
// TODO: Make BlockContactConfirmationDialog a dynamic component on a future refactor
|
|
|
|
|
BlockContactConfirmationDialog {
|
|
|
|
|
id: blockContactConfirmationDialog
|
|
|
|
|
onBlockButtonClicked: {
|
|
|
|
|
root.contactsStore.blockContact(blockContactConfirmationDialog.contactAddress)
|
|
|
|
|
blockContactConfirmationDialog.close()
|
|
|
|
|
}
|
2021-10-06 09:16:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2022-05-07 11:45:15 +00:00
|
|
|
|
// TODO: Make ConfirmationDialog a dynamic component on a future refactor
|
|
|
|
|
ConfirmationDialog {
|
|
|
|
|
id: removeContactConfirmationDialog
|
2022-04-04 11:26:30 +00:00
|
|
|
|
header.title: qsTr("Remove contact")
|
|
|
|
|
confirmationText: qsTr("Are you sure you want to remove this contact?")
|
2022-05-07 11:45:15 +00:00
|
|
|
|
onConfirmButtonClicked: {
|
2022-07-06 16:51:56 +00:00
|
|
|
|
if (Utils.getContactDetailsAsJson(removeContactConfirmationDialog.value).isAdded) {
|
2022-05-07 11:45:15 +00:00
|
|
|
|
root.contactsStore.removeContact(removeContactConfirmationDialog.value);
|
|
|
|
|
}
|
|
|
|
|
removeContactConfirmationDialog.close()
|
2022-06-28 18:11:18 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Component {
|
|
|
|
|
id: contactVerificationRequestPopupComponent
|
|
|
|
|
ContactVerificationRequestPopup {
|
|
|
|
|
onResponseSent: {
|
|
|
|
|
root.contactsStore.acceptVerificationRequest(senderPublicKey, response)
|
|
|
|
|
}
|
|
|
|
|
onVerificationRefused: {
|
|
|
|
|
root.contactsStore.declineVerificationRequest(senderPublicKey)
|
|
|
|
|
}
|
2021-10-06 09:16:39 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-03-28 14:42:26 +00:00
|
|
|
|
|
2022-05-07 11:45:15 +00:00
|
|
|
|
Loader {
|
|
|
|
|
id: sendContactRequest
|
2022-05-16 10:31:24 +00:00
|
|
|
|
width: parent.width
|
|
|
|
|
height: parent.height
|
2022-05-07 11:45:15 +00:00
|
|
|
|
active: false
|
2022-03-28 14:42:26 +00:00
|
|
|
|
|
2022-05-07 11:45:15 +00:00
|
|
|
|
function open() {
|
|
|
|
|
active = true
|
|
|
|
|
sendContactRequest.item.open()
|
|
|
|
|
}
|
|
|
|
|
function close() {
|
|
|
|
|
active = false
|
|
|
|
|
}
|
2022-03-28 14:42:26 +00:00
|
|
|
|
|
2022-05-07 11:45:15 +00:00
|
|
|
|
sourceComponent: SendContactRequestModal {
|
2022-05-16 10:31:24 +00:00
|
|
|
|
anchors.centerIn: parent
|
2022-05-07 11:45:15 +00:00
|
|
|
|
contactsStore: root.contactsStore
|
|
|
|
|
onClosed: {
|
|
|
|
|
sendContactRequest.close();
|
|
|
|
|
}
|
2022-03-28 14:42:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-16 18:04:56 +00:00
|
|
|
|
}
|
2021-10-06 09:16:39 +00:00
|
|
|
|
|