Messages redesign: messages now follow design; rework timestamp workflow; inject dates into message pane

This commit is contained in:
Dan Ballard 2020-07-25 09:47:19 -07:00
parent f91f932c00
commit af3c593228
13 changed files with 190 additions and 109 deletions

4
go.mod
View File

@ -4,11 +4,11 @@ go 1.12
require ( require (
cwtch.im/cwtch v0.3.16 cwtch.im/cwtch v0.3.16
git.openprivacy.ca/openprivacy/connectivity v1.2.0 git.openprivacy.ca/openprivacy/connectivity v1.1.4
git.openprivacy.ca/openprivacy/log v1.0.1 git.openprivacy.ca/openprivacy/log v1.0.1
github.com/gopherjs/gopherjs v0.0.0-20200209183636-89e6cbcd0b6d // indirect github.com/gopherjs/gopherjs v0.0.0-20200209183636-89e6cbcd0b6d // indirect
github.com/therecipe/qt v0.0.0-20200126204426-5074eb6d8c41 github.com/therecipe/qt v0.0.0-20200126204426-5074eb6d8c41
github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200126204426-5074eb6d8c41 // indirect github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200126204426-5074eb6d8c41 // indirect
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20200126204426-5074eb6d8c41 // indirect github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20200126204426-5074eb6d8c41 // indirect
golang.org/x/crypto v0.0.0-20200420104511-884d27f42877 // indirect golang.org/x/crypto v0.0.0-20200420104511-884d27f42877 // indirect
) )

2
go.sum
View File

@ -6,6 +6,8 @@ cwtch.im/cwtch v0.3.14 h1:XL8UbCUyIosdFTD5nSlpvhbQQGFLjvFmd81/SmfBSP8=
cwtch.im/cwtch v0.3.14/go.mod h1:wDmgxWBWak/xvZ5GurdYNOJ8b8eha1MwVdiWsCS/pwI= cwtch.im/cwtch v0.3.14/go.mod h1:wDmgxWBWak/xvZ5GurdYNOJ8b8eha1MwVdiWsCS/pwI=
cwtch.im/cwtch v0.3.15 h1:Z7fFREwXY728q2YmmwgHL357zAobrsWJ2oPkkGwzvo0= cwtch.im/cwtch v0.3.15 h1:Z7fFREwXY728q2YmmwgHL357zAobrsWJ2oPkkGwzvo0=
cwtch.im/cwtch v0.3.15/go.mod h1:iI9q4C3njHFBYQkNEbzMdK6QWPS0Vbkc0FigRHZNTvM= cwtch.im/cwtch v0.3.15/go.mod h1:iI9q4C3njHFBYQkNEbzMdK6QWPS0Vbkc0FigRHZNTvM=
cwtch.im/cwtch v0.3.16 h1:4M5So2zRDjy5byzd3G8ZrA2ZWObfm/oSIRfMBIFdOuI=
cwtch.im/cwtch v0.3.16/go.mod h1:iI9q4C3njHFBYQkNEbzMdK6QWPS0Vbkc0FigRHZNTvM=
cwtch.im/tapir v0.1.15 h1:XSCWOvjmNkzMT2IceFgTBXWGKtYfr3a8o+La1s10OhE= cwtch.im/tapir v0.1.15 h1:XSCWOvjmNkzMT2IceFgTBXWGKtYfr3a8o+La1s10OhE=
cwtch.im/tapir v0.1.15/go.mod h1:HzezugpEx+nZ3LdyDsl0w6n45IJYnOt8uqldkLWmaqs= cwtch.im/tapir v0.1.15/go.mod h1:HzezugpEx+nZ3LdyDsl0w6n45IJYnOt8uqldkLWmaqs=
cwtch.im/tapir v0.1.17 h1:2jVZUe1a88tMI4aJPvRTO4Id3NN3PsM62cT5lntEChk= cwtch.im/tapir v0.1.17 h1:2jVZUe1a88tMI4aJPvRTO4Id3NN3PsM62cT5lntEChk=

View File

@ -1,3 +0,0 @@
package constants
var TIME_FORMAT = "Mon 3:04pm"

View File

