Redesign: contact Row and Picture: themeing and modularizing: #276

Merged
sarah merged 2 commits from :03-widgets into master 2020-04-16 22:31:00 +00:00
19 changed files with 519 additions and 389 deletions

View File

@ -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))

View File

@ -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))
}
})
}

View File

@ -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>

View File

@ -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{

View File

@ -106,7 +106,6 @@ ColumnLayout {
displayName: _displayName
image: _image
blocked: false
background: false
}
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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 { }
}

View File

@ -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

24
qml/widgets/Badge.qml Normal file
View File

@ -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
}
}

View File

@ -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)

View File

@ -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"
}
}

View File

@ -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
}
}
}
}

View File

@ -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++
}
}
}
}
}
}

View File

@ -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

68
qml/widgets/Portrait.qml Normal file
View File

@ -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
}
}

160
qml/widgets/PortraitRow.qml Normal file
View File

@ -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
}
}
}
}

View File

@ -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 }
}
}
}
}

View File

@ -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
}
}