Redesign: contact Row and Picture: themeing and modularizing: #276
19
go/ui/gcd.go
19
go/ui/gcd.go
|
@ -48,14 +48,14 @@ type GrandCentralDispatcher struct {
|
|||
_ func(failed bool) `signal:"ChangePasswordResponse"`
|
||||
|
||||
// contact list stuff
|
||||
_ func(handle, displayName, image, server string, badge, status int, blocked bool, loading bool, lastMsgTime int) `signal:"AddContact"`
|
||||
_ func(handle, displayName string) `signal:"UpdateContactDisplayName"`
|
||||
_ func(handle, image string) `signal:"UpdateContactPicture"`
|
||||
_ func(handle string, status int, loading bool) `signal:"UpdateContactStatus"`
|
||||
_ func(handle string, blocked bool) `signal:"UpdateContactBlocked"`
|
||||
_ func(handle string) `signal:"IncContactUnreadCount"`
|
||||
_ func(handle string) `signal:"RemoveContact"`
|
||||
_ func(handle, key, value string) `signal:"UpdateContactAttribute"`
|
||||
_ func(handle, displayName, image string, badge, status int, blocked bool, loading bool, lastMsgTime int) `signal:"AddContact"`
|
||||
_ func(handle, displayName string) `signal:"UpdateContactDisplayName"`
|
||||
_ func(handle, image string) `signal:"UpdateContactPicture"`
|
||||
_ func(handle string, status int, loading bool) `signal:"UpdateContactStatus"`
|
||||
_ func(handle string, blocked bool) `signal:"UpdateContactBlocked"`
|
||||
_ func(handle string) `signal:"IncContactUnreadCount"`
|
||||
_ func(handle string) `signal:"RemoveContact"`
|
||||
_ func(handle, key, value string) `signal:"UpdateContactAttribute"`
|
||||
|
||||
// messages pane stuff
|
||||
_ func(handle, from, displayName, message, image string, mID string, fromMe bool, ts string, ackd bool, error bool) `signal:"AppendMessage"`
|
||||
|
@ -590,6 +590,9 @@ func (this *GrandCentralDispatcher) unlockProfiles(password string) {
|
|||
|
||||
func (this *GrandCentralDispatcher) loadProfile(onion string) {
|
||||
the.Peer = the.CwtchApp.GetPeer(onion)
|
||||
if the.Peer == nil {
|
||||
return
|
||||
}
|
||||
the.EventBus = the.CwtchApp.GetEventBus(onion)
|
||||
|
||||
picVal, exists := the.Peer.GetAttribute(attr.GetPublicScope(constants.Picture))
|
||||
|
|
|
@ -242,7 +242,7 @@ func (this *manager) AddContact(handle string) {
|
|||
unread := countUnread(group.Timeline.GetMessages(), lastRead)
|
||||
picture := getProfilePic(handle)
|
||||
|
||||
this.gcd.AddContact(handle, getNick(handle), picture, group.GroupServer, unread, int(connections.ConnectionStateToType[group.State]), false, false, getLastMessageTime(&group.Timeline))
|
||||
this.gcd.AddContact(handle, getNick(handle), picture, unread, int(connections.ConnectionStateToType[group.State]), false, false, getLastMessageTime(&group.Timeline))
|
||||
}
|
||||
return
|
||||
} else if !isPeer(handle) {
|
||||
|
@ -257,7 +257,7 @@ func (this *manager) AddContact(handle string) {
|
|||
unread := countUnread(contact.Timeline.GetMessages(), lastRead)
|
||||
picture := getProfilePic(handle)
|
||||
|
||||
this.gcd.AddContact(handle, getNick(handle), picture, "", unread, int(connections.ConnectionStateToType[contact.State]), contact.Blocked, false, getLastMessageTime(&contact.Timeline))
|
||||
this.gcd.AddContact(handle, getNick(handle), picture, unread, int(connections.ConnectionStateToType[contact.State]), contact.Blocked, false, getLastMessageTime(&contact.Timeline))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
5
qml.qrc
5
qml.qrc
|
@ -18,7 +18,10 @@
|
|||
<file>qml/styles/CwtchTextAreaStyle.qml</file>
|
||||
<file>qml/styles/CwtchTextFieldStyle.qml</file>
|
||||
<file>qml/widgets/ContactList.qml</file>
|
||||
<file>qml/widgets/ContactPicture.qml</file>
|
||||
<file>qml/widgets/Portrait.qml</file>
|
||||
<file>qml/widgets/Badge.qml</file>
|
||||
<file>qml/widgets/PortraitRow.qml</file>
|
||||
<file>qml/widgets/ProfileRow.qml</file>
|
||||
<file>qml/widgets/ContactRow.qml</file>
|
||||
<file>qml/widgets/EmojiDrawer.qml</file>
|
||||
<file>qml/widgets/FontAwesome.qml</file>
|
||||
|
|
10
qml/main.qml
10
qml/main.qml
|
@ -126,21 +126,15 @@ ApplicationWindow {
|
|||
|
||||
|
||||
RowLayout { // CONTAINS EVERYTHING EXCEPT THE TOOLBAR
|
||||
/* anchors.left: ratio >= 0.92 ? parent.left : toolbar.right
|
||||
anchors.top: ratio >= 0.92 ? toolbar.bottom : parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom */
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
|
||||
|
||||
Rectangle { // THE LEFT PANE WITH TOOLS AND CONTACTS
|
||||
color: "#D2C0DD"
|
||||
Layout.fillHeight: true
|
||||
Layout.minimumWidth: Layout.maximumWidth
|
||||
Layout.maximumWidth: theStack.pane == theStack.emptyPane ? parent.width : 450
|
||||
visible: (ratio <= 1.08 && windowItem.width >= 700 && !Qt.inputMethod.visible) || theStack.pane == theStack.emptyPane
|
||||
Layout.maximumWidth: theStack.pane == theStack.emptyPane ? parent.width : Theme.sidePaneMinSize
|
||||
visible: (windowItem.width >= Theme.doublePaneMinSize && !Qt.inputMethod.visible) || theStack.pane == theStack.emptyPane
|
||||
|
||||
|
||||
ContactList{
|
||||
|
|
|
@ -106,7 +106,6 @@ ColumnLayout {
|
|||
displayName: _displayName
|
||||
image: _image
|
||||
blocked: false
|
||||
background: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,12 +6,28 @@ ThemeType {
|
|||
readonly property color purple: "#DFB9DE"
|
||||
readonly property color whitePurple: "#FFFDFF"
|
||||
readonly property color softPurple: "#FDF3FC"
|
||||
readonly property color hotPink: "#d01972"
|
||||
readonly property color pink: "#E85DA1"
|
||||
readonly property color hotPink: "#D01972"
|
||||
|
||||
backgroundMainColor: darkGrayPurple
|
||||
backgroundPaneColor: mauvePurple
|
||||
|
||||
mainTextColor: whitePurple
|
||||
defaultButtonColor: hotPink
|
||||
defaultButtonActiveColor: pink
|
||||
defaultButtonTextColor: whitePurple
|
||||
|
||||
portraitOnlineBorderColor: whitePurple
|
||||
portraitOnlineBackgroundColor: darkGrayPurple
|
||||
portraitOnlineTextColor: whitePurple
|
||||
portraitConnectingBorderColor: mauvePurple
|
||||
portraitConnectingBackgroundColor: darkGrayPurple
|
||||
portraitConnectingTextColor: whitePurple
|
||||
portraitOfflineBorderColor: deepPurple
|
||||
portraitOfflineBackgroundColor: darkGrayPurple
|
||||
portraitOfflineTextColor: softPurple
|
||||
|
||||
portraitContactBadgeColor: hotPink
|
||||
portraitContactBadgeTextColor: whitePurple
|
||||
portraitProfileBadgeColor: mauvePurple
|
||||
}
|
|
@ -2,16 +2,32 @@
|
|||
ThemeType {
|
||||
readonly property color whitePurple: "#FFFDFF"
|
||||
readonly property color softPurple: "#FDF3FC"
|
||||
readonly property color purple: "#FDF3FC"
|
||||
readonly property color purple: "#DFB9DE"
|
||||
readonly property color brightPurple: "#760388"
|
||||
readonly property color darkPurple: "#350052"
|
||||
readonly property color greyPurple: "#775F84"
|
||||
readonly property color hotPink: "#d01972"
|
||||
readonly property color pink: "#E85DA1"
|
||||
readonly property color hotPink: "#D01972"
|
||||
|
||||
backgroundMainColor: whitePurple
|
||||
backgroundPaneColor: purple
|
||||
backgroundPaneColor: softPurple
|
||||
|
||||
mainTextColor: darkPurple
|
||||
defaultButtonColor: hotPink
|
||||
defaultButtonActiveColor: pink
|
||||
defaultButtonTextColor: whitePurple
|
||||
|
||||
portraitOnlineBorderColor: darkPurple
|
||||
portraitOnlineBackgroundColor: darkPurple
|
||||
portraitOnlineTextColor: darkPurple
|
||||
portraitConnectingBorderColor: greyPurple
|
||||
portraitConnectingBackgroundColor: greyPurple
|
||||
portraitConnectingTextColor: greyPurple
|
||||
portraitOfflineBorderColor: purple
|
||||
portraitOfflineBackgroundColor: purple
|
||||
portraitOfflineTextColor: purple
|
||||
|
||||
portraitContactBadgeColor: hotPink
|
||||
portraitContactBadgeTextColor: whitePurple
|
||||
portraitProfileBadgeColor: brightPurple
|
||||
}
|
|
@ -8,7 +8,33 @@ Item {
|
|||
|
||||
readonly property color mainTextColor: theme.mainTextColor
|
||||
readonly property color defaultButtonColor: theme.defaultButtonColor
|
||||
readonly property color defaultButtonActiveColor: theme.defaultButtonActiveColor
|
||||
readonly property color defaultButtonTextColor: theme.defaultButtonTextColor
|
||||
|
||||
readonly property color portraitOnlineBorderColor: theme.portraitOnlineBorderColor
|
||||
readonly property color portraitOnlineBackgroundColor: theme.portraitOnlineBackgroundColor
|
||||
readonly property color portraitOnlineTextColor: theme.portraitOnlineTextColor
|
||||
readonly property color portraitConnectingBorderColor: theme.portraitConnectingBorderColor
|
||||
readonly property color portraitConnectingBackgroundColor: theme.portraitConnectingBackgroundColor
|
||||
readonly property color portraitConnectingTextColor: theme.portraitConnectingTextColor
|
||||
readonly property color portraitOfflineBorderColor: theme.portraitOfflineBorderColor
|
||||
readonly property color portraitOfflineBackgroundColor: theme.portraitOfflineBackgroundColor
|
||||
readonly property color portraitOfflineTextColor: theme.portraitOfflineTextColor
|
||||
|
||||
readonly property color portraitContactBadgeColor: theme.portraitContactBadgeColor
|
||||
readonly property color portraitContactBadgeTextColor: theme.portraitContactBadgeTextColor
|
||||
readonly property color portraitProfileBadgeColor: theme.portraitProfileBadgeColor
|
||||
|
||||
readonly property int headerSize: 50
|
||||
readonly property int usernameSize: 30
|
||||
readonly property int tabSize: 25
|
||||
readonly property int chatSize: 20
|
||||
readonly property int secondaryTextSize: 20 // address
|
||||
readonly property int chatMetaTextSize: 15
|
||||
readonly property int badgeTextSize: 12
|
||||
|
||||
readonly property int sidePaneMinSize: 700
|
||||
readonly property int doublePaneMinSize: 1000
|
||||
|
||||
property ThemeType theme: CwtchLight { }
|
||||
}
|
|
@ -6,7 +6,23 @@ QtObject {
|
|||
|
||||
property color mainTextColor: "red"
|
||||
property color defaultButtonColor: "red"
|
||||
property color defaultButtonActiveColor: "red"
|
||||
property color defaultButtonTextColor: "red"
|
||||
|
||||
property color portraitOnlineBorderColor: "red"
|
||||
property color portraitOnlineBackgroundColor: "red"
|
||||
property color portraitOnlineTextColor: "red"
|
||||
property color portraitConnectingBorderColor: "red"
|
||||
property color portraitConnectingBackgroundColor: "red"
|
||||
property color portraitConnectingTextColor: "red"
|
||||
property color portraitOfflineBorderColor: "red"
|
||||
property color portraitOfflineBackgroundColor: "red"
|
||||
property color portraitOfflineTextColor: "red"
|
||||
|
||||
property color portraitContactBadgeColor: "red"
|
||||
property color portraitContactBadgeTextColor: "red"
|
||||
property color portraitProfileBadgeColor: "red"
|
||||
|
||||
// ... more to come
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import QtGraphicalEffects 1.0
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Controls.Material 2.0
|
||||
import QtQuick.Layouts 1.3
|
||||
import CustomQmlTypes 1.0
|
||||
import "../theme"
|
||||
|
||||
Rectangle {
|
||||
width: parent.width * 0.25
|
||||
height: width
|
||||
radius: width/2
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: parent.width * 0.15
|
||||
property alias content: container.children
|
||||
|
||||
Column {
|
||||
id: container
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
}
|
|
@ -15,7 +15,7 @@ Rectangle {
|
|||
height: 20 * gcd.themeScale
|
||||
Layout.minimumHeight: height
|
||||
Layout.maximumHeight: height
|
||||
color: mousedown ? Qt.lighter(Theme.defaultButtonColor, 1.5) : Theme.defaultButtonColor
|
||||
color: mousedown ? Theme.defaultButtonActiveColor : Theme.defaultButtonColor
|
||||
border.color: Theme.defaultButtonColor
|
||||
border.width: 1
|
||||
radius: (height / 2.0)
|
||||
|
|
|
@ -47,7 +47,7 @@ ColumnLayout {
|
|||
Connections { // ADD/REMOVE CONTACT ENTRIES
|
||||
target: gcd
|
||||
|
||||
onAddContact: function(handle, displayName, image, server, badge, status, blocked, loading, lastMsgTs) {
|
||||
onAddContact: function(handle, displayName, image, badge, status, blocked, loading, lastMsgTs) {
|
||||
|
||||
for (var i = 0; i < contactsModel.count; i++) {
|
||||
if (contactsModel.get(i)["_handle"] == handle) {
|
||||
|
@ -67,7 +67,6 @@ ColumnLayout {
|
|||
"_handle": handle,
|
||||
"_displayName": displayName + (blocked ? " (blocked)" : "" ),
|
||||
"_image": image,
|
||||
"_server": server,
|
||||
"_badge": badge,
|
||||
"_status": status,
|
||||
"_blocked": blocked,
|
||||
|
@ -95,7 +94,6 @@ ColumnLayout {
|
|||
if(contactsModel.get(i)["_handle"] == handle) {
|
||||
var contact = contactsModel.get(i)
|
||||
contact["_lastMsgTs"] = ts
|
||||
console.log("Found at " + i + " contact: " + contact)
|
||||
contactsModel.move(i, 0, 1)
|
||||
}
|
||||
}
|
||||
|
@ -116,12 +114,10 @@ ColumnLayout {
|
|||
handle: _handle
|
||||
displayName: _displayName
|
||||
image: _image
|
||||
server: _server
|
||||
badge: _badge
|
||||
status: _status
|
||||
blocked: _blocked
|
||||
loading: _loading
|
||||
type: "contact"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
import QtGraphicalEffects 1.0
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Controls.Material 2.0
|
||||
import QtQuick.Layouts 1.3
|
||||
import CustomQmlTypes 1.0
|
||||
|
||||
Item {
|
||||
id: imgProfile
|
||||
implicitWidth: baseWidth
|
||||
implicitHeight: baseWidth
|
||||
anchors.margins: 5
|
||||
|
||||
property string handle
|
||||
property string source
|
||||
property int status
|
||||
property bool isGroup
|
||||
property bool showStatus
|
||||
property bool highlight
|
||||
property bool button
|
||||
property real logscale: 4 * Math.log10(gcd.themeScale + 1)
|
||||
property int baseWidth: 48 * logscale
|
||||
|
||||
Rectangle {
|
||||
id: mainImage
|
||||
width: baseWidth
|
||||
height: baseWidth
|
||||
color: "#350052" //: "#FFFFFF" //windowItem.cwtch_dark_color: "#FFFFFF"
|
||||
radius: width / 2
|
||||
|
||||
Rectangle {
|
||||
width: highlight ? baseWidth - 4 : baseWidth
|
||||
height: highlight ? baseWidth - 4 : baseWidth
|
||||
color: "#350052" //: "#FFFFFF" // windowItem.cwtch_dark_color: "#FFFFFF"
|
||||
radius: width / 2
|
||||
anchors.centerIn:parent
|
||||
|
||||
|
||||
Image { // PROFILE IMAGE
|
||||
id: img
|
||||
source: gcd.assetPath + imgProfile.source
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectFit
|
||||
visible: false
|
||||
}
|
||||
|
||||
Image { // CIRCLE MASK
|
||||
id: mask
|
||||
fillMode: Image.PreserveAspectFit
|
||||
visible: false
|
||||
source: "qrc:/qml/images/extra/clipcircle.png"
|
||||
}
|
||||
|
||||
OpacityMask {
|
||||
anchors.fill: img
|
||||
source: img
|
||||
maskSource: mask
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle { // PRESENCE INDICATOR
|
||||
visible: showStatus
|
||||
color: "#FFFFFF"
|
||||
width: 8 * logscale
|
||||
height: 8 * logscale
|
||||
radius: 2 * logscale
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: 4 * logscale
|
||||
|
||||
|
||||
Rectangle { //-2:WtfCodeError,-1:Error,0:Disconnected,1:Connecting,2:Connected,3:Authenticated,4:Synced,5:Failed,6:Killed
|
||||
color: status == 4 ? "green" : status == 3 ? "green" : status == -1 ? "blue" : status == 1 ? "orange" : status == 2 ? "orange" : "red"
|
||||
width: 5 * logscale
|
||||
height: 5 * logscale
|
||||
radius: 2 * logscale
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: 1.5 * logscale
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -6,255 +6,97 @@ import QtQuick.Layouts 1.3
|
|||
import CustomQmlTypes 1.0
|
||||
import "../styles"
|
||||
import "../widgets" as Widgets
|
||||
import "../theme"
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
PortraitRow {
|
||||
|
||||
Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
|
||||
id: crItem
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 48 * logscale + 3
|
||||
implicitHeight: height
|
||||
|
||||
property real logscale: 4 * Math.log10(gcd.themeScale + 1)
|
||||
property alias displayName: cn.text
|
||||
property alias image: imgProfile.source
|
||||
property string handle
|
||||
property int badge
|
||||
property bool isActive
|
||||
property bool isHover
|
||||
property bool background: true
|
||||
property string type // profile or contact or button
|
||||
property string tag // profile version/type
|
||||
|
||||
// Profile
|
||||
property bool defaultPassword
|
||||
|
||||
// Contact
|
||||
property bool blocked
|
||||
property int status: 0
|
||||
property int badge
|
||||
property bool loading
|
||||
property alias status: imgProfile.status
|
||||
property string server
|
||||
|
||||
badgeColor: Theme.portraitContactBadgeColor
|
||||
badgeVisible: badge > 0
|
||||
|
||||
Rectangle { // CONTACT ENTRY BACKGROUND COLOR
|
||||
id: crRect
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 48 * logscale + 3
|
||||
width: parent.width
|
||||
color: background ? (isHover ? "#D2D2F3" : (isActive ? "#D2D2F3" : "#D2C0DD")) : windowItem.cwtch_background_color
|
||||
|
||||
ContactPicture {
|
||||
id: imgProfile
|
||||
showStatus: type == "contact"
|
||||
button: type == "button"
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
|
||||
anchors.left: imgProfile.right
|
||||
anchors.right: loading ? loadingProgress.left : rectUnread.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
|
||||
Label { // CONTACT NAME
|
||||
id: cn
|
||||
leftPadding: 10
|
||||
rightPadding: 10
|
||||
//wrapMode: Text.WordWrap
|
||||
font.pixelSize: 16 * gcd.themeScale
|
||||
font.strikeout: blocked
|
||||
textFormat: Text.PlainText
|
||||
//fontSizeMode: Text.HorizontalFit
|
||||
elide: Text.ElideRight
|
||||
color: "#000000"
|
||||
}
|
||||
|
||||
Label { // Onion
|
||||
id: onion
|
||||
text: handle
|
||||
leftPadding: 10
|
||||
rightPadding: 10
|
||||
font.pixelSize: 10 * gcd.themeScale
|
||||
font.strikeout: blocked
|
||||
textFormat: Text.PlainText
|
||||
//fontSizeMode: Text.HorizontalFit
|
||||
elide: Text.ElideRight
|
||||
color: "#000000"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle { // UNREAD MESSAGES?
|
||||
id: rectUnread
|
||||
height: txtmetric.tightBoundingRect.height + 8 * gcd.themeScale
|
||||
width: txtmetric.tightBoundingRect.width + 8 * gcd.themeScale
|
||||
radius: 8 * gcd.themeScale
|
||||
color: "#4B3557"
|
||||
visible: badge != 0
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 9 * gcd.themeScale
|
||||
|
||||
Label {
|
||||
id: lblUnread
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: "#FFFFFF"
|
||||
font.pixelSize: 12 * gcd.themeScale
|
||||
text: txtmetric.text
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: txtmetric
|
||||
text: badge
|
||||
font: lblUnread.font
|
||||
}
|
||||
}
|
||||
|
||||
// Profile
|
||||
|
||||
Image {// Profle Type
|
||||
id: profiletype
|
||||
|
||||
source: tag == "v1-userPassword" ? gcd.assetPath + "/fontawesome/solid/lock.svg" : gcd.assetPath + "/fontawesome/solid/lock-open.svg"
|
||||
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: 1 * gcd.themeScale
|
||||
anchors.rightMargin: (20 * gcd.themeScale) + parent.height
|
||||
height: parent.height * 0.5
|
||||
width: height
|
||||
|
||||
visible: type == "profile"
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Contact
|
||||
ProgressBar { // LOADING ?
|
||||
id: loadingProgress
|
||||
property bool running
|
||||
running: loading
|
||||
visible: loading
|
||||
|
||||
anchors.right: rectUnread.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: 1 * gcd.themeScale
|
||||
anchors.rightMargin: 1 * gcd.themeScale
|
||||
|
||||
|
||||
height: cn.height/2
|
||||
width: 100 * gcd.themeScale
|
||||
|
||||
|
||||
|
||||
indeterminate: true
|
||||
|
||||
style: ProgressBarStyle {
|
||||
progress: CwtchProgress { running: loadingProgress.running}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea { // ONCLICK: LOAD CONVERSATION WITH THIS CONTACT
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
onClicked: {
|
||||
if (type == "contact") {
|
||||
if (displayName != "me") {
|
||||
gcd.broadcast("ResetMessagePane")
|
||||
isActive = true
|
||||
theStack.pane = theStack.messagePane
|
||||
gcd.loadMessagesPane(handle)
|
||||
badge = 0
|
||||
if (handle.length == 32) {
|
||||
gcd.requestGroupSettings(handle)
|
||||
}
|
||||
}
|
||||
} else if (type == "profile") {
|
||||
gcd.broadcast("ResetMessagePane")
|
||||
gcd.broadcast("ResetProfile")
|
||||
gcd.selectedProfile = handle
|
||||
gcd.loadProfile(handle)
|
||||
parentStack.pane = parentStack.profilePane
|
||||
} else if (type == "button") { // Add profile button
|
||||
profileAddEditPane.reset()
|
||||
parentStack.pane = parentStack.addEditProfilePane
|
||||
}
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
isHover = true
|
||||
}
|
||||
|
||||
onExited: {
|
||||
isHover = false
|
||||
}
|
||||
}
|
||||
|
||||
Widgets.Button {// Edit BUTTON
|
||||
id: btnEdit
|
||||
icon: "solid/user-edit"
|
||||
|
||||
anchors.right: parent.right
|
||||
|
||||
//rectUnread.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: 1 * gcd.themeScale
|
||||
anchors.rightMargin: 20 * gcd.themeScale
|
||||
height: parent.height * 0.75
|
||||
|
||||
visible: type == "profile"
|
||||
|
||||
|
||||
onClicked: {
|
||||
profileAddEditPane.load(handle, displayName, tag)
|
||||
parentStack.pane = parentStack.addEditProfilePane
|
||||
}
|
||||
badgeContent: Label {
|
||||
id: lblUnread
|
||||
color: Theme.portraitContactBadgeTextColor
|
||||
font.pixelSize: Theme.badgeTextSize * gcd.themeScale
|
||||
font.weight: Font.Bold
|
||||
text: badge > 99 ? "99+" : badge
|
||||
}
|
||||
|
||||
Connections { // UPDATE UNREAD MESSAGES COUNTER
|
||||
target: gcd
|
||||
ProgressBar { // LOADING ?
|
||||
id: loadingProgress
|
||||
property bool running
|
||||
running: loading
|
||||
visible: loading
|
||||
|
||||
onResetMessagePane: function() {
|
||||
isActive = false
|
||||
}
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: 1 * gcd.themeScale
|
||||
anchors.rightMargin: 25 * gcd.themeScale
|
||||
|
||||
onUpdateContactStatus: function(_handle, _status, _loading) {
|
||||
if (handle == _handle) {
|
||||
status = _status
|
||||
loadingProgress.visible = loadingProgress.running = loading = _loading
|
||||
height: parent.height * .1
|
||||
width: 100 * gcd.themeScale
|
||||
|
||||
indeterminate: true
|
||||
|
||||
style: ProgressBarStyle {
|
||||
progress: CwtchProgress { running: loadingProgress.running}
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: function(handle) {
|
||||
gcd.broadcast("ResetMessagePane")
|
||||
isActive = true
|
||||
theStack.pane = theStack.messagePane
|
||||
gcd.loadMessagesPane(handle)
|
||||
badge = 0
|
||||
if (handle.length == 32) {
|
||||
gcd.requestGroupSettings(handle)
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: { setColors(status) }
|
||||
|
||||
onStatusChanged: { setColors(status) }
|
||||
|
||||
function setColors(status) {
|
||||
//-2:WtfCodeError,-1:Error,0:Disconnected,1:Connecting,2:Connected,3:Authenticated,4:Synced,5:Failed,6:Killed
|
||||
if (status == 4 || status == 3) {
|
||||
portraitBorderColor = Theme.portraitOnlineBorderColor
|
||||
portraitColor = Theme.portraitOnlineBackgroundColor
|
||||
nameColor = Theme.portraitOnlineTextColor
|
||||
onionColor = Theme.portraitOnlineTextColor
|
||||
} else if (status == 2 || status == 1) {
|
||||
portraitBorderColor = Theme.portraitConnectingBorderColor
|
||||
portraitColor = Theme.portraitConnectingBackgroundColor
|
||||
nameColor = Theme.portraitConnectingTextColor
|
||||
onionColor = Theme.portraitConnectingTextColor
|
||||
} else {
|
||||
portraitBorderColor = Theme.portraitOfflineBorderColor
|
||||
portraitColor = Theme.portraitOfflineBackgroundColor
|
||||
nameColor = Theme.portraitOfflineTextColor
|
||||
onionColor = Theme.portraitOfflineTextColor
|
||||
}
|
||||
}
|
||||
|
||||
Connections { // UPDATE UNREAD MESSAGES COUNTER
|
||||
target: gcd
|
||||
|
||||
onUpdateContactStatus: function(_handle, _status, _loading) {
|
||||
if (handle == _handle) {
|
||||
status = _status
|
||||
loadingProgress.visible = loadingProgress.running = loading = _loading
|
||||
}
|
||||
}
|
||||
|
||||
onIncContactUnreadCount: function(handle) {
|
||||
if (handle == _handle && gcd.selectedConversation != handle) {
|
||||
badge++
|
||||
}
|
||||
}
|
||||
|
||||
onUpdateContactBlocked: function(_handle, _blocked) {
|
||||
if (handle == _handle) {
|
||||
blocked = _blocked
|
||||
}
|
||||
}
|
||||
|
||||
onUpdateContactDisplayName: function(_handle, _displayName) {
|
||||
if (handle == _handle) {
|
||||
displayName = _displayName + (_blocked == true ? " (blocked)" : "")
|
||||
}
|
||||
}
|
||||
|
||||
onUpdateContactPicture: function(_handle, _image) {
|
||||
if (handle == _handle) {
|
||||
image = _image
|
||||
}
|
||||
}
|
||||
|
||||
onIncContactUnreadCount: function(handle) {
|
||||
if (handle == _handle && gcd.selectedConversation != handle) {
|
||||
badge++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,7 +23,6 @@ Item {
|
|||
property bool ackd
|
||||
property alias timestamp: ts.text
|
||||
property alias image: imgProfile.source
|
||||
property alias status: imgProfile.status
|
||||
property string error
|
||||
|
||||
Connections {
|
||||
|
@ -43,13 +42,13 @@ Item {
|
|||
}
|
||||
|
||||
|
||||
ContactPicture {
|
||||
Portrait {
|
||||
id: imgProfile
|
||||
anchors.left: parent.left
|
||||
handle: root.from
|
||||
visible: !fromMe
|
||||
showStatus: false
|
||||
highlight: ima.containsMouse
|
||||
//showStatus: false
|
||||
//highlight: ima.containsMouse
|
||||
|
||||
ToolTip.visible: ima.containsMouse
|
||||
//: Click to DM
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
import QtGraphicalEffects 1.0
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Controls.Material 2.0
|
||||
import QtQuick.Layouts 1.3
|
||||
import CustomQmlTypes 1.0
|
||||
import "../theme"
|
||||
|
||||
Item {
|
||||
id: imgProfile
|
||||
implicitWidth: baseWidth
|
||||
implicitHeight: baseWidth
|
||||
|
||||
property string handle
|
||||
property string source
|
||||
property alias badgeColor: badge.color
|
||||
|
||||
property real logscale: 4 * Math.log10(gcd.themeScale + 1)
|
||||
property int baseWidth: parent.height
|
||||
|
||||
property alias portraitBorderColor: mainImage.color
|
||||
property alias portraitColor: imageInner.color
|
||||
property alias badgeVisible: badge.visible
|
||||
property alias badgeContent: badge.content
|
||||
|
||||
Rectangle {
|
||||
id: mainImage
|
||||
width: baseWidth * 0.8
|
||||
height: width
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: Theme.portraitOfflineBorderColor
|
||||
radius: width / 2
|
||||
|
||||
Rectangle {
|
||||
id: imageInner
|
||||
width: parent.width - 4
|
||||
height: width
|
||||
color: Theme.portraitOfflineBorderColor
|
||||
radius: width / 2
|
||||
anchors.centerIn:parent
|
||||
|
||||
Image { // PROFILE IMAGE
|
||||
id: img
|
||||
source: gcd.assetPath + imgProfile.source
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectFit
|
||||
visible: false
|
||||
}
|
||||
|
||||
Image { // CIRCLE MASK
|
||||
id: mask
|
||||
fillMode: Image.PreserveAspectFit
|
||||
visible: false
|
||||
source: "qrc:/qml/images/extra/clipcircle.png"
|
||||
}
|
||||
|
||||
OpacityMask {
|
||||
anchors.fill: img
|
||||
source: img
|
||||
maskSource: mask
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Badge {
|
||||
id: badge
|
||||
}
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
import QtGraphicalEffects 1.0
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Controls.Material 2.0
|
||||
import QtQuick.Layouts 1.3
|
||||
import CustomQmlTypes 1.0
|
||||
import "../styles"
|
||||
import "../widgets" as Widgets
|
||||
import "../theme"
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
|
||||
id: crItem
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: 78 * logscale + 3
|
||||
implicitHeight: 78 * logscale + 3 //height
|
||||
|
||||
property real logscale: 4 * Math.log10(gcd.themeScale + 1)
|
||||
property string displayName //: nameTxtmetric.text
|
||||
property alias image: portrait.source
|
||||
property string handle
|
||||
property bool isActive
|
||||
property bool isHover
|
||||
property string tag // profile version/type
|
||||
|
||||
property alias badgeColor: portrait.badgeColor
|
||||
property alias portraitBorderColor: portrait.portraitBorderColor
|
||||
property alias portraitColor: portrait.portraitColor
|
||||
property alias nameColor: cn.color
|
||||
property alias onionColor: onion.color
|
||||
property alias badgeVisible: portrait.badgeVisible
|
||||
property alias badgeContent: portrait.badgeContent
|
||||
|
||||
|
||||
// TODO: should be in ContactRow
|
||||
property bool blocked
|
||||
|
||||
signal clicked(string handle)
|
||||
|
||||
Rectangle { // CONTACT ENTRY BACKGROUND COLOR
|
||||
id: crRect
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: crItem.height
|
||||
width: parent.width
|
||||
color: isHover ? Theme.backgroundPaneColor : (isActive ? Theme.backgroundPaneColor : Theme.backgroundMainColor)
|
||||
|
||||
Portrait {
|
||||
id: portrait
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 25 * logscale
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
|
||||
anchors.left: portrait.right
|
||||
anchors.leftMargin: 4 * logscale
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Label { // CONTACT NAME
|
||||
id: cn
|
||||
leftPadding: 10
|
||||
rightPadding: 10
|
||||
//wrapMode: Text.WordWrap
|
||||
font.pixelSize: Theme.usernameSize * gcd.themeScale
|
||||
font.weight: Font.Bold
|
||||
font.strikeout: blocked
|
||||
elide: Text.ElideRight
|
||||
text: nameTxtmetric.text
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: nameTxtmetric
|
||||
text: displayName
|
||||
font: cn.font
|
||||
}
|
||||
|
||||
|
||||
Label { // Onion
|
||||
id: onion
|
||||
text: onionTxtmetric.text
|
||||
leftPadding: 10
|
||||
rightPadding: 10
|
||||
font.pixelSize: Theme.secondaryTextSize * gcd.themeScale
|
||||
font.strikeout: blocked
|
||||
textFormat: Text.PlainText
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: onionTxtmetric
|
||||
text: handle
|
||||
font: onion.font
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onWidthChanged: {
|
||||
nameTxtmetric.text = displayName
|
||||
onionTxtmetric.text = handle
|
||||
var i = 2
|
||||
var maxWidth = Math.max(200, width - portrait.width - (50 * logscale))
|
||||
|
||||
while (nameTxtmetric.width > maxWidth) {
|
||||
nameTxtmetric.text = displayName.slice(0, displayName.length - (i * 3)) + "..."
|
||||
i++
|
||||
}
|
||||
i = 2
|
||||
while (onionTxtmetric.width > maxWidth) {
|
||||
onionTxtmetric.text = handle.slice(0, handle.length - (i * 3)) + "..."
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea { // Full row mouse area triggering onClick
|
||||
id: buttonMA
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
onClicked: { crItem.clicked(crItem.handle) }
|
||||
|
||||
onEntered: {
|
||||
isHover = true
|
||||
}
|
||||
|
||||
onExited: {
|
||||
isHover = false
|
||||
}
|
||||
}
|
||||
|
||||
Connections { // UPDATE UNREAD MESSAGES COUNTER
|
||||
target: gcd
|
||||
|
||||
onResetMessagePane: function() {
|
||||
isActive = false
|
||||
}
|
||||
|
||||
onUpdateContactBlocked: function(_handle, _blocked) {
|
||||
if (handle == _handle) {
|
||||
blocked = _blocked
|
||||
}
|
||||
}
|
||||
|
||||
onUpdateContactDisplayName: function(_handle, _displayName) {
|
||||
if (handle == _handle) {
|
||||
displayName = _displayName + (_blocked == true ? " (blocked)" : "")
|
||||
}
|
||||
}
|
||||
|
||||
onUpdateContactPicture: function(_handle, _image) {
|
||||
if (handle == _handle) {
|
||||
image = _image
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,11 +3,11 @@ import QtQuick 2.7
|
|||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Controls.Material 2.0
|
||||
import QtQuick.Layouts 1.3
|
||||
import "../theme"
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
||||
|
@ -44,7 +44,6 @@ ColumnLayout {
|
|||
onAddProfile: function(handle, displayName, image, tag) {
|
||||
|
||||
// don't add duplicates
|
||||
console.log("ProfileList onAddProfile for: " + handle)
|
||||
for (var i = 0; i < profilesModel.count; i++) {
|
||||
if (profilesModel.get(i)["_handle"] == handle) {
|
||||
return
|
||||
|
@ -52,8 +51,8 @@ ColumnLayout {
|
|||
}
|
||||
|
||||
// find index for insert (sort by onion)
|
||||
var index = profilesModel.count-1
|
||||
for (var i = 0; i < profilesModel.count-1; i++) {
|
||||
var index = profilesModel.count
|
||||
for (var i = 0; i < profilesModel.count; i++) {
|
||||
if (profilesModel.get(i)["_handle"] > handle) {
|
||||
index = i
|
||||
break
|
||||
|
@ -62,11 +61,11 @@ ColumnLayout {
|
|||
|
||||
profilesModel.insert(index,
|
||||
{
|
||||
"_handle": handle,
|
||||
"_displayName": displayName,
|
||||
"_image": image,
|
||||
"_type": "profile",
|
||||
"_tag": tag
|
||||
_handle: handle,
|
||||
_displayName: displayName,
|
||||
_image: image,
|
||||
_tag: tag,
|
||||
_status: 4,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -83,43 +82,41 @@ ColumnLayout {
|
|||
|
||||
onResetProfileList: function() {
|
||||
profilesModel.clear()
|
||||
profilesModel.append({
|
||||
_handle: "",
|
||||
_displayName: qsTr("add-new-profile-btn"),
|
||||
_image: "/fontawesome/solid/user-plus.svg",
|
||||
_type: "button",
|
||||
_tag: ","
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
ListModel { // Profile OBJECTS ARE STORED HERE ...
|
||||
id: profilesModel
|
||||
|
||||
ListElement {
|
||||
_handle: ""
|
||||
_displayName: qsTr("add-new-profile-btn")
|
||||
_image: "/fontawesome/solid/user-plus.svg"
|
||||
_type: "button"
|
||||
_tag: ""
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: profileList
|
||||
model: profilesModel // ... AND DISPLAYED HERE
|
||||
delegate: ContactRow {
|
||||
delegate: ProfileRow {
|
||||
handle: _handle
|
||||
displayName: _displayName
|
||||
image: _image
|
||||
server: ""
|
||||
badge: 0
|
||||
status: 0
|
||||
blocked: false
|
||||
loading: false
|
||||
type: _type
|
||||
tag: _tag
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PortraitRow {
|
||||
handle: ""
|
||||
displayName: qsTr("add-new-profile-btn")
|
||||
image: "/fontawesome/regular/user.svg"
|
||||
tag: ""
|
||||
portraitBorderColor: Theme.defaultButtonColor
|
||||
portraitColor: Theme.defaultButtonColor
|
||||
badgeVisible: true
|
||||
badgeContent: Image {
|
||||
source: gcd.assetPath + "/fontawesome/solid/plus.svg"
|
||||
height: Theme.badgeTextSize * gcd.themeScale
|
||||
width: height
|
||||
}
|
||||
badgeColor: Theme.portraitOnlineBorderColor
|
||||
onClicked: function(handle) { profileAddEditPane.reset(); parentStack.pane = parentStack.addEditProfilePane }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
import QtGraphicalEffects 1.0
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Controls.Material 2.0
|
||||
import QtQuick.Layouts 1.3
|
||||
import CustomQmlTypes 1.0
|
||||
import "../styles"
|
||||
import "../widgets" as Widgets
|
||||
import "../theme"
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
PortraitRow {
|
||||
|
||||
badgeColor: Theme.portraitProfileBadgeColor
|
||||
|
||||
portraitBorderColor: Theme.portraitOnlineBorderColor
|
||||
portraitColor: Theme.portraitOnlineBackgroundColor
|
||||
nameColor: Theme.portraitOnlineTextColor
|
||||
onionColor: Theme.portraitOnlineTextColor
|
||||
|
||||
badgeContent: Image {// Profle Type
|
||||
id: profiletype
|
||||
source: tag == "v1-userPassword" ? gcd.assetPath + "/fontawesome/solid/lock.svg" : gcd.assetPath + "/fontawesome/solid/lock-open.svg"
|
||||
height: Theme.badgeTextSize * gcd.themeScale
|
||||
width: height
|
||||
}
|
||||
|
||||
Widgets.Button {// Edit BUTTON
|
||||
id: btnEdit
|
||||
icon: "solid/user-edit"
|
||||
|
||||
anchors.right: parent.right
|
||||
|
||||
//rectUnread.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: 1 * gcd.themeScale
|
||||
anchors.rightMargin: 20 * gcd.themeScale
|
||||
height: parent.height * 0.75
|
||||
|
||||
|
||||
|
||||
onClicked: {
|
||||
profileAddEditPane.load(handle, displayName, tag)
|
||||
parentStack.pane = parentStack.addEditProfilePane
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: function openClick(handle) {
|
||||
gcd.broadcast("ResetMessagePane");
|
||||
gcd.broadcast("ResetProfile");
|
||||
gcd.selectedProfile = handle
|
||||
gcd.loadProfile(handle)
|
||||
parentStack.pane = parentStack.profilePane
|
||||
}
|
||||
}
|
Reference in New Issue