@ -62,14 +62,14 @@ type GrandCentralDispatcher struct {
_ func(handle, key, value string) `signal:"UpdateContactAttribute"` _ func(handle, key, value string) `signal:"UpdateContactAttribute"`
// messages pane stuff // messages pane stuff
_ func(handle, from, displayName, message, image string, mID string, fromMe bool, ts string, ackd bool, error bool) `signal:"AppendMessage"` _ func(handle, from, displayName, message, image string, mID string, fromMe bool, ts int64, ackd bool, error bool) `signal:"AppendMessage"`
_ func(handle, from, displayName, message, image string, mID string, fromMe bool, ts string, ackd bool, error bool) `signal:"PrependMessage"` _ func(handle, from, displayName, message, image string, mID string, fromMe bool, ts int64, ackd bool, error bool) `signal:"PrependMessage"`
_ func() `signal:"ClearMessages"` _ func() `signal:"ClearMessages"`
_ func() `signal:"ResetMessagePane"` _ func() `signal:"ResetMessagePane"`
_ func(mID string) `signal:"Acknowledged"` _ func(mID string) `signal:"Acknowledged"`
_ func(title string) `signal:"SetToolbarTitle"` _ func(title string) `signal:"SetToolbarTitle"`
_ func(signature string, err string) `signal:"GroupSendError"` _ func(signature string, err string) `signal:"GroupSendError"`
_ func(loading bool) `signal:"SetLoadingState"` _ func(loading bool) `signal:"SetLoadingState"`
// profile-area stuff // profile-area stuff
_ func(name, onion, image, tag, showBlocked string) `signal:"UpdateMyProfile"` _ func(name, onion, image, tag, showBlocked string) `signal:"UpdateMyProfile"`
@ -113,8 +113,8 @@ type GrandCentralDispatcher struct {
_ func(onion string) `signal:"deleteContact,auto"` _ func(onion string) `signal:"deleteContact,auto"`
_ func() `signal:"allowUnknownPeers,auto"` _ func() `signal:"allowUnknownPeers,auto"`
_ func() `signal:"blockUnknownPeers,auto"` _ func() `signal:"blockUnknownPeers,auto"`
_ func(onion string) `signal:"storeHistoryForPeer,auto"` _ func(onion string) `signal:"storeHistoryForPeer,auto"`
_ func(onion string) `signal:"deleteHistoryForPeer,auto"` _ func(onion string) `signal:"deleteHistoryForPeer,auto"`
_ func() `constructor:"init"` _ func() `constructor:"init"`
} }
@ -283,7 +283,7 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
image, image,
string(tl[i].Signature), string(tl[i].Signature),
tl[i].PeerID == the.Peer.GetOnion(), tl[i].PeerID == the.Peer.GetOnion(),
tl[i].Timestamp.Format(constants.TIME_FORMAT), tl[i].Timestamp.Unix(),
tl[i].Received.Equal(time.Unix(0, 0)) == false, // If the received timestamp is epoch, we have not yet received this message through an active server tl[i].Received.Equal(time.Unix(0, 0)) == false, // If the received timestamp is epoch, we have not yet received this message through an active server
false, false,
) )
@ -322,7 +322,7 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
image, image,
string(messages[i].Signature), string(messages[i].Signature),
fromMe, fromMe,
messages[i].Timestamp.Format(constants.TIME_FORMAT), messages[i].Timestamp.Unix(),
messages[i].Acknowledged, messages[i].Acknowledged,
messages[i].Error != "", messages[i].Error != "",
) )
@ -351,7 +351,7 @@ func (this *GrandCentralDispatcher) requestPeerSettings() {
//blockunkownpeers, _ := the.Peer.GetAttribute(attr.GetPeerScope(constants.BlockUnknownPeersSetting)) //blockunkownpeers, _ := the.Peer.GetAttribute(attr.GetPeerScope(constants.BlockUnknownPeersSetting))
// Whether Cwtch should save the history of the peer // Whether Cwtch should save the history of the peer
saveHistory,exists := contact.GetAttribute(event.SaveHistoryKey) saveHistory, exists := contact.GetAttribute(event.SaveHistoryKey)
if !exists { if !exists {
saveHistory = event.DeleteHistoryDefault saveHistory = event.DeleteHistoryDefault
} }

View File

@ -285,10 +285,10 @@ func (this *manager) AddMessage(handle string, from string, message string, from
updateLastReadTime(handle) updateLastReadTime(handle)
// If the message is not from the user then add it, otherwise, just acknowledge. // If the message is not from the user then add it, otherwise, just acknowledge.
if !fromMe { if !fromMe {
this.gcd.AppendMessage(handle, from, nick, message, image, messageID, fromMe, timestamp.Format(constants.TIME_FORMAT), false, false) this.gcd.AppendMessage(handle, from, nick, message, image, messageID, fromMe, timestamp.Unix(), false, false)
} else { } else {
if !Acknowledged { if !Acknowledged {
this.gcd.AppendMessage(handle, from, nick, message, image, messageID, fromMe, timestamp.Format(constants.TIME_FORMAT), false, false) this.gcd.AppendMessage(handle, from, nick, message, image, messageID, fromMe, timestamp.Unix(), false, false)
} else { } else {
this.gcd.Acknowledged(messageID) this.gcd.Acknowledged(messageID)
} }

View File

@ -204,8 +204,13 @@ ApplicationWindow {
Item { anchors.fill: parent } // empty Item { anchors.fill: parent } // empty
OverlayPane { // messagePane Rectangle {
anchors.fill: parent color: Theme.backgroundMainColor
Layout.fillWidth: true
Layout.fillHeight: true
OverlayPane { // messagePane
anchors.fill: parent
}
} }
@ -242,13 +247,17 @@ ApplicationWindow {
function updateToolbar() { function updateToolbar() {
toolbar.hideTitle()
toolbar.rightMenuVisible = false
if (currentIndex == splashPane) { if (currentIndex == splashPane) {
toolbar.hideTitle()
toolbar.rightMenuVisible = false
toolbar.visible = false toolbar.visible = false
} else { } else {
toolbar.visible = true toolbar.visible = true
if (currentIndex == managementPane) { if (currentIndex == managementPane) {
toolbar.hideTitle()
toolbar.rightMenuVisible = false
toolbar.color = Theme.backgroundMainColor toolbar.color = Theme.backgroundMainColor
toolbar.leftMenuVisible = true toolbar.leftMenuVisible = true
toolbar.backVisible = false toolbar.backVisible = false
@ -257,6 +266,8 @@ ApplicationWindow {
toolbar.backVisible = true toolbar.backVisible = true
if (currentIndex == profilePane && theStack.currentIndex == theStack.emptyPane) { if (currentIndex == profilePane && theStack.currentIndex == theStack.emptyPane) {
toolbar.hideTitle()
toolbar.rightMenuVisible = false
toolbar.color = Theme.backgroundMainColor toolbar.color = Theme.backgroundMainColor
} else { } else {
toolbar.color = Theme.backgroundPaneColor toolbar.color = Theme.backgroundPaneColor

View File

@ -140,7 +140,7 @@ ColumnLayout {
} }
Text { Text {
id: texttitle id: texttitle
text: '<b>' + Utils.htmlEscaped(title) + '</b> by ' + from + "<br/>" + timestamp text: '<b>' + Utils.htmlEscaped(title) + '</b> by ' + from + "<br/>" + Qt.formatDateTime(new Date(timestamp*1000), "MMMM d, h:mm ap")
leftPadding: 10 leftPadding: 10
topPadding: 5 topPadding: 5
bottomPadding:5 bottomPadding:5

View File

@ -42,9 +42,12 @@ Item {
timestamp: _ts timestamp: _ts
ackd: _ackd ackd: _ackd
error: _error error: _error
calendarEvent: _handle == "calendar"
// listview doesnt do anchors right
// https://stackoverflow.com/questions/31381997/why-does-anchors-fill-does-not-work-in-a-qml-listviews-delegates-subviews-and/31382307
width: messagesListView.width
} }
Connections { Connections {
target: gcd target: gcd
@ -62,6 +65,28 @@ Item {
} }
if (msg.o != 1) return if (msg.o != 1) return
var date = new Date(ts * 1000);
if (messagesModel.count != 0) {
var prevDate = new Date(messagesModel.get(messagesModel.count-1)["_ts"] * 1000);
if (prevDate.getFullYear() != date.getFullYear()
|| prevDate.getMonth() != date.getMonth()
|| prevDate.getUTCDate() != date.getUTCDate()) {
console.log("DATES DONT MATCH")
messagesModel.append({
"_handle": "calendar",
"_from": "calendar",
"_displayName": "calendar",
"_message": Qt.formatDateTime(date, "MMMM dd, yyyy"),
"_rawMessage": "",
"_image": "",
"_mid": "",
"_fromMe": false,
"_ts": ts,
"_ackd": true,
"_error": "",
})
}
}
messagesModel.append({ messagesModel.append({
"_handle": handle, "_handle": handle,
@ -95,6 +120,28 @@ Item {
} }
if (msg.o != 1) return if (msg.o != 1) return
var date = new Date(ts * 1000);
if (messagesModel.count != 0) {
var prevDate = new Date(messagesModel.get(0)["_ts"] * 1000);
if (prevDate.getFullYear() != date.getFullYear()
|| prevDate.getMonth() != date.getMonth()
|| prevDate.getUTCDate() != date.getUTCDate()) {
messagesModel.insert(0, {
"_handle": "calendar",
"_from": "calendar",
"_displayName": "calendar",
"_message": Qt.formatDateTime(prevDate, "MMMM dd, yyyy"),
"_rawMessage": "",
"_image": "",
"_mid": "",
"_fromMe": false,
"_ts": ts,
"_ackd": true,
"_error": "",
})
}
}
messagesModel.insert(0, { messagesModel.insert(0, {
"_handle": handle, "_handle": handle,

View File

@ -172,7 +172,7 @@ ColumnLayout {
RowLayout { RowLayout {
Text { Text {
id: texttitle id: texttitle
text: '<b>' + Utils.htmlEscaped(title) + '</b> by ' + displayName + "<br/>" + timestamp text: '<b>' + Utils.htmlEscaped(title) + '</b> by ' + displayName + "<br/>" + Qt.formatDateTime(new Date(timestamp*1000), "MMMM d, h:mm ap")
leftPadding: 10 leftPadding: 10
topPadding: 5 topPadding: 5
bottomPadding:5 bottomPadding:5

View File

@ -53,8 +53,7 @@ Opaque.SettingsList { // settingsPane
dropShadowColor: Theme.dropShadowPaneColor dropShadowColor: Theme.dropShadowPaneColor
onClicked: { onClicked: {
gcd.savePeerSettings(txtOnion.text, txtDisplayName.text) gcd.savePeerSettings(txtOnion.text, txtDisplayName.text)
// TODO: broken toolbar.setTitle(txtDisplayName.text)
theStack.title = txtDisplayName.text
theStack.pane = theStack.messagePane theStack.pane = theStack.messagePane
} }
} }

View File

@ -71,7 +71,8 @@ Opaque.SettingsList { // settingsPane
to: gcd.os == "android" ? 4.0 : 1.9 to: gcd.os == "android" ? 4.0 : 1.9
value: gcd.themeScale value: gcd.themeScale
live: false live: false
stepSize: 0.1 snapMode: Slider.SnapAlways
stepSize: 0.25
onValueChanged: { onValueChanged: {
gcd.themeScale = zoomSlider.value gcd.themeScale = zoomSlider.value

View File

@ -6,12 +6,12 @@ import QtQuick.Layouts 1.3
import "../opaque" as Opaque import "../opaque" as Opaque
import "../opaque/controls" as Awesome import "../opaque/controls" as Awesome
import "../opaque/theme"
import "../opaque/fonts"
Item { Rectangle {
id: root id: root
anchors.left: fromMe ? undefined : parent.left
anchors.right: fromMe ? parent.right : undefined
height: Math.max(imgProfile.height, rectMessageBubble.height) height: Math.max(imgProfile.height, rectMessageBubble.height)
property string message property string message
@ -22,9 +22,12 @@ Item {
property string messageID property string messageID
property bool fromMe property bool fromMe
property bool ackd property bool ackd
property alias timestamp: ts.text property int timestamp
property alias image: imgProfile.source property alias image: imgProfile.source
property string error property string error
property bool calendarEvent
property real logscale: 4 * Math.log10(gcd.themeScale + 1)
Connections { Connections {
target: gcd target: gcd
@ -42,15 +45,20 @@ Item {
} }
} }
Opaque.Portrait { Opaque.Portrait {
id: imgProfile id: imgProfile
anchors.left: parent.left anchors.left: parent.left
// TODO: currently unused? anchors.bottom: parent.bottom
//handle: root.from
visible: !fromMe visible: !fromMe && !calendarEvent
//showStatus: false
//highlight: ima.containsMouse
size: fromMe || calendarEvent ? 0 : Theme.contactPortraitSize * 0.5
badgeVisible: false
portraitBorderColor: Theme.portraitOnlineBorderColor
portraitColor: Theme.portraitOnlineBackgroundColor
ToolTip.visible: ima.containsMouse ToolTip.visible: ima.containsMouse
//: Click to DM //: Click to DM
@ -75,95 +83,112 @@ Item {
Rectangle { // THIS IS JUST A PRETTY MESSAGE-HOLDING RECTANGLE Rectangle { // THIS IS JUST A PRETTY MESSAGE-HOLDING RECTANGLE
id: rectMessageBubble id: rectMessageBubble
height: colMessageBubble.height + 8 height: (handle.visible ? handle.height : 0) + (10 * gcd.themeScale) + colMessageBubble.height + 8
width: colMessageBubble.width + 6 width: colMessageBubble.width + 6
color: fromMe ? "#B09CBC" : "#4B3557" color: fromMe ? Theme.messageFromMeBackgroundColor : (calendarEvent ? Theme.messageFromOtherBackgroundColor : Theme.messageFromOtherBackgroundColor)
radius: 5 radius: 15 * logscale
// the console will complain constantly about me setting these anchors, but qt only allows margins if they've been set to something anchors.left: fromMe ? undefined : (calendarEvent ? undefined : imgProfile.right) //parent.left
// a kludge to fix this would be to have spacers before/after and set the widths according to the side they're on ^ea anchors.right: fromMe ? (calendarEvent ? undefined : parent.right) : undefined
anchors.left: fromMe ? undefined : imgProfile.right //parent.left anchors.horizontalCenter: calendarEvent ? parent.horizontalCenter : undefined
anchors.right: fromMe ? parent.right : undefined
anchors.leftMargin: 5 anchors.leftMargin: calendarEvent ? 0 : 5
anchors.rightMargin: 9 anchors.rightMargin: calendarEvent ? 0 : 9
anchors.topMargin: 5 anchors.topMargin: 5
// A sharp corner on the side of the "speaker"
Rectangle {
id: sharpCorner
visible: !calendarEvent
height: parent.radius
width: parent.radius
ColumnLayout { anchors.bottom: rectMessageBubble.bottom
anchors.left: fromMe ? undefined : parent.left
anchors.right: fromMe ? parent.right : undefined
color: parent.color
}
Opaque.EllipsisLabel {
id: handle
visible: !fromMe && !calendarEvent
text: displayName
color: Theme.messageFromOtherTextColor
size: Theme.chatSize * gcd.themeScale
weight: Font.Bold
font.family: Fonts.applicationFontBold.name
font.styleName: "Bold"
leftPadding: 10 * gcd.themeScale
topPadding: 10 * gcd.themeScale
container: lbl
}
onWidthChanged: { handle.textResize() }
Column {
id: colMessageBubble id: colMessageBubble
width: Math.max(lbl.width, ts.width + ack.width + 10)
Column { // combine these into one element or else childrenRect won't play nicely anchors.top: fromMe ? parent.top : (calendarEvent ? parent.top : handle.bottom)
TextEdit { // this is used as a helper to calculate the message box width anchors.topMargin: 10 * gcd.themeScale
id: dummy
visible: false
padding: 6
leftPadding: 10
font.pixelSize: gcd.themeScale * 12
wrapMode: TextEdit.NoWrap
text: lbl.text
textFormat: Text.RichText
}
TextEdit { // this is the actual text display TextEdit { // this is used as a helper to calculate the message box width
id: lbl id: dummy
text: parse(message, 12, true) visible: false
color: "#FFFFFF" padding: 6 * gcd.themeScale
padding: 6 leftPadding: 10 * gcd.themeScale
leftPadding: 10 font.pixelSize: gcd.themeScale * Theme.chatSize
font.pixelSize: gcd.themeScale * 12 wrapMode: TextEdit.NoWrap
selectByMouse: gcd.os != "android" text: lbl.text
readOnly: true textFormat: Text.RichText
width: Math.min(dummy.width, root.parent.width - (imgProfile.visible ? imgProfile.width : 0) - 40)
wrapMode: TextEdit.Wrap
textFormat: Text.RichText
}
} }
RowLayout { TextEdit { // this is the actual text display
id: lbl
text: parse(message, 12, true)
color: fromMe ? Theme.messageFromMeTextColor : Theme.messageFromOtherTextColor
padding: 6 * gcd.themeScale
leftPadding: 10 * gcd.themeScale
font.pixelSize: gcd.themeScale * Theme.chatSize
selectByMouse: gcd.os != "android"
readOnly: true
width: Math.min(dummy.width, root.parent.width - (imgProfile.visible ? imgProfile.width : 0) - 40)
wrapMode: TextEdit.Wrap
textFormat: Text.RichText
}
Row {
id: rowBottom id: rowBottom
anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
visible: !calendarEvent
Opaque.ScalingLabel { // TIMESTAMP
Label { // TIMESTAMP
id: ts id: ts
color: "#FFFFFF" text: Qt.formatDateTime(new Date(root.timestamp*1000), "h:mm ap")
font.pixelSize: 10 * gcd.themeScale color: fromMe ? Theme.messageFromMeTextColor : Theme.messageFromOtherTextColor
anchors.left: parent.left font.pixelSize: Theme.chatMetaTextSize * gcd.themeScale
leftPadding: 10 rightPadding: 10
}
Label { // DISPLAY NAME FOR GROUPS
color: "#FFFFFF"
font.pixelSize: 10 * gcd.themeScale
anchors.right: parent.right
text: displayName.length > 12 ? displayName.substr(0,12) + "..." : displayName
visible: !fromMe
ToolTip.text: from
ToolTip.visible: ma2.containsMouse
ToolTip.delay: 200
MouseArea {
id: ma2
anchors.fill: parent
hoverEnabled: true
}
} }
Image { // ACKNOWLEDGEMENT ICON Image { // ACKNOWLEDGEMENT ICON
id: ack id: ack
anchors.right: parent.right
source: root.error != "" ? gcd.assetPath + "fontawesome/regular/window-close.svg" : (root.ackd ? gcd.assetPath + "fontawesome/regular/check-circle.svg" : gcd.assetPath + "fontawesome/regular/hourglass.svg") source: root.error != "" ? gcd.assetPath + "fontawesome/regular/window-close.svg" : (root.ackd ? gcd.assetPath + "fontawesome/regular/check-circle.svg" : gcd.assetPath + "fontawesome/regular/hourglass.svg")
height: 10 * gcd.themeScale height: Theme.chatMetaTextSize * gcd.themeScale
sourceSize.height: 10 * gcd.themeScale width: Theme.chatMetaTextSize * gcd.themeScale
anchors.bottom: parent.bottom
sourceSize.height: Theme.chatMetaTextSize * gcd.themeScale
visible: fromMe visible: fromMe
ToolTip.visible: ma.containsMouse ToolTip.visible: ma.containsMouse
ToolTip.delay: 200 ToolTip.delay: 200
//: Could not send this message //: Could not send this message
ToolTip.text: root.error != "" ? qsTr("could-not-send-msg-error") + ":" + root.error : (root.ackd ? qsTr("acknowledged-label") : qsTr("pending-label")) ToolTip.text: root.error != "" ? qsTr("could-not-send-msg-error") + ":" + root.error : (root.ackd ? qsTr("acknowledged-label") : qsTr("pending-label"))
MouseArea { MouseArea {
id: ma id: ma
anchors.fill: parent anchors.fill: parent

View File

@ -31,10 +31,10 @@ Item {
function realignProfile() { function realignProfile() {
if (dualPane) { if (dualPane) {
profile.height = 78 * logscale profile.height = Theme.contactPortraitSize * logscale
portrait.baseWidth = 78 * logscale portrait.baseWidth = Theme.contactPortraitSize * logscale
portrait.height = 78 * logscale portrait.height = Theme.contactPortraitSize * logscale
portrait.anchors.horizontalCenter = undefined portrait.anchors.horizontalCenter = undefined
portrait.anchors.left = profile.left portrait.anchors.left = profile.left
@ -49,10 +49,9 @@ Item {
nameCenter.anchors.horizontalCenter = undefined nameCenter.anchors.horizontalCenter = undefined
nameCenter.anchors.left = nameRow.left nameCenter.anchors.left = nameRow.left
} else { } else {
profile.height = (150 * logscale) profile.height = (Theme.contactPortraitSize * 2 * logscale)
portrait.baseWidth = 100 * logscale portrait.size = Theme.contactPortraitSize * 1.5
portrait.height = 100 * logscale
portrait.anchors.left = undefined portrait.anchors.left = undefined
portrait.anchors.leftMargin = undefined portrait.anchors.leftMargin = undefined