2018-10-23 18:52:13 +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
|
2018-10-30 19:48:37 +00:00
|
|
|
import QtQuick.Window 2.11
|
2018-10-23 18:52:13 +00:00
|
|
|
|
2020-05-20 00:03:08 +00:00
|
|
|
import "opaque"
|
|
|
|
import "opaque/fonts"
|
|
|
|
import "opaque/fonts/MutantStandard.js" as Mutant
|
|
|
|
import "opaque/theme"
|
|
|
|
|
2019-01-26 22:54:08 +00:00
|
|
|
import "overlays"
|
2018-11-22 00:01:17 +00:00
|
|
|
import "panes"
|
2020-05-20 02:39:01 +00:00
|
|
|
import "widgets"
|
2019-01-30 19:46:22 +00:00
|
|
|
import "utils.js" as Utils
|
2018-10-23 18:52:13 +00:00
|
|
|
|
2019-02-13 00:06:52 +00:00
|
|
|
ApplicationWindow {
|
2020-04-27 21:55:10 +00:00
|
|
|
id: windowItem
|
|
|
|
width: 1200
|
|
|
|
height: 800
|
|
|
|
visible: true
|
|
|
|
title: "cwtch" + ""
|
2020-04-27 20:53:46 +00:00
|
|
|
font.family: Fonts.applicationFontRegular.name
|
|
|
|
font.styleName: "Light"
|
2019-02-13 00:06:52 +00:00
|
|
|
|
2020-04-27 21:55:10 +00:00
|
|
|
readonly property real ratio: height / width
|
2018-10-23 18:52:13 +00:00
|
|
|
|
2020-04-27 21:55:10 +00:00
|
|
|
FontAwesome { // PRETTY BUTTON ICONS
|
|
|
|
id: awesome
|
2020-05-20 00:03:08 +00:00
|
|
|
resource: "qrc:/qml/opaque/fonts/fontawesome.ttf"
|
2020-04-27 21:55:10 +00:00
|
|
|
}
|
2018-10-28 02:49:14 +00:00
|
|
|
|
2020-04-27 21:55:10 +00:00
|
|
|
FontLoader {
|
2020-05-20 00:03:08 +00:00
|
|
|
source: "qrc:/qml/opaque/fonts/AdobeBlank.ttf"
|
2020-04-27 21:55:10 +00:00
|
|
|
}
|
2020-01-10 21:02:33 +00:00
|
|
|
|
2020-04-27 21:55:10 +00:00
|
|
|
function parse(text, size, isntEditable) { // REPLACE EMOJI WITH <IMG> TAGS
|
2020-11-27 00:30:54 +00:00
|
|
|
var retText = Utils.htmlEscaped(text)
|
|
|
|
retText = retText.replace(/\n/g,"<br/>").replace(/\s\s/g, " ")
|
2020-01-10 21:02:33 +00:00
|
|
|
|
2020-04-27 21:55:10 +00:00
|
|
|
// mutant standard stickers
|
2020-11-27 00:30:54 +00:00
|
|
|
if (isntEditable) retText = Mutant.standard.parse(retText, 1.5 * gcd.themeScale * Theme.chatSize)
|
2020-01-10 21:02:33 +00:00
|
|
|
|
2020-04-27 21:55:10 +00:00
|
|
|
return retText
|
|
|
|
}
|
2018-10-28 02:49:14 +00:00
|
|
|
|
2019-04-16 19:40:19 +00:00
|
|
|
function ptToPx(pt) {
|
|
|
|
return Screen.pixelDensity * 25.4 * pt / 72
|
|
|
|
}
|
|
|
|
|
|
|
|
function pxToPt(px) {
|
|
|
|
return px * 72 / (Screen.pixelDensity * 25.4)
|
|
|
|
}
|
2018-10-30 19:48:37 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
StackView {
|
|
|
|
id: rootStack
|
2020-05-01 23:53:44 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
anchors.fill: parent
|
2020-05-01 23:53:44 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
property bool splash: true
|
|
|
|
|
|
|
|
// Splash pane
|
|
|
|
initialItem: Rectangle {
|
2020-04-08 22:30:10 +00:00
|
|
|
color: Theme.backgroundMainColor
|
2018-10-23 18:52:13 +00:00
|
|
|
|
2019-03-19 20:35:31 +00:00
|
|
|
visible: true
|
2018-10-23 18:52:13 +00:00
|
|
|
|
2019-03-19 20:35:31 +00:00
|
|
|
SplashPane {
|
2019-04-24 20:32:20 +00:00
|
|
|
id: splashPane
|
2019-03-19 20:35:31 +00:00
|
|
|
anchors.fill: parent
|
2019-04-24 20:32:20 +00:00
|
|
|
running: true
|
2019-03-19 20:35:31 +00:00
|
|
|
}
|
|
|
|
}
|
2019-10-22 18:55:16 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
replaceEnter: Transition {
|
|
|
|
PropertyAnimation{
|
|
|
|
property: "opacity"
|
|
|
|
from: 0
|
|
|
|
to: 1
|
2020-11-18 01:47:31 +00:00
|
|
|
duration: 200
|
2020-04-27 21:55:10 +00:00
|
|
|
}
|
2019-10-22 18:55:16 +00:00
|
|
|
}
|
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
replaceExit: Transition {
|
|
|
|
PropertyAnimation{
|
|
|
|
property: "opacity"
|
|
|
|
from: 1
|
|
|
|
to: 0
|
2020-11-18 01:47:31 +00:00
|
|
|
duration: 200
|
2020-05-26 18:21:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-20 19:06:41 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
// The actual app
|
|
|
|
property Item mainLayout: Rectangle {
|
|
|
|
color: Theme.backgroundMainColor
|
2020-05-26 18:21:27 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
Toolbar {
|
|
|
|
id: toolbar
|
2019-11-30 01:35:57 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
onLeftMenu: {
|
|
|
|
gcd.requestSettings()
|
|
|
|
parentStack.pane = parentStack.settingsPane
|
|
|
|
}
|
2019-11-30 01:35:57 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
onBack: { backFn() }
|
|
|
|
|
|
|
|
onRightMenu: {
|
2020-11-26 22:08:16 +00:00
|
|
|
// If a group is selected....
|
2020-11-17 20:10:27 +00:00
|
|
|
if (gcd.selectedConversation.length == 32) {
|
|
|
|
theStack.pane = theStack.groupProfilePane
|
|
|
|
gcd.requestGroupSettings(gcd.selectedConversation)
|
|
|
|
} else {
|
2020-11-26 22:08:16 +00:00
|
|
|
// if a peer is selected..
|
|
|
|
if (theStack.pane == theStack.userProfilePane) {
|
|
|
|
theStack.pane = theStack.messagePane
|
|
|
|
} else {
|
|
|
|
theStack.pane = theStack.userProfilePane
|
|
|
|
gcd.requestPeerSettings(gcd.selectedConversation)
|
|
|
|
}
|
2020-11-17 20:10:27 +00:00
|
|
|
}
|
|
|
|
}
|
2019-11-30 01:35:57 +00:00
|
|
|
}
|
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
StackLayout {
|
|
|
|
id: parentStack
|
|
|
|
|
|
|
|
readonly property int managementPane: 0
|
|
|
|
readonly property int settingsPane: 1
|
|
|
|
readonly property int addEditProfilePane: 2
|
|
|
|
readonly property int profilePane: 3
|
|
|
|
readonly property int addEditServerPane: 4
|
2020-11-23 20:50:06 +00:00
|
|
|
|
|
|
|
currentIndex: gcd.firstTime ? parentStack.settingsPane : parentStack.managementPane
|
|
|
|
|
|
|
|
anchors.right: parent.right
|
|
|
|
anchors.left: parent.left
|
|
|
|
anchors.bottom: statusbar.top
|
|
|
|
anchors.top: toolbar.bottom
|
|
|
|
|
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
property alias pane: parentStack.currentIndex
|
|
|
|
|
|
|
|
Rectangle { // Profile login/management pane
|
|
|
|
Layout.fillHeight: true
|
|
|
|
Layout.fillWidth: true
|
|
|
|
visible: false
|
|
|
|
color: Theme.backgroundMainColor
|
|
|
|
|
|
|
|
ProfileManagerPane {
|
|
|
|
id: profilesPane
|
|
|
|
anchors.fill: parent
|
|
|
|
}
|
2019-03-19 20:35:31 +00:00
|
|
|
}
|
2020-08-24 22:01:00 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
Rectangle { // Settings pane
|
|
|
|
Layout.fillHeight: true
|
|
|
|
Layout.fillWidth: true
|
|
|
|
color: Theme.backgroundPaneColor
|
|
|
|
|
|
|
|
SettingsPane {
|
|
|
|
id: settingsPane
|
|
|
|
anchors.fill: parent
|
|
|
|
}
|
2020-08-24 22:01:00 +00:00
|
|
|
}
|
2018-10-29 18:00:21 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
Rectangle { // Profile Add / Edit pane
|
|
|
|
Layout.fillHeight: true
|
|
|
|
Layout.fillWidth: true
|
|
|
|
color: Theme.backgroundPaneColor
|
2018-10-29 18:00:21 +00:00
|
|
|
|
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
ProfileAddEditPane{
|
|
|
|
id: profileAddEditPane
|
|
|
|
anchors.fill: parent
|
|
|
|
}
|
|
|
|
}
|
2018-10-29 18:00:21 +00:00
|
|
|
|
2020-11-20 19:06:41 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
RowLayout { // Profile Pane (contact list + overlays)
|
|
|
|
Layout.fillHeight: true
|
|
|
|
Layout.fillWidth: true
|
|
|
|
spacing: 0
|
2019-03-19 20:35:31 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
Rectangle { // THE LEFT PANE WITH TOOLS AND CONTACTS
|
2020-07-25 16:47:19 +00:00
|
|
|
color: Theme.backgroundMainColor
|
2020-11-17 20:10:27 +00:00
|
|
|
Layout.fillHeight: true
|
|
|
|
Layout.minimumWidth: Theme.sidePaneMinSize
|
|
|
|
Layout.maximumWidth: theStack.pane == theStack.emptyPane ? parent.width : Theme.sidePaneMinSize
|
|
|
|
Layout.fillWidth: theStack.pane == theStack.emptyPane ? true : false
|
|
|
|
visible: (windowItem.width >= Theme.doublePaneMinSize && !Qt.inputMethod.visible) || theStack.pane == theStack.emptyPane
|
|
|
|
|
|
|
|
ContactList {
|
|
|
|
anchors.top: parent.top
|
|
|
|
anchors.left: parent.left
|
|
|
|
anchors.bottom: parent.bottom
|
|
|
|
anchors.right: (divider.visible ? divider.left : parent.right)
|
|
|
|
//anchors.topMargin: 10 * gcd.themeScale
|
|
|
|
dualPane: theStack.pane != theStack.emptyPane || theStack.pane == undefined
|
|
|
|
}
|
|
|
|
|
|
|
|
Rectangle {
|
|
|
|
id: divider
|
|
|
|
width: 2
|
|
|
|
anchors.right: parent.right
|
|
|
|
height: parent.height - (20 * gcd.themeScale)
|
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
visible: theStack.pane != theStack.emptyPane
|
|
|
|
//Layout.fillHeight: true
|
|
|
|
color: Theme.dividerColor
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Rectangle { // THE RIGHT PANE WHERE THE MESSAGES AND STUFF GO
|
|
|
|
color: Theme.backgroundPaneColor
|
2020-07-25 16:47:19 +00:00
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.fillHeight: true
|
2020-11-17 20:10:27 +00:00
|
|
|
|
|
|
|
StackLayout {
|
|
|
|
id: theStack
|
2020-07-25 16:47:19 +00:00
|
|
|
anchors.fill: parent
|
2020-11-17 20:10:27 +00:00
|
|
|
currentIndex: 0
|
|
|
|
|
|
|
|
property alias pane: theStack.currentIndex
|
|
|
|
readonly property int emptyPane: 0
|
|
|
|
readonly property int messagePane: 1
|
|
|
|
readonly property int userProfilePane: 2
|
|
|
|
readonly property int groupProfilePane: 3
|
|
|
|
readonly property int addPeerGroupPane: 4
|
|
|
|
readonly property int serverInfoPane: 5
|
|
|
|
|
|
|
|
Item { anchors.fill: parent } // empty
|
|
|
|
|
|
|
|
Rectangle {
|
|
|
|
color: Theme.backgroundMainColor
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.fillHeight: true
|
|
|
|
OverlayPane { // messagePane
|
|
|
|
anchors.fill: parent
|
|
|
|
anchors.topMargin: 10 * gcd.themeScale
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
PeerSettingsPane { anchors.fill: parent }
|
|
|
|
|
|
|
|
GroupSettingsPane{ anchors.fill: parent }
|
|
|
|
|
|
|
|
AddPeerGroupPane {
|
|
|
|
id: addPeerGroupPaneInstance
|
|
|
|
anchors.fill: parent
|
|
|
|
}
|
|
|
|
|
|
|
|
ServerInfoPane { anchors.fill: parent }
|
|
|
|
|
|
|
|
onCurrentIndexChanged: {
|
|
|
|
parentStack.updateToolbar()
|
|
|
|
if (currentIndex == emptyPane) {
|
|
|
|
toolbar.hideTitle()
|
|
|
|
toolbar.rightMenuVisible = false
|
|
|
|
} else if (currentIndex == addPeerGroupPane) {
|
|
|
|
//: New Connection
|
|
|
|
toolbar.setTitle(qsTr('new-connection-pane-title'))
|
|
|
|
toolbar.rightMenuVisible = false
|
|
|
|
addPeerGroupPaneInstance.reset()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onWidthChanged: {toolbar.titleWidth = width}
|
2020-07-25 16:47:19 +00:00
|
|
|
}
|
2019-03-19 20:35:31 +00:00
|
|
|
}
|
2020-11-17 20:10:27 +00:00
|
|
|
}
|
2019-03-19 20:35:31 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
Rectangle { // Server Add / Edit pane
|
|
|
|
Layout.fillHeight: true
|
|
|
|
Layout.fillWidth: true
|
|
|
|
color: Theme.backgroundPaneColor
|
2020-05-01 23:53:44 +00:00
|
|
|
|
2019-03-19 20:35:31 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
ServerAddEditPane{
|
|
|
|
id: serverAddEditPane
|
2020-11-11 01:42:33 +00:00
|
|
|
anchors.fill: parent
|
|
|
|
}
|
2020-11-17 20:10:27 +00:00
|
|
|
}
|
2019-03-19 20:35:31 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
focus: true
|
|
|
|
Keys.onPressed: {
|
|
|
|
if (event.key == Qt.Key_Back) {
|
|
|
|
event.accepted = true
|
|
|
|
backFn()
|
|
|
|
}
|
|
|
|
}
|
2020-10-01 21:37:15 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
onCurrentIndexChanged : { updateToolbar(); statusbar.resetHeight() }
|
|
|
|
|
|
|
|
function updateToolbar() {
|
|
|
|
if (rootStack.splash == true) {
|
|
|
|
toolbar.hideTitle()
|
|
|
|
toolbar.rightMenuVisible = false
|
|
|
|
toolbar.visible = false
|
|
|
|
} else {
|
|
|
|
toolbar.visible = true
|
|
|
|
if (currentIndex == managementPane) {
|
2020-05-01 23:53:44 +00:00
|
|
|
toolbar.hideTitle()
|
|
|
|
toolbar.rightMenuVisible = false
|
2020-11-17 20:10:27 +00:00
|
|
|
toolbar.color = Theme.toolbarMainColor
|
|
|
|
toolbar.leftMenuVisible = true
|
|
|
|
toolbar.backVisible = false
|
|
|
|
} else {
|
|
|
|
toolbar.leftMenuVisible = false
|
|
|
|
toolbar.backVisible = true
|
|
|
|
|
|
|
|
if (currentIndex == profilePane && theStack.currentIndex == theStack.emptyPane) {
|
|
|
|
toolbar.hideTitle()
|
|
|
|
toolbar.rightMenuVisible = false
|
|
|
|
toolbar.color = Theme.toolbarMainColor
|
|
|
|
} else {
|
|
|
|
toolbar.color = Theme.toolbarAltColor
|
|
|
|
}
|
2020-05-01 23:53:44 +00:00
|
|
|
}
|
|
|
|
}
|
2019-03-19 20:35:31 +00:00
|
|
|
}
|
2019-09-13 23:24:58 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
Component.onCompleted: updateToolbar()
|
2020-10-26 20:29:58 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
Connections {
|
|
|
|
target: Theme
|
2020-05-11 22:48:07 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
onThemeChanged: {
|
|
|
|
parentStack.updateToolbar()
|
2020-06-03 23:20:40 +00:00
|
|
|
}
|
2019-09-13 23:24:58 +00:00
|
|
|
}
|
|
|
|
}
|
2020-05-26 18:21:27 +00:00
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
Statusbar {
|
|
|
|
id: statusbar
|
2020-05-26 18:21:27 +00:00
|
|
|
}
|
2020-06-03 23:20:40 +00:00
|
|
|
}
|
2020-05-01 23:53:44 +00:00
|
|
|
}
|
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
|
2020-05-11 22:48:07 +00:00
|
|
|
|
2020-05-01 23:53:44 +00:00
|
|
|
function backFn() {
|
|
|
|
if (parentStack.currentIndex == parentStack.managementPane) {
|
|
|
|
androidCwtchActivity.rootHomeButtonHandle()
|
|
|
|
} else if (parentStack.currentIndex != parentStack.profilePane) {
|
|
|
|
parentStack.currentIndex = parentStack.managementPane
|
|
|
|
} else {
|
|
|
|
if (theStack.currentIndex == theStack.emptyPane) {
|
|
|
|
gcd.selectedProfile = "none"
|
|
|
|
gcd.reloadProfileList()
|
|
|
|
parentStack.pane = parentStack.managementPane
|
|
|
|
} else if (theStack.currentIndex == theStack.userProfilePane || theStack.currentIndex == theStack.groupProfilePane) {
|
|
|
|
theStack.currentIndex = theStack.messagePane
|
|
|
|
} else {
|
|
|
|
theStack.currentIndex = theStack.emptyPane
|
|
|
|
}
|
|
|
|
}
|
2020-04-27 21:55:10 +00:00
|
|
|
}
|
|
|
|
|
2020-05-01 23:53:44 +00:00
|
|
|
PropertyAnimation { id: anmPopup; easing.type: Easing.InQuart; duration: 7000; target: popup; property: "opacity"; to: 0; }
|
2020-04-27 21:55:10 +00:00
|
|
|
|
|
|
|
Rectangle { // THE ERROR MESSAGE POPUP
|
|
|
|
id: popup
|
|
|
|
anchors.top: parent.top
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
|
|
anchors.topMargin: 20
|
|
|
|
width: lblPopup.width + 30
|
|
|
|
height: lblPopup.height + 8 * gcd.themeScale
|
|
|
|
color: "#000000"
|
|
|
|
opacity: 0.5
|
|
|
|
radius: 15
|
|
|
|
visible: false
|
|
|
|
|
|
|
|
|
|
|
|
Label {
|
|
|
|
id: lblPopup
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
font.pixelSize: 18 * gcd.themeScale
|
|
|
|
color: "#FFFFFF"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-17 20:10:27 +00:00
|
|
|
|
2020-04-27 21:55:10 +00:00
|
|
|
Connections { // POPUPS ARE INVOKED BY GO FUNCS
|
|
|
|
target: gcd
|
|
|
|
|
|
|
|
onInvokePopup: function(str) {
|
|
|
|
lblPopup.text = str
|
|
|
|
popup.opacity = 0.5
|
|
|
|
popup.visible = true
|
|
|
|
anmPopup.restart()
|
|
|
|
}
|
|
|
|
|
|
|
|
onLoaded: function() {
|
2020-11-17 20:10:27 +00:00
|
|
|
//parentStack.pane = parentStack.managementPane
|
|
|
|
rootStack.replace(rootStack.mainLayout)
|
2019-10-22 18:55:16 +00:00
|
|
|
splashPane.running = false
|
2020-11-17 20:10:27 +00:00
|
|
|
rootStack.splash = false
|
|
|
|
parentStack.updateToolbar()
|
|
|
|
statusbar.resetHeight()
|
2019-10-22 18:55:16 +00:00
|
|
|
}
|
2020-11-25 00:45:50 +00:00
|
|
|
|
|
|
|
onNotify: function(onion) {
|
|
|
|
// If we are processing QML it means the app is open, and as such we don't want to
|
|
|
|
// Send a notification - in the future we should probably use an API like this to Cancel notifications
|
|
|
|
// Until then I am leaving this here for documentation.
|
|
|
|
// androidCwtchActivity.channel = onion
|
|
|
|
// androidCwtchActivity.notification = "Message from " + onion;
|
|
|
|
}
|
2020-04-27 21:55:10 +00:00
|
|
|
}
|
2019-09-26 23:36:35 +00:00
|
|
|
|
2020-04-27 21:55:10 +00:00
|
|
|
Component.onCompleted: Mutant.standard.imagePath = gcd.assetPath;
|
2020-01-10 21:02:33 +00:00
|
|
|
|
2020-04-27 21:55:10 +00:00
|
|
|
Connections {
|
2019-09-26 23:36:35 +00:00
|
|
|
target: Qt.application
|
|
|
|
onStateChanged: function() {
|
|
|
|
// https://doc.qt.io/qt-5/qt.html#ApplicationState-enum
|
|
|
|
if (Qt.application.state == 4) {
|
|
|
|
// Active
|
|
|
|
gcd.onActivate()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-11-25 00:45:50 +00:00
|
|
|
|
|
|
|
|
2019-03-19 20:35:31 +00:00
|
|
|
}
|