Chat overlay messages and message editor redesign #320
2
go.mod
2
go.mod
|
@ -4,7 +4,7 @@ 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
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -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=
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
package constants
|
|
||||||
|
|
||||||
var TIME_FORMAT = "Mon 3:04pm"
|
|
138
go/ui/gcd.go
138
go/ui/gcd.go
|
@ -1,6 +1,8 @@
|
||||||
package ui
|
package ui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
"cwtch.im/cwtch/app"
|
"cwtch.im/cwtch/app"
|
||||||
"cwtch.im/cwtch/event"
|
"cwtch.im/cwtch/event"
|
||||||
"cwtch.im/cwtch/model"
|
"cwtch.im/cwtch/model"
|
||||||
|
@ -8,14 +10,14 @@ import (
|
||||||
"cwtch.im/cwtch/protocol/connections"
|
"cwtch.im/cwtch/protocol/connections"
|
||||||
"cwtch.im/ui/go/constants"
|
"cwtch.im/ui/go/constants"
|
||||||
"github.com/therecipe/qt/qml"
|
"github.com/therecipe/qt/qml"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"cwtch.im/ui/go/the"
|
|
||||||
"encoding/base32"
|
"encoding/base32"
|
||||||
"git.openprivacy.ca/openprivacy/log"
|
|
||||||
"github.com/therecipe/qt/core"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"cwtch.im/ui/go/the"
|
||||||
|
"git.openprivacy.ca/openprivacy/log"
|
||||||
|
"github.com/therecipe/qt/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GrandCentralDispatcher struct {
|
type GrandCentralDispatcher struct {
|
||||||
|
@ -62,14 +64,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"`
|
||||||
|
@ -94,27 +96,27 @@ type GrandCentralDispatcher struct {
|
||||||
_ func(onion, currentPassword, newPassword string, defaultPass bool) `signal:"changePassword,auto""`
|
_ func(onion, currentPassword, newPassword string, defaultPass bool) `signal:"changePassword,auto""`
|
||||||
_ func(key, val string) `signal:"storeSetting,auto"`
|
_ func(key, val string) `signal:"storeSetting,auto"`
|
||||||
// operating a profile
|
// operating a profile
|
||||||
_ func(message string, mid string) `signal:"sendMessage,auto"`
|
_ func(message string) `signal:"sendMessage,auto"`
|
||||||
_ func(onion string, auth string) `signal:"setPeerAuthorization,auto"`
|
_ func(onion string, auth string) `signal:"setPeerAuthorization,auto"`
|
||||||
_ func(onion string) `signal:"loadMessagesPane,auto"`
|
_ func(onion string) `signal:"loadMessagesPane,auto"`
|
||||||
_ func(signal string) `signal:"broadcast,auto"` // convenience relay signal
|
_ func(signal string) `signal:"broadcast,auto"` // convenience relay signal
|
||||||
_ func(str string) `signal:"importString,auto"`
|
_ func(str string) `signal:"importString,auto"`
|
||||||
_ func(str string) `signal:"createContact,auto"`
|
_ func(str string) `signal:"createContact,auto"`
|
||||||
_ func(str string) `signal:"popup,auto"`
|
_ func(str string) `signal:"popup,auto"`
|
||||||
_ func(server, groupName string) `signal:"createGroup,auto"`
|
_ func(server, groupName string) `signal:"createGroup,auto"`
|
||||||
_ func(groupID string) `signal:"leaveGroup,auto"`
|
_ func(groupID string) `signal:"leaveGroup,auto"`
|
||||||
_ func(groupID string) `signal:"acceptGroup,auto"`
|
_ func(groupID string) `signal:"acceptGroup,auto"`
|
||||||
_ func() `signal:"requestSettings,auto"`
|
_ func() `signal:"requestSettings,auto"`
|
||||||
_ func(groupID string) `signal:"requestGroupSettings,auto"`
|
_ func(groupID string) `signal:"requestGroupSettings,auto"`
|
||||||
_ func(groupID, nick string) `signal:"saveGroupSettings,auto"`
|
_ func(groupID, nick string) `signal:"saveGroupSettings,auto"`
|
||||||
_ func() `signal:"requestPeerSettings,auto"`
|
_ func(handle string) `signal:"requestPeerSettings,auto"`
|
||||||
_ func(onion, nick string) `signal:"savePeerSettings,auto"`
|
_ func(onion, nick string) `signal:"savePeerSettings,auto"`
|
||||||
_ func(onion, groupID string) `signal:"inviteToGroup,auto"`
|
_ func(onion, groupID string) `signal:"inviteToGroup,auto"`
|
||||||
_ 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"`
|
||||||
}
|
}
|
||||||
|
@ -197,7 +199,7 @@ func (this *GrandCentralDispatcher) DoIfConversation(conversation string, fn fun
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) sendMessage(message string, mID string) {
|
func (this *GrandCentralDispatcher) sendMessage(message string) {
|
||||||
if len(message) > 65530 {
|
if len(message) > 65530 {
|
||||||
this.InvokePopup("message is too long")
|
this.InvokePopup("message is too long")
|
||||||
return
|
return
|
||||||
|
@ -217,8 +219,7 @@ func (this *GrandCentralDispatcher) sendMessage(message string, mID string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
mID, err := the.Peer.SendMessageToGroupTracked(this.SelectedConversation(), message)
|
||||||
mID, err = the.Peer.SendMessageToGroupTracked(this.SelectedConversation(), message)
|
|
||||||
|
|
||||||
this.GetUiManager(this.selectedProfile()).AddMessage(this.SelectedConversation(), "me", message, true, mID, time.Now(), false)
|
this.GetUiManager(this.selectedProfile()).AddMessage(this.SelectedConversation(), "me", message, true, mID, time.Now(), false)
|
||||||
|
|
||||||
|
@ -228,7 +229,7 @@ func (this *GrandCentralDispatcher) sendMessage(message string, mID string) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
to := this.SelectedConversation()
|
to := this.SelectedConversation()
|
||||||
mID = the.Peer.SendMessageToPeer(to, message)
|
mID := the.Peer.SendMessageToPeer(to, message)
|
||||||
|
|
||||||
this.GetUiManager(this.selectedProfile()).AddMessage(to, "me", message, true, mID, time.Now(), false)
|
this.GetUiManager(this.selectedProfile()).AddMessage(to, "me", message, true, mID, time.Now(), false)
|
||||||
}
|
}
|
||||||
|
@ -255,6 +256,7 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
|
||||||
loading = true
|
loading = true
|
||||||
}
|
}
|
||||||
this.UpdateContactStatus(group.GroupID, int(state), loading)
|
this.UpdateContactStatus(group.GroupID, int(state), loading)
|
||||||
|
this.requestGroupSettings(handle)
|
||||||
|
|
||||||
tl := group.GetTimeline()
|
tl := group.GetTimeline()
|
||||||
nick := getNick(handle)
|
nick := getNick(handle)
|
||||||
|
@ -265,35 +267,41 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
|
||||||
this.SetToolbarTitle(nick)
|
this.SetToolbarTitle(nick)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := len(tl) - 1; i >= 0; i-- {
|
go func() {
|
||||||
if tl[i].PeerID == the.Peer.GetOnion() {
|
// Janky hack to let the ui/qml respond to the status updates first before freezing under a deluge of new messages
|
||||||
handle = "me"
|
time.Sleep(10 * time.Millisecond)
|
||||||
} else {
|
for i := len(tl) - 1; i >= 0; i-- {
|
||||||
handle = tl[i].PeerID
|
if tl[i].PeerID == the.Peer.GetOnion() {
|
||||||
|
handle = "me"
|
||||||
|
} else {
|
||||||
|
handle = tl[i].PeerID
|
||||||
|
}
|
||||||
|
|
||||||
|
name := getNick(tl[i].PeerID)
|
||||||
|
image := getProfilePic(tl[i].PeerID)
|
||||||
|
|
||||||
|
this.PrependMessage(
|
||||||
|
handle,
|
||||||
|
tl[i].PeerID,
|
||||||
|
name,
|
||||||
|
tl[i].Message,
|
||||||
|
image,
|
||||||
|
string(tl[i].Signature),
|
||||||
|
tl[i].PeerID == the.Peer.GetOnion(),
|
||||||
|
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
|
||||||
|
false,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
name := getNick(tl[i].PeerID)
|
|
||||||
image := getProfilePic(tl[i].PeerID)
|
|
||||||
|
|
||||||
this.PrependMessage(
|
|
||||||
handle,
|
|
||||||
tl[i].PeerID,
|
|
||||||
name,
|
|
||||||
tl[i].Message,
|
|
||||||
image,
|
|
||||||
string(tl[i].Signature),
|
|
||||||
tl[i].PeerID == the.Peer.GetOnion(),
|
|
||||||
tl[i].Timestamp.Format(constants.TIME_FORMAT),
|
|
||||||
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,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
} // ELSE LOAD CONTACT
|
} // ELSE LOAD CONTACT
|
||||||
|
|
||||||
contact := the.Peer.GetContact(handle)
|
contact := the.Peer.GetContact(handle)
|
||||||
|
|
||||||
this.UpdateContactStatus(handle, int(connections.ConnectionStateToType[contact.State]), false)
|
this.UpdateContactStatus(handle, int(connections.ConnectionStateToType[contact.State]), false)
|
||||||
|
this.requestPeerSettings(handle)
|
||||||
|
|
||||||
var nick string
|
var nick string
|
||||||
if contact != nil {
|
if contact != nil {
|
||||||
|
@ -322,7 +330,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 != "",
|
||||||
)
|
)
|
||||||
|
@ -337,11 +345,11 @@ func (this *GrandCentralDispatcher) saveSettings(zoom, locale string) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) requestPeerSettings() {
|
func (this *GrandCentralDispatcher) requestPeerSettings(handle string) {
|
||||||
contact := the.Peer.GetContact(this.SelectedConversation())
|
contact := the.Peer.GetContact(handle)
|
||||||
if contact == nil {
|
if contact == nil {
|
||||||
log.Errorf("error: requested settings for unknown contact %v?", this.SelectedConversation())
|
log.Errorf("error: requested settings for unknown contact %v?", handle)
|
||||||
this.SupplyPeerSettings(this.SelectedConversation(), this.SelectedConversation(), string(contact.Authorization), "")
|
this.SupplyPeerSettings(this.SelectedConversation(), this.SelectedConversation(), string(model.AuthUnknown), "")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,7 +359,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
|
||||||
}
|
}
|
||||||
|
@ -387,9 +395,7 @@ func (this *GrandCentralDispatcher) requestGroupSettings(groupID string) {
|
||||||
contactnames := make([]string, len(contactaddrs))
|
contactnames := make([]string, len(contactaddrs))
|
||||||
for i, contact := range contactaddrs {
|
for i, contact := range contactaddrs {
|
||||||
contactnames[i] = getNick(contact)
|
contactnames[i] = getNick(contact)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.SupplyGroupSettings(group.GroupID, nick, group.GroupServer, invite, group.Accepted, contactnames, contactaddrs)
|
this.SupplyGroupSettings(group.GroupID, nick, group.GroupServer, invite, group.Accepted, contactnames, contactaddrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
|
@ -61,7 +61,7 @@
|
||||||
<translation type="unfinished">Adresse hier hinzufügen, um einen Kontakt aufzunehmen</translation>
|
<translation type="unfinished">Adresse hier hinzufügen, um einen Kontakt aufzunehmen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/ContactList.qml" line="251"/>
|
<location filename="../qml/widgets/ContactList.qml" line="232"/>
|
||||||
<source>blocked</source>
|
<source>blocked</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -140,7 +140,7 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/overlays/ListOverlay.qml" line="203"/>
|
<location filename="../qml/overlays/ListOverlay.qml" line="200"/>
|
||||||
<source>add-list-item-btn</source>
|
<source>add-list-item-btn</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -157,28 +157,43 @@
|
||||||
<context>
|
<context>
|
||||||
<name>Message</name>
|
<name>Message</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="57"/>
|
<location filename="../qml/widgets/Message.qml" line="66"/>
|
||||||
<source>dm-tooltip</source>
|
<source>dm-tooltip</source>
|
||||||
<extracomment>Click to DM</extracomment>
|
<extracomment>Click to DM</extracomment>
|
||||||
<translation>Klicken, um DM zu senden</translation>
|
<translation>Klicken, um DM zu senden</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="164"/>
|
<location filename="../qml/widgets/Message.qml" line="189"/>
|
||||||
<source>could-not-send-msg-error</source>
|
<source>could-not-send-msg-error</source>
|
||||||
<extracomment>Could not send this message</extracomment>
|
<extracomment>Could not send this message</extracomment>
|
||||||
<translation>Nachricht konnte nicht gesendet werden</translation>
|
<translation>Nachricht konnte nicht gesendet werden</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="164"/>
|
<location filename="../qml/widgets/Message.qml" line="189"/>
|
||||||
<source>acknowledged-label</source>
|
<source>acknowledged-label</source>
|
||||||
<translation>bestätigt</translation>
|
<translation>bestätigt</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="164"/>
|
<location filename="../qml/widgets/Message.qml" line="189"/>
|
||||||
<source>pending-label</source>
|
<source>pending-label</source>
|
||||||
<translation>Bestätigung ausstehend</translation>
|
<translation>Bestätigung ausstehend</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MessageEditor</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/widgets/MessageEditor.qml" line="32"/>
|
||||||
|
<source>peer-blocked-message</source>
|
||||||
|
<extracomment>Peer is blockced</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/widgets/MessageEditor.qml" line="49"/>
|
||||||
|
<source>peer-offline-message</source>
|
||||||
|
<extracomment>Peer is offline, messages can't be delivered right now</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>MyProfile</name>
|
<name>MyProfile</name>
|
||||||
<message>
|
<message>
|
||||||
|
@ -205,35 +220,32 @@
|
||||||
<context>
|
<context>
|
||||||
<name>OverlayPane</name>
|
<name>OverlayPane</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="24"/>
|
|
||||||
<source>accept-group-invite-label</source>
|
<source>accept-group-invite-label</source>
|
||||||
<extracomment>Do you want to accept the invitation to $GROUP</extracomment>
|
<extracomment>Do you want to accept the invitation to $GROUP</extracomment>
|
||||||
<translation>Möchtest Du die Einladung annehmen</translation>
|
<translation type="vanished">Möchtest Du die Einladung annehmen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="29"/>
|
|
||||||
<source>accept-group-btn</source>
|
<source>accept-group-btn</source>
|
||||||
<extracomment>Accept group invite button</extracomment>
|
<extracomment>Accept group invite button</extracomment>
|
||||||
<translation>Annehmen</translation>
|
<translation type="vanished">Annehmen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="39"/>
|
|
||||||
<source>reject-group-btn</source>
|
<source>reject-group-btn</source>
|
||||||
<extracomment>Reject Group invite button</extracomment>
|
<extracomment>Reject Group invite button</extracomment>
|
||||||
<translation>Ablehnen</translation>
|
<translation type="vanished">Ablehnen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="53"/>
|
<location filename="../qml/panes/OverlayPane.qml" line="66"/>
|
||||||
<source>chat-btn</source>
|
<source>chat-btn</source>
|
||||||
<translation>Chat</translation>
|
<translation>Chat</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="60"/>
|
<location filename="../qml/panes/OverlayPane.qml" line="80"/>
|
||||||
<source>lists-btn</source>
|
<source>lists-btn</source>
|
||||||
<translation>Listen</translation>
|
<translation>Listen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="67"/>
|
<location filename="../qml/panes/OverlayPane.qml" line="94"/>
|
||||||
<source>bulletins-btn</source>
|
<source>bulletins-btn</source>
|
||||||
<translation>Meldungen</translation>
|
<translation>Meldungen</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -271,34 +283,29 @@
|
||||||
<translation>speichern</translation>
|
<translation>speichern</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="90"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="89"/>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="103"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="99"/>
|
||||||
<source>save-peer-history</source>
|
<source>save-peer-history</source>
|
||||||
<extracomment>Save Peer History</extracomment>
|
<extracomment>Save Peer History</extracomment>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="91"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="90"/>
|
||||||
<source>save-peer-history-description</source>
|
<source>save-peer-history-description</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="101"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="98"/>
|
||||||
<source>dont-save-peer-history-default</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="102"/>
|
|
||||||
<source>dont-save-peer-history</source>
|
<source>dont-save-peer-history</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="129"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="120"/>
|
||||||
<source>delete-btn</source>
|
<source>delete-btn</source>
|
||||||
<translation>löschen</translation>
|
<translation>löschen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="65"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="64"/>
|
||||||
<source>block-btn</source>
|
<source>block-btn</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -411,7 +418,7 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ProfileList</name>
|
<name>ProfileList</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/ProfileList.qml" line="107"/>
|
<location filename="../qml/widgets/ProfileList.qml" line="101"/>
|
||||||
<source>add-new-profile-btn</source>
|
<source>add-new-profile-btn</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -487,34 +494,34 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="86"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="87"/>
|
||||||
<source>large-text-label</source>
|
<source>large-text-label</source>
|
||||||
<translation>Groß</translation>
|
<translation>Groß</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="94"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="95"/>
|
||||||
<source>setting-theme</source>
|
<source>setting-theme</source>
|
||||||
<extracomment>Theme</extracomment>
|
<extracomment>Theme</extracomment>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="103"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="104"/>
|
||||||
<source>theme-light</source>
|
<source>theme-light</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="104"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="105"/>
|
||||||
<source>theme-dark</source>
|
<source>theme-dark</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="153"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="154"/>
|
||||||
<source>version %1</source>
|
<source>version %1</source>
|
||||||
<extracomment>Version %1</extracomment>
|
<extracomment>Version %1</extracomment>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="162"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="163"/>
|
||||||
<source>builddate %2</source>
|
<source>builddate %2</source>
|
||||||
<extracomment>Built on: %2</extracomment>
|
<extracomment>Built on: %2</extracomment>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
|
|
Binary file not shown.
|
@ -61,7 +61,7 @@
|
||||||
<translation>... paste an address here to add a contact...</translation>
|
<translation>... paste an address here to add a contact...</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/ContactList.qml" line="251"/>
|
<location filename="../qml/widgets/ContactList.qml" line="232"/>
|
||||||
<source>blocked</source>
|
<source>blocked</source>
|
||||||
<translation>Blocked</translation>
|
<translation>Blocked</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -212,17 +212,17 @@ Right-click to reset.</translation>
|
||||||
<location filename="../qml/overlays/ListOverlay.qml" line="33"/>
|
<location filename="../qml/overlays/ListOverlay.qml" line="33"/>
|
||||||
<source>search-list</source>
|
<source>search-list</source>
|
||||||
<extracomment>ex: "... paste an address here to add a contact ..."</extracomment>
|
<extracomment>ex: "... paste an address here to add a contact ..."</extracomment>
|
||||||
<translation type="unfinished">Search List</translation>
|
<translation>Search List</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/overlays/ListOverlay.qml" line="62"/>
|
<location filename="../qml/overlays/ListOverlay.qml" line="62"/>
|
||||||
<source>peer-not-online</source>
|
<source>peer-not-online</source>
|
||||||
<translation type="unfinished">Peer is Offline. Applications cannot be used right now.</translation>
|
<translation>Peer is Offline. Applications cannot be used right now.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/overlays/ListOverlay.qml" line="203"/>
|
<location filename="../qml/overlays/ListOverlay.qml" line="200"/>
|
||||||
<source>add-list-item-btn</source>
|
<source>add-list-item-btn</source>
|
||||||
<translation type="unfinished">Add Item</translation>
|
<translation>Add Item</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
@ -237,28 +237,43 @@ Right-click to reset.</translation>
|
||||||
<context>
|
<context>
|
||||||
<name>Message</name>
|
<name>Message</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="57"/>
|
<location filename="../qml/widgets/Message.qml" line="66"/>
|
||||||
<source>dm-tooltip</source>
|
<source>dm-tooltip</source>
|
||||||
<extracomment>Click to DM</extracomment>
|
<extracomment>Click to DM</extracomment>
|
||||||
<translation>Click to DM</translation>
|
<translation>Click to DM</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="164"/>
|
<location filename="../qml/widgets/Message.qml" line="189"/>
|
||||||
<source>could-not-send-msg-error</source>
|
<source>could-not-send-msg-error</source>
|
||||||
<extracomment>Could not send this message</extracomment>
|
<extracomment>Could not send this message</extracomment>
|
||||||
<translation>Could not send this message</translation>
|
<translation>Could not send this message</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="164"/>
|
<location filename="../qml/widgets/Message.qml" line="189"/>
|
||||||
<source>acknowledged-label</source>
|
<source>acknowledged-label</source>
|
||||||
<translation>Acknowledged</translation>
|
<translation>Acknowledged</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="164"/>
|
<location filename="../qml/widgets/Message.qml" line="189"/>
|
||||||
<source>pending-label</source>
|
<source>pending-label</source>
|
||||||
<translation>Pending</translation>
|
<translation>Pending</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MessageEditor</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/widgets/MessageEditor.qml" line="32"/>
|
||||||
|
<source>peer-blocked-message</source>
|
||||||
|
<extracomment>Peer is blockced</extracomment>
|
||||||
|
<translation>Peer is blocked</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/widgets/MessageEditor.qml" line="49"/>
|
||||||
|
<source>peer-offline-message</source>
|
||||||
|
<extracomment>Peer is offline, messages can't be delivered right now</extracomment>
|
||||||
|
<translation>Peer is offline, messages can't be delivered right now</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>MyProfile</name>
|
<name>MyProfile</name>
|
||||||
<message>
|
<message>
|
||||||
|
@ -285,35 +300,32 @@ Right-click to reset.</translation>
|
||||||
<context>
|
<context>
|
||||||
<name>OverlayPane</name>
|
<name>OverlayPane</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="24"/>
|
|
||||||
<source>accept-group-invite-label</source>
|
<source>accept-group-invite-label</source>
|
||||||
<extracomment>Do you want to accept the invitation to $GROUP</extracomment>
|
<extracomment>Do you want to accept the invitation to $GROUP</extracomment>
|
||||||
<translation>Do you want to accept the invitation to</translation>
|
<translation type="vanished">Do you want to accept the invitation to</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="29"/>
|
|
||||||
<source>accept-group-btn</source>
|
<source>accept-group-btn</source>
|
||||||
<extracomment>Accept group invite button</extracomment>
|
<extracomment>Accept group invite button</extracomment>
|
||||||
<translation>Accept</translation>
|
<translation type="vanished">Accept</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="39"/>
|
|
||||||
<source>reject-group-btn</source>
|
<source>reject-group-btn</source>
|
||||||
<extracomment>Reject Group invite button</extracomment>
|
<extracomment>Reject Group invite button</extracomment>
|
||||||
<translation>Reject</translation>
|
<translation type="vanished">Reject</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="53"/>
|
<location filename="../qml/panes/OverlayPane.qml" line="66"/>
|
||||||
<source>chat-btn</source>
|
<source>chat-btn</source>
|
||||||
<translation>Chat</translation>
|
<translation>Chat</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="60"/>
|
<location filename="../qml/panes/OverlayPane.qml" line="80"/>
|
||||||
<source>lists-btn</source>
|
<source>lists-btn</source>
|
||||||
<translation>Lists</translation>
|
<translation>Lists</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="67"/>
|
<location filename="../qml/panes/OverlayPane.qml" line="94"/>
|
||||||
<source>bulletins-btn</source>
|
<source>bulletins-btn</source>
|
||||||
<translation>Bulletins</translation>
|
<translation>Bulletins</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -351,38 +363,33 @@ Right-click to reset.</translation>
|
||||||
<translation>Save</translation>
|
<translation>Save</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="65"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="64"/>
|
||||||
<source>block-btn</source>
|
<source>block-btn</source>
|
||||||
<translation>Block Peer</translation>
|
<translation>Block Peer</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="90"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="89"/>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="103"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="99"/>
|
||||||
<source>save-peer-history</source>
|
<source>save-peer-history</source>
|
||||||
<extracomment>Save Peer History</extracomment>
|
<extracomment>Save Peer History</extracomment>
|
||||||
<translation type="unfinished">Save Peer History</translation>
|
<translation>Save Peer History</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="91"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="90"/>
|
||||||
<source>save-peer-history-description</source>
|
<source>save-peer-history-description</source>
|
||||||
<translation type="unfinished">Determines whether or not to delete any history associated with the peer.</translation>
|
<translation>Determines whether or not to delete any history associated with the peer.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="101"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="98"/>
|
||||||
<source>dont-save-peer-history-default</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="102"/>
|
|
||||||
<source>dont-save-peer-history</source>
|
<source>dont-save-peer-history</source>
|
||||||
<translation type="unfinished">Delete Peer History</translation>
|
<translation>Delete Peer History</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>unblock-btn</source>
|
<source>unblock-btn</source>
|
||||||
<translation type="vanished">Unblock Peer</translation>
|
<translation type="vanished">Unblock Peer</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="129"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="120"/>
|
||||||
<source>delete-btn</source>
|
<source>delete-btn</source>
|
||||||
<translation>Delete</translation>
|
<translation>Delete</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -503,7 +510,7 @@ Right-click to reset.</translation>
|
||||||
<context>
|
<context>
|
||||||
<name>ProfileList</name>
|
<name>ProfileList</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/ProfileList.qml" line="107"/>
|
<location filename="../qml/widgets/ProfileList.qml" line="101"/>
|
||||||
<source>add-new-profile-btn</source>
|
<source>add-new-profile-btn</source>
|
||||||
<translation>Add new profile</translation>
|
<translation>Add new profile</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -588,34 +595,34 @@ Right-click to reset.</translation>
|
||||||
<translation>Zoom level</translation>
|
<translation>Zoom level</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="86"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="87"/>
|
||||||
<source>large-text-label</source>
|
<source>large-text-label</source>
|
||||||
<translation>Large</translation>
|
<translation>Large</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="94"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="95"/>
|
||||||
<source>setting-theme</source>
|
<source>setting-theme</source>
|
||||||
<extracomment>Theme</extracomment>
|
<extracomment>Theme</extracomment>
|
||||||
<translation>Theme</translation>
|
<translation>Theme</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="103"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="104"/>
|
||||||
<source>theme-light</source>
|
<source>theme-light</source>
|
||||||
<translation>Light</translation>
|
<translation>Light</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="104"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="105"/>
|
||||||
<source>theme-dark</source>
|
<source>theme-dark</source>
|
||||||
<translation>Dark</translation>
|
<translation>Dark</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="153"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="154"/>
|
||||||
<source>version %1</source>
|
<source>version %1</source>
|
||||||
<extracomment>Version %1</extracomment>
|
<extracomment>Version %1</extracomment>
|
||||||
<translation>Version %1</translation>
|
<translation>Version %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="162"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="163"/>
|
||||||
<source>builddate %2</source>
|
<source>builddate %2</source>
|
||||||
<extracomment>Built on: %2</extracomment>
|
<extracomment>Built on: %2</extracomment>
|
||||||
<translation>Built on: %2</translation>
|
<translation>Built on: %2</translation>
|
||||||
|
|
Binary file not shown.
|
@ -61,7 +61,7 @@
|
||||||
<translation type="unfinished">... coller une adresse ici pour ajouter un contact...</translation>
|
<translation type="unfinished">... coller une adresse ici pour ajouter un contact...</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/ContactList.qml" line="251"/>
|
<location filename="../qml/widgets/ContactList.qml" line="232"/>
|
||||||
<source>blocked</source>
|
<source>blocked</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -140,7 +140,7 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/overlays/ListOverlay.qml" line="203"/>
|
<location filename="../qml/overlays/ListOverlay.qml" line="200"/>
|
||||||
<source>add-list-item-btn</source>
|
<source>add-list-item-btn</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -157,28 +157,43 @@
|
||||||
<context>
|
<context>
|
||||||
<name>Message</name>
|
<name>Message</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="57"/>
|
<location filename="../qml/widgets/Message.qml" line="66"/>
|
||||||
<source>dm-tooltip</source>
|
<source>dm-tooltip</source>
|
||||||
<extracomment>Click to DM</extracomment>
|
<extracomment>Click to DM</extracomment>
|
||||||
<translation>Envoyer un message privé</translation>
|
<translation>Envoyer un message privé</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="164"/>
|
<location filename="../qml/widgets/Message.qml" line="189"/>
|
||||||
<source>could-not-send-msg-error</source>
|
<source>could-not-send-msg-error</source>
|
||||||
<extracomment>Could not send this message</extracomment>
|
<extracomment>Could not send this message</extracomment>
|
||||||
<translation>Impossible d'envoyer ce message</translation>
|
<translation>Impossible d'envoyer ce message</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="164"/>
|
<location filename="../qml/widgets/Message.qml" line="189"/>
|
||||||
<source>acknowledged-label</source>
|
<source>acknowledged-label</source>
|
||||||
<translation>Confirmé</translation>
|
<translation>Confirmé</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="164"/>
|
<location filename="../qml/widgets/Message.qml" line="189"/>
|
||||||
<source>pending-label</source>
|
<source>pending-label</source>
|
||||||
<translation>En attente</translation>
|
<translation>En attente</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MessageEditor</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/widgets/MessageEditor.qml" line="32"/>
|
||||||
|
<source>peer-blocked-message</source>
|
||||||
|
<extracomment>Peer is blockced</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/widgets/MessageEditor.qml" line="49"/>
|
||||||
|
<source>peer-offline-message</source>
|
||||||
|
<extracomment>Peer is offline, messages can't be delivered right now</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>MyProfile</name>
|
<name>MyProfile</name>
|
||||||
<message>
|
<message>
|
||||||
|
@ -205,35 +220,32 @@
|
||||||
<context>
|
<context>
|
||||||
<name>OverlayPane</name>
|
<name>OverlayPane</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="24"/>
|
|
||||||
<source>accept-group-invite-label</source>
|
<source>accept-group-invite-label</source>
|
||||||
<extracomment>Do you want to accept the invitation to $GROUP</extracomment>
|
<extracomment>Do you want to accept the invitation to $GROUP</extracomment>
|
||||||
<translation>Voulez-vous accepter l'invitation au groupe</translation>
|
<translation type="vanished">Voulez-vous accepter l'invitation au groupe</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="29"/>
|
|
||||||
<source>accept-group-btn</source>
|
<source>accept-group-btn</source>
|
||||||
<extracomment>Accept group invite button</extracomment>
|
<extracomment>Accept group invite button</extracomment>
|
||||||
<translation>Accepter</translation>
|
<translation type="vanished">Accepter</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="39"/>
|
|
||||||
<source>reject-group-btn</source>
|
<source>reject-group-btn</source>
|
||||||
<extracomment>Reject Group invite button</extracomment>
|
<extracomment>Reject Group invite button</extracomment>
|
||||||
<translation>Refuser</translation>
|
<translation type="vanished">Refuser</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="53"/>
|
<location filename="../qml/panes/OverlayPane.qml" line="66"/>
|
||||||
<source>chat-btn</source>
|
<source>chat-btn</source>
|
||||||
<translation>Discuter</translation>
|
<translation>Discuter</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="60"/>
|
<location filename="../qml/panes/OverlayPane.qml" line="80"/>
|
||||||
<source>lists-btn</source>
|
<source>lists-btn</source>
|
||||||
<translation>Listes</translation>
|
<translation>Listes</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="67"/>
|
<location filename="../qml/panes/OverlayPane.qml" line="94"/>
|
||||||
<source>bulletins-btn</source>
|
<source>bulletins-btn</source>
|
||||||
<translation>Bulletins</translation>
|
<translation>Bulletins</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -271,34 +283,29 @@
|
||||||
<translation>Sauvegarder</translation>
|
<translation>Sauvegarder</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="90"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="89"/>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="103"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="99"/>
|
||||||
<source>save-peer-history</source>
|
<source>save-peer-history</source>
|
||||||
<extracomment>Save Peer History</extracomment>
|
<extracomment>Save Peer History</extracomment>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="91"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="90"/>
|
||||||
<source>save-peer-history-description</source>
|
<source>save-peer-history-description</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="101"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="98"/>
|
||||||
<source>dont-save-peer-history-default</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="102"/>
|
|
||||||
<source>dont-save-peer-history</source>
|
<source>dont-save-peer-history</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="129"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="120"/>
|
||||||
<source>delete-btn</source>
|
<source>delete-btn</source>
|
||||||
<translation>Effacer</translation>
|
<translation>Effacer</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="65"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="64"/>
|
||||||
<source>block-btn</source>
|
<source>block-btn</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -411,7 +418,7 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ProfileList</name>
|
<name>ProfileList</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/ProfileList.qml" line="107"/>
|
<location filename="../qml/widgets/ProfileList.qml" line="101"/>
|
||||||
<source>add-new-profile-btn</source>
|
<source>add-new-profile-btn</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -487,34 +494,34 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="86"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="87"/>
|
||||||
<source>large-text-label</source>
|
<source>large-text-label</source>
|
||||||
<translation type="unfinished">Large</translation>
|
<translation type="unfinished">Large</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="94"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="95"/>
|
||||||
<source>setting-theme</source>
|
<source>setting-theme</source>
|
||||||
<extracomment>Theme</extracomment>
|
<extracomment>Theme</extracomment>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="103"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="104"/>
|
||||||
<source>theme-light</source>
|
<source>theme-light</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="104"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="105"/>
|
||||||
<source>theme-dark</source>
|
<source>theme-dark</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="153"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="154"/>
|
||||||
<source>version %1</source>
|
<source>version %1</source>
|
||||||
<extracomment>Version %1</extracomment>
|
<extracomment>Version %1</extracomment>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="162"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="163"/>
|
||||||
<source>builddate %2</source>
|
<source>builddate %2</source>
|
||||||
<extracomment>Built on: %2</extracomment>
|
<extracomment>Built on: %2</extracomment>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
|
|
Binary file not shown.
|
@ -61,7 +61,7 @@
|
||||||
<translation type="unfinished">… cole um endereço aqui para adicionar um contato…</translation>
|
<translation type="unfinished">… cole um endereço aqui para adicionar um contato…</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/ContactList.qml" line="251"/>
|
<location filename="../qml/widgets/ContactList.qml" line="232"/>
|
||||||
<source>blocked</source>
|
<source>blocked</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -140,7 +140,7 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/overlays/ListOverlay.qml" line="203"/>
|
<location filename="../qml/overlays/ListOverlay.qml" line="200"/>
|
||||||
<source>add-list-item-btn</source>
|
<source>add-list-item-btn</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -157,28 +157,43 @@
|
||||||
<context>
|
<context>
|
||||||
<name>Message</name>
|
<name>Message</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="57"/>
|
<location filename="../qml/widgets/Message.qml" line="66"/>
|
||||||
<source>dm-tooltip</source>
|
<source>dm-tooltip</source>
|
||||||
<extracomment>Click to DM</extracomment>
|
<extracomment>Click to DM</extracomment>
|
||||||
<translation>Clique para DM</translation>
|
<translation>Clique para DM</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="164"/>
|
<location filename="../qml/widgets/Message.qml" line="189"/>
|
||||||
<source>could-not-send-msg-error</source>
|
<source>could-not-send-msg-error</source>
|
||||||
<extracomment>Could not send this message</extracomment>
|
<extracomment>Could not send this message</extracomment>
|
||||||
<translation>Não deu para enviar esta mensagem</translation>
|
<translation>Não deu para enviar esta mensagem</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="164"/>
|
<location filename="../qml/widgets/Message.qml" line="189"/>
|
||||||
<source>acknowledged-label</source>
|
<source>acknowledged-label</source>
|
||||||
<translation>Confirmada</translation>
|
<translation>Confirmada</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="164"/>
|
<location filename="../qml/widgets/Message.qml" line="189"/>
|
||||||
<source>pending-label</source>
|
<source>pending-label</source>
|
||||||
<translation>Pendente</translation>
|
<translation>Pendente</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MessageEditor</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/widgets/MessageEditor.qml" line="32"/>
|
||||||
|
<source>peer-blocked-message</source>
|
||||||
|
<extracomment>Peer is blockced</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/widgets/MessageEditor.qml" line="49"/>
|
||||||
|
<source>peer-offline-message</source>
|
||||||
|
<extracomment>Peer is offline, messages can't be delivered right now</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>MyProfile</name>
|
<name>MyProfile</name>
|
||||||
<message>
|
<message>
|
||||||
|
@ -205,35 +220,32 @@
|
||||||
<context>
|
<context>
|
||||||
<name>OverlayPane</name>
|
<name>OverlayPane</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="24"/>
|
|
||||||
<source>accept-group-invite-label</source>
|
<source>accept-group-invite-label</source>
|
||||||
<extracomment>Do you want to accept the invitation to $GROUP</extracomment>
|
<extracomment>Do you want to accept the invitation to $GROUP</extracomment>
|
||||||
<translation>Você quer aceitar o convite para</translation>
|
<translation type="vanished">Você quer aceitar o convite para</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="29"/>
|
|
||||||
<source>accept-group-btn</source>
|
<source>accept-group-btn</source>
|
||||||
<extracomment>Accept group invite button</extracomment>
|
<extracomment>Accept group invite button</extracomment>
|
||||||
<translation>Aceitar</translation>
|
<translation type="vanished">Aceitar</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="39"/>
|
|
||||||
<source>reject-group-btn</source>
|
<source>reject-group-btn</source>
|
||||||
<extracomment>Reject Group invite button</extracomment>
|
<extracomment>Reject Group invite button</extracomment>
|
||||||
<translation>Recusar</translation>
|
<translation type="vanished">Recusar</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="53"/>
|
<location filename="../qml/panes/OverlayPane.qml" line="66"/>
|
||||||
<source>chat-btn</source>
|
<source>chat-btn</source>
|
||||||
<translation>Chat</translation>
|
<translation>Chat</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="60"/>
|
<location filename="../qml/panes/OverlayPane.qml" line="80"/>
|
||||||
<source>lists-btn</source>
|
<source>lists-btn</source>
|
||||||
<translation>Listas</translation>
|
<translation>Listas</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/OverlayPane.qml" line="67"/>
|
<location filename="../qml/panes/OverlayPane.qml" line="94"/>
|
||||||
<source>bulletins-btn</source>
|
<source>bulletins-btn</source>
|
||||||
<translation>Boletins</translation>
|
<translation>Boletins</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -271,34 +283,29 @@
|
||||||
<translation>Salvar</translation>
|
<translation>Salvar</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="90"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="89"/>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="103"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="99"/>
|
||||||
<source>save-peer-history</source>
|
<source>save-peer-history</source>
|
||||||
<extracomment>Save Peer History</extracomment>
|
<extracomment>Save Peer History</extracomment>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="91"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="90"/>
|
||||||
<source>save-peer-history-description</source>
|
<source>save-peer-history-description</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="101"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="98"/>
|
||||||
<source>dont-save-peer-history-default</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="102"/>
|
|
||||||
<source>dont-save-peer-history</source>
|
<source>dont-save-peer-history</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="129"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="120"/>
|
||||||
<source>delete-btn</source>
|
<source>delete-btn</source>
|
||||||
<translation>Deletar</translation>
|
<translation>Deletar</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/PeerSettingsPane.qml" line="65"/>
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="64"/>
|
||||||
<source>block-btn</source>
|
<source>block-btn</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -411,7 +418,7 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ProfileList</name>
|
<name>ProfileList</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/ProfileList.qml" line="107"/>
|
<location filename="../qml/widgets/ProfileList.qml" line="101"/>
|
||||||
<source>add-new-profile-btn</source>
|
<source>add-new-profile-btn</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -487,34 +494,34 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="86"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="87"/>
|
||||||
<source>large-text-label</source>
|
<source>large-text-label</source>
|
||||||
<translation>Grande</translation>
|
<translation>Grande</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="94"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="95"/>
|
||||||
<source>setting-theme</source>
|
<source>setting-theme</source>
|
||||||
<extracomment>Theme</extracomment>
|
<extracomment>Theme</extracomment>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="103"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="104"/>
|
||||||
<source>theme-light</source>
|
<source>theme-light</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="104"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="105"/>
|
||||||
<source>theme-dark</source>
|
<source>theme-dark</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="153"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="154"/>
|
||||||
<source>version %1</source>
|
<source>version %1</source>
|
||||||
<extracomment>Version %1</extracomment>
|
<extracomment>Version %1</extracomment>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/panes/SettingsPane.qml" line="162"/>
|
<location filename="../qml/panes/SettingsPane.qml" line="163"/>
|
||||||
<source>builddate %2</source>
|
<source>builddate %2</source>
|
||||||
<extracomment>Built on: %2</extracomment>
|
<extracomment>Built on: %2</extracomment>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
|
|
1
qml.qrc
1
qml.qrc
|
@ -16,6 +16,7 @@
|
||||||
<file>qml/widgets/ContactList.qml</file>
|
<file>qml/widgets/ContactList.qml</file>
|
||||||
<file>qml/widgets/ContactRow.qml</file>
|
<file>qml/widgets/ContactRow.qml</file>
|
||||||
<file>qml/widgets/Message.qml</file>
|
<file>qml/widgets/Message.qml</file>
|
||||||
|
<file>qml/widgets/MessageEditor.qml</file>
|
||||||
<file>qml/widgets/MyProfile.qml</file>
|
<file>qml/widgets/MyProfile.qml</file>
|
||||||
<file>qml/widgets/ProfileList.qml</file>
|
<file>qml/widgets/ProfileList.qml</file>
|
||||||
<file>qml/widgets/ProfileRow.qml</file>
|
<file>qml/widgets/ProfileRow.qml</file>
|
||||||
|
|
|
@ -11,4 +11,16 @@ Item {
|
||||||
|
|
||||||
// defined in cwtch.im/ui/go/constants/attributes.go
|
// defined in cwtch.im/ui/go/constants/attributes.go
|
||||||
readonly property string show_blocked: "show-blocked"
|
readonly property string show_blocked: "show-blocked"
|
||||||
|
|
||||||
|
// defined in cwtch.im/cwtch/protocol/connection/state.go
|
||||||
|
//0:Disconnected,1:Connecting,2:Connected,3:Authenticated,4:Synced,5:Failed,6:Killed
|
||||||
|
readonly property int state_disconnected: 0
|
||||||
|
readonly property int state_connecting: 1
|
||||||
|
readonly property int state_connected: 2
|
||||||
|
readonly property int state_authenticated: 3
|
||||||
|
readonly property int state_synced: 4
|
||||||
|
readonly property int state_failed: 5
|
||||||
|
readonly property int state_killed: 6
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
42
qml/main.qml
42
qml/main.qml
|
@ -93,7 +93,7 @@ ApplicationWindow {
|
||||||
gcd.requestGroupSettings(gcd.selectedConversation)
|
gcd.requestGroupSettings(gcd.selectedConversation)
|
||||||
} else {
|
} else {
|
||||||
theStack.pane = theStack.userProfilePane
|
theStack.pane = theStack.userProfilePane
|
||||||
gcd.requestPeerSettings()
|
gcd.requestPeerSettings(gcd.selectedConversation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,7 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RowLayout { // CONTAINS EVERYTHING EXCEPT THE TOOLBAR
|
RowLayout { // Profile Pane (contact list + overlays)
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
@ -179,9 +179,24 @@ ApplicationWindow {
|
||||||
|
|
||||||
|
|
||||||
ContactList {
|
ContactList {
|
||||||
anchors.fill: parent
|
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
|
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
|
Rectangle { // THE RIGHT PANE WHERE THE MESSAGES AND STUFF GO
|
||||||
|
@ -189,7 +204,6 @@ ApplicationWindow {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
|
||||||
StackLayout {
|
StackLayout {
|
||||||
id: theStack
|
id: theStack
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
@ -204,8 +218,14 @@ 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
|
||||||
|
anchors.topMargin: 10 * gcd.themeScale
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -242,13 +262,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 +281,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
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0505934172c42fc589f8c0e095e1e8f0efeda245
|
Subproject commit 60c6a8d9838df0a83b7e0faf06a4d6d01b4eb0a0
|
|
@ -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
|
||||||
|
|
|
@ -9,25 +9,30 @@ import "../opaque/controls" as Awesome
|
||||||
import "../opaque/fonts/Twemoji.js" as T
|
import "../opaque/fonts/Twemoji.js" as T
|
||||||
import "../utils.js" as Utils
|
import "../utils.js" as Utils
|
||||||
import "../widgets"
|
import "../widgets"
|
||||||
|
import "../opaque/theme"
|
||||||
|
|
||||||
Item {
|
Overlay {
|
||||||
width: parent.width
|
|
||||||
property bool loading
|
property bool loading
|
||||||
|
|
||||||
|
//horizontalPadding: 15 * gcd.themeScale
|
||||||
|
|
||||||
ListModel { // MESSAGE OBJECTS ARE STORED HERE ...
|
ListModel { // MESSAGE OBJECTS ARE STORED HERE ...
|
||||||
id: messagesModel
|
id: messagesModel
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView {
|
|
||||||
|
|
||||||
|
contentItem: ListView {
|
||||||
id: messagesListView
|
id: messagesListView
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.top: parent.top
|
Layout.fillWidth: true
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottom: emojiDrawer.visible ? emojiDrawer.top : rowDrawer.top
|
width: parent.width
|
||||||
model: messagesModel
|
model: messagesModel
|
||||||
spacing: 6
|
spacing: 6
|
||||||
|
|
||||||
clip: true
|
clip: true
|
||||||
ScrollBar.vertical: ScrollBar {}
|
ScrollBar.vertical: Opaque.ScrollBar {}
|
||||||
maximumFlickVelocity: 1250
|
maximumFlickVelocity: 1250
|
||||||
|
|
||||||
delegate: Message {
|
delegate: Message {
|
||||||
|
@ -42,15 +47,17 @@ 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
|
||||||
|
|
||||||
onClearMessages: function() {
|
onClearMessages: function() {
|
||||||
messagesModel.clear()
|
messagesModel.clear()
|
||||||
txtMessage.text = ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onAppendMessage: function(handle, from, displayName, message, image, mid, fromMe, ts, ackd, error) {
|
onAppendMessage: function(handle, from, displayName, message, image, mid, fromMe, ts, ackd, error) {
|
||||||
|
@ -62,6 +69,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()) {
|
||||||
|
// new Day detected, Add Date message divider
|
||||||
|
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 +124,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,
|
||||||
|
@ -112,216 +163,16 @@ Item {
|
||||||
|
|
||||||
messagesListView.positionViewAtEnd()
|
messagesListView.positionViewAtEnd()
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpdateContactStatus: function(_handle, _status, _loading) {
|
|
||||||
if (gcd.selectedConversation == _handle) {
|
|
||||||
// Group is Synced OR p2p is Authenticated
|
|
||||||
if ( (_handle.length == 32 && _status == 4) || (_handle.length == 56 && _status == 3) ) {
|
|
||||||
txtMessage.enabled = true
|
|
||||||
btnSend.enabled = true
|
|
||||||
} else {
|
|
||||||
txtMessage.enabled = false
|
|
||||||
btnSend.enabled = false
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Opaque.EmojiDrawer {
|
|
||||||
id: emojiDrawer
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottom: rowDrawer.top
|
|
||||||
size: 24 * gcd.themeScale
|
|
||||||
|
|
||||||
onPicked: function(shortcode) {
|
onSendClicked: function(messageText) {
|
||||||
if (!txtMessage.enabled) return
|
var msg = JSON.stringify({"o":1, "d":messageText.replace(/\[\:newline\:\]/g,"\n")})
|
||||||
txtMessage.insert(txtMessage.cursorPosition, ":" + shortcode + ":")
|
gcd.sendMessage(msg)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout { // THE BOTTOM DRAWER
|
|
||||||
id: rowDrawer
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
Rectangle { // MESSAGE ENTRY TEXTFIELD
|
|
||||||
id: rectMessage
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.minimumHeight: 40 * gcd.themeScale
|
|
||||||
Layout.maximumHeight: 40 * gcd.themeScale
|
|
||||||
color: txtMessage.isEnabled ? "#EDEDED" : "#CCCCCC"
|
|
||||||
border.color: "#AAAAAA"
|
|
||||||
radius: 10
|
|
||||||
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
onClicked: txtMessage.focus = true
|
|
||||||
}
|
|
||||||
|
|
||||||
Flickable {
|
|
||||||
id: flkMessage
|
|
||||||
anchors.fill: parent//this does nothing! bug in qt
|
|
||||||
Layout.minimumWidth: parent.width
|
|
||||||
Layout.maximumWidth: parent.width
|
|
||||||
Layout.minimumHeight: rectMessage.height
|
|
||||||
Layout.maximumHeight: rectMessage.height
|
|
||||||
contentWidth: txtMessage.width
|
|
||||||
contentHeight: txtMessage.height
|
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
|
||||||
clip:true
|
|
||||||
maximumFlickVelocity: 300
|
|
||||||
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBar{}
|
|
||||||
|
|
||||||
TextEdit {
|
|
||||||
id: txtMessage
|
|
||||||
font.pixelSize: 10 * gcd.themeScale
|
|
||||||
text: ""
|
|
||||||
padding: 6
|
|
||||||
wrapMode: TextEdit.Wrap
|
|
||||||
textFormat: Text.RichText
|
|
||||||
width: rectMessage.width
|
|
||||||
|
|
||||||
property bool skipOneUpdate: false
|
|
||||||
property int previousCursor
|
|
||||||
|
|
||||||
Keys.onReturnPressed: { // CTRL+ENTER = LINEBREAK
|
|
||||||
if ((event.modifiers & Qt.ControlModifier) && gcd.os != "android") {
|
|
||||||
txtMessage.insert(txtMessage.cursorPosition, "<br>")
|
|
||||||
} else if (event.modifiers == Qt.NoModifier) {
|
|
||||||
btnSend.clicked()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// welcome to the emoji parser! it is horrifying code that needs to leave in <img src="[emoji]">
|
|
||||||
// while also stripping any other tag, including other images.
|
|
||||||
// TODO: this probably breaks if people actually do want to paste html
|
|
||||||
onTextChanged: {
|
|
||||||
if (gcd.os == "android") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// we're taking advantage of TextEdit.getText()'s parsing capability, which means occasionally
|
|
||||||
// passing text into it to be filtered. this prevents recursive calls putting us into an
|
|
||||||
// infinite loop
|
|
||||||
if (skipOneUpdate) {
|
|
||||||
skipOneUpdate = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
previousCursor = cursorPosition
|
|
||||||
//console.log("onTextChanged() at position " + previousCursor)
|
|
||||||
|
|
||||||
//console.log("1: " + txtMessage.getText(0, txtMessage.text.length))
|
|
||||||
|
|
||||||
// convert <img> tags back to their emoji form
|
|
||||||
// Then parse out the rest of the HTML
|
|
||||||
var nt = restoreEmoji(txtMessage.text)
|
|
||||||
if (nt != txtMessage.text) {
|
|
||||||
skipOneUpdate = true
|
|
||||||
txtMessage.text = nt
|
|
||||||
}
|
|
||||||
|
|
||||||
//console.log("2: " + txtMessage.getText(0, txtMessage.text.length))
|
|
||||||
var preserveSpaces = txtMessage.text.replace(/<br \/>/g,"[:newline:]");
|
|
||||||
if (preserveSpaces != txtMessage.text) {
|
|
||||||
skipOneUpdate = true
|
|
||||||
txtMessage.text = preserveSpaces
|
|
||||||
}
|
|
||||||
// strip all HTML tags
|
|
||||||
var theText = Utils.htmlEscaped(txtMessage.getText(0, txtMessage.text.length))
|
|
||||||
//console.log("3: " + theText)
|
|
||||||
|
|
||||||
// convert emoji back to <img> tags
|
|
||||||
nt = parse(theText, 10)
|
|
||||||
//console.log("4: " + nt)
|
|
||||||
|
|
||||||
// preserve double spacing
|
|
||||||
nt = nt.replace(/\s\s/g, " ");
|
|
||||||
nt = nt.replace(/\[\:newline\:\]/g, "<br/>");
|
|
||||||
|
|
||||||
// then we actually put the updated text in
|
|
||||||
skipOneUpdate = true
|
|
||||||
txtMessage.text = nt
|
|
||||||
|
|
||||||
txtMessage.cursorPosition = previousCursor
|
|
||||||
|
|
||||||
// autoscroll down only when the scrollbar is already all the way down
|
|
||||||
if (flkMessage.contentY + flkMessage.height >= flkMessage.contentHeight - txtMessage.height && flkMessage.contentHeight > flkMessage.height) {
|
|
||||||
flkMessage.contentY = flkMessage.contentHeight - flkMessage.height
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: colRight
|
|
||||||
spacing: 1
|
|
||||||
|
|
||||||
|
|
||||||
Opaque.Button { // SEND MESSAGE BUTTON
|
|
||||||
id: btnSend
|
|
||||||
icon: "regular/paper-plane"
|
|
||||||
text: "send"
|
|
||||||
Layout.minimumWidth: btnEmoji.width + btnAttach.width + 2
|
|
||||||
Layout.maximumWidth: btnEmoji.width + btnAttach.width + 2
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.rightMargin: 2
|
|
||||||
|
|
||||||
property int nextMessageID: 1
|
|
||||||
|
|
||||||
TextEdit {
|
|
||||||
id: txtHidden
|
|
||||||
visible: false
|
|
||||||
textFormat: Text.RichText
|
|
||||||
}
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
if (txtMessage.text != "") {
|
|
||||||
txtHidden.text = restoreEmoji(txtMessage.text)
|
|
||||||
txtHidden.text = txtHidden.text.replace(/<br \/>/g,"[:newline:]");
|
|
||||||
var txt = txtHidden.text.trim()
|
|
||||||
if (txt.length > 0) {
|
|
||||||
var rawText = txtHidden.getText(0, txtHidden.text.length)
|
|
||||||
var msg = JSON.stringify({"o":1, "d":rawText.replace(/\[\:newline\:\]/g,"\n")})
|
|
||||||
gcd.sendMessage(msg, nextMessageID++)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
txtMessage.text = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
spacing: 1
|
|
||||||
|
|
||||||
|
|
||||||
Opaque.Button { // EMOJI DRAWER BUTTON
|
|
||||||
id: btnEmoji
|
|
||||||
icon: "regular/smile"
|
|
||||||
anchors.right: btnAttach.left
|
|
||||||
anchors.rightMargin: 2
|
|
||||||
|
|
||||||
onClicked: emojiDrawer.visible ? emojiDrawer.slideclosed() : emojiDrawer.slideopen()
|
|
||||||
}
|
|
||||||
|
|
||||||
Opaque.Button {
|
|
||||||
id: btnAttach
|
|
||||||
icon: "solid/paperclip"
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.rightMargin: 2
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
gcd.popup("attachments not yet implemented, sorry")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
@ -181,10 +181,7 @@ ColumnLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Opaque.HLine{}
|
Opaque.HLine{}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -197,23 +194,23 @@ ColumnLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
Opaque.ButtonTextField {
|
Opaque.ButtonTextField {
|
||||||
id: newlistitem
|
id: newlistitem
|
||||||
visible:listpanel.online
|
visible:listpanel.online
|
||||||
readOnly: false
|
readOnly: false
|
||||||
button_text: qsTr("add-list-item-btn")
|
button_text: qsTr("add-list-item-btn")
|
||||||
dropShadowColor: Theme.dropShadowPaneColor
|
dropShadowColor: Theme.dropShadowPaneColor
|
||||||
property int nextMessageID: 1
|
property int nextMessageID: 1
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.margins: 10
|
anchors.margins: 10
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (newlistitem.text != "") {
|
if (newlistitem.text != "") {
|
||||||
var msg = JSON.stringify({"o":4, "t":newlistitem.text})
|
var msg = JSON.stringify({"o":4, "t":newlistitem.text})
|
||||||
gcd.sendMessage(msg, nextMessageID++)
|
gcd.sendMessage(msg, nextMessageID++)
|
||||||
}
|
|
||||||
newlistitem.text = ""
|
|
||||||
}
|
}
|
||||||
|
newlistitem.text = ""
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,77 +7,102 @@ import QtQuick.Layouts 1.3
|
||||||
import "../opaque" as Opaque
|
import "../opaque" as Opaque
|
||||||
import "../opaque/styles"
|
import "../opaque/styles"
|
||||||
import "../overlays"
|
import "../overlays"
|
||||||
|
import "../opaque/fonts"
|
||||||
|
import "../opaque/theme"
|
||||||
|
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
id: overlay
|
id: overlay
|
||||||
|
|
||||||
property string name
|
property string name
|
||||||
property bool accepted
|
property bool accepted
|
||||||
property bool inGroup
|
property bool inGroup
|
||||||
|
|
||||||
RowLayout {
|
// TODO: this isn't needed now right? the peer approval flow can be addapted for groups too?
|
||||||
visible:!overlay.accepted && (gcd.selectedConversation.length == 32)
|
/* RowLayout {
|
||||||
|
visible:!overlay.accepted && (gcd.selectedConversation.length == 32)
|
||||||
|
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
//: Do you want to accept the invitation to $GROUP
|
//: Do you want to accept the invitation to $GROUP
|
||||||
text: qsTr("accept-group-invite-label") + " " + overlay.name + "?"
|
text: qsTr("accept-group-invite-label") + " " + overlay.name + "?"
|
||||||
}
|
|
||||||
|
|
||||||
Opaque.Button {
|
|
||||||
//: Accept group invite button
|
|
||||||
text: qsTr("accept-group-btn")
|
|
||||||
icon: "regular/heart"
|
|
||||||
onClicked: {
|
|
||||||
gcd.acceptGroup(gcd.selectedConversation)
|
|
||||||
gcd.requestGroupSettings(gcd.selectedConversation)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Opaque.Button {
|
|
||||||
//: Reject Group invite button
|
|
||||||
text: qsTr("reject-group-btn")
|
|
||||||
icon: "regular/trash-alt"
|
|
||||||
onClicked: {
|
|
||||||
gcd.leaveGroup(gcd.selectedConversation)
|
|
||||||
theStack.pane = theStack.emptyPane
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Opaque.Button {
|
||||||
|
//: Accept group invite button
|
||||||
|
text: qsTr("accept-group-btn")
|
||||||
|
icon: "regular/heart"
|
||||||
|
onClicked: {
|
||||||
|
gcd.acceptGroup(gcd.selectedConversation)
|
||||||
|
gcd.requestGroupSettings(gcd.selectedConversation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Opaque.Button {
|
||||||
|
//: Reject Group invite button
|
||||||
|
text: qsTr("reject-group-btn")
|
||||||
|
icon: "regular/trash-alt"
|
||||||
|
onClicked: {
|
||||||
|
gcd.leaveGroup(gcd.selectedConversation)
|
||||||
|
theStack.pane = theStack.emptyPane
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: switcher
|
id: switcher
|
||||||
|
|
||||||
|
height: chatTab.height
|
||||||
|
implicitHeight: height
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
Opaque.Button {
|
property string selectedTab: "chat"
|
||||||
|
|
||||||
|
Opaque.Tab {
|
||||||
|
id: chatTab
|
||||||
|
Layout.fillWidth: true
|
||||||
|
active: switcher.selectedTab == "chat"
|
||||||
text: qsTr("chat-btn")
|
text: qsTr("chat-btn")
|
||||||
|
|
||||||
|
onClicked: { switcher.selectedTab = "chat"; overlayStack.overlay = overlayStack.chatOverlay }
|
||||||
onClicked: overlayStack.overlay = overlayStack.chatOverlay
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Opaque.Button {
|
Rectangle {
|
||||||
|
width: 2
|
||||||
|
height: parent.height
|
||||||
|
color: Theme.dividerColor
|
||||||
|
}
|
||||||
|
|
||||||
|
Opaque.Tab {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
active: switcher.selectedTab == "lists"
|
||||||
text: qsTr("lists-btn")
|
text: qsTr("lists-btn")
|
||||||
|
|
||||||
|
onClicked: { switcher.selectedTab = "lists"; overlayStack.overlay = overlayStack.listOverlay }
|
||||||
onClicked: overlayStack.overlay = overlayStack.listOverlay
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Opaque.Button {
|
Rectangle {
|
||||||
|
width: 2
|
||||||
|
height: parent.height
|
||||||
|
color: Theme.dividerColor
|
||||||
|
}
|
||||||
|
|
||||||
|
Opaque.Tab {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
active: switcher.selectedTab == "bullitin"
|
||||||
text: qsTr("bulletins-btn")
|
text: qsTr("bulletins-btn")
|
||||||
|
|
||||||
|
onClicked: { switcher.selectedTab = "bullitin"; overlayStack.overlay = overlayStack.bulletinOverlay }
|
||||||
onClicked: overlayStack.overlay = overlayStack.bulletinOverlay
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StackLayout {
|
StackLayout {
|
||||||
id: overlayStack
|
id: overlayStack
|
||||||
anchors.left: parent.left
|
Layout.fillWidth: true
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.top: switcher.bottom
|
|
||||||
implicitHeight: height
|
implicitHeight: height
|
||||||
currentIndex: 0
|
currentIndex: 0
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,7 +104,7 @@ Opaque.SettingsList { // settingsPane
|
||||||
if (item["value"] == "SaveHistory") {
|
if (item["value"] == "SaveHistory") {
|
||||||
gcd.storeHistoryForPeer(txtOnion.text)
|
gcd.storeHistoryForPeer(txtOnion.text)
|
||||||
} else {
|
} else {
|
||||||
gcd.deleteHistoryForPeer(txtOnion.text)
|
gcd.deleteHistoryForPeer(txtOnion.text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -45,3 +45,11 @@ function isGridOccupied(x, y, points) {
|
||||||
}
|
}
|
||||||
return inPoints
|
return inPoints
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isGroup(id) {
|
||||||
|
return id.length == 32
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPeer(id) {
|
||||||
|
return id.length == 56
|
||||||
|
}
|
|
@ -64,34 +64,15 @@ ColumnLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Flickable { // THE ACTUAL CONTACT LIST
|
Opaque.Flickable { // THE ACTUAL CONTACT LIST
|
||||||
id: sv
|
id: sv
|
||||||
//Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
|
||||||
clip: true
|
|
||||||
Layout.minimumHeight: 100
|
Layout.minimumHeight: 100
|
||||||
//Layout.maximumHeight: parent.height - 30
|
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.minimumWidth: parent.width
|
Layout.minimumWidth: parent.width
|
||||||
Layout.maximumWidth: parent.width
|
Layout.maximumWidth: parent.width
|
||||||
contentWidth: parent.width
|
contentWidth: parent.width
|
||||||
contentHeight: colContacts.height
|
contentHeight: colContacts.height
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBar {
|
|
||||||
policy: ScrollBar.AsNeeded
|
|
||||||
background: Rectangle {
|
|
||||||
implicitWidth: 6
|
|
||||||
|
|
||||||
color: Theme.backgroundMainColor
|
|
||||||
}
|
|
||||||
contentItem: Rectangle {
|
|
||||||
implicitWidth: 6
|
|
||||||
implicitHeight:1
|
|
||||||
color: Theme.backgroundPaneColor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: colContacts
|
id: colContacts
|
||||||
|
@ -227,13 +208,13 @@ ColumnLayout {
|
||||||
anchors.fill: blockItem
|
anchors.fill: blockItem
|
||||||
color: Theme.backgroundMainColor
|
color: Theme.backgroundMainColor
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: Theme
|
target: Theme
|
||||||
|
|
||||||
onThemeChanged: {
|
onThemeChanged: {
|
||||||
blockedBG.color = Theme.backgroundMainColor
|
blockedBG.color = Theme.backgroundMainColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
|
@ -263,12 +244,12 @@ ColumnLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: gcd
|
target: gcd
|
||||||
|
|
||||||
onUpdateMyProfile: function(_nick, _onion, _image, _tag, _showBlocked) {
|
onUpdateMyProfile: function(_nick, _onion, _image, _tag, _showBlocked) {
|
||||||
blockedToggle.showing = (_showBlocked == "true")
|
blockedToggle.showing = (_showBlocked == "true")
|
||||||
blockedContacts.visible = (_showBlocked == "true")
|
blockedContacts.visible = (_showBlocked == "true")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,7 +258,7 @@ ColumnLayout {
|
||||||
id: blockedContactsModel
|
id: blockedContactsModel
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: blockedContacts
|
id: blockedContacts
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
|
@ -82,15 +82,12 @@ Opaque.PortraitRow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked: function(handle) {
|
onClicked: function() {
|
||||||
gcd.broadcast("ResetMessagePane")
|
gcd.broadcast("ResetMessagePane")
|
||||||
isActive = true
|
isActive = true
|
||||||
theStack.pane = theStack.messagePane
|
theStack.pane = theStack.messagePane
|
||||||
gcd.loadMessagesPane(handle)
|
gcd.loadMessagesPane(handle)
|
||||||
badge = 0
|
badge = 0
|
||||||
if (handle.length == 32) {
|
|
||||||
gcd.requestGroupSettings(handle)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: { setColors(status) }
|
Component.onCompleted: { setColors(status) }
|
||||||
|
@ -105,12 +102,12 @@ Opaque.PortraitRow {
|
||||||
portraitColor = Theme.portraitBlockedBackgroundColor
|
portraitColor = Theme.portraitBlockedBackgroundColor
|
||||||
nameColor = Theme.portraitBlockedTextColor
|
nameColor = Theme.portraitBlockedTextColor
|
||||||
onionColor = Theme.portraitBlockedTextColor
|
onionColor = Theme.portraitBlockedTextColor
|
||||||
} else if (status == 4 || status == 3) {
|
} else if (status == Const.state_synced || status == Const.state_authenticated) {
|
||||||
portraitBorderColor = Theme.portraitOnlineBorderColor
|
portraitBorderColor = Theme.portraitOnlineBorderColor
|
||||||
portraitColor = Theme.portraitOnlineBackgroundColor
|
portraitColor = Theme.portraitOnlineBackgroundColor
|
||||||
nameColor = Theme.portraitOnlineTextColor
|
nameColor = Theme.portraitOnlineTextColor
|
||||||
onionColor = Theme.portraitOnlineTextColor
|
onionColor = Theme.portraitOnlineTextColor
|
||||||
} else if (status == 2 || status == 1) {
|
} else if (status == Const.state_connected || status == Const.state_connecting) {
|
||||||
portraitBorderColor = Theme.portraitConnectingBorderColor
|
portraitBorderColor = Theme.portraitConnectingBorderColor
|
||||||
portraitColor = Theme.portraitConnectingBackgroundColor
|
portraitColor = Theme.portraitConnectingBackgroundColor
|
||||||
nameColor = Theme.portraitConnectingTextColor
|
nameColor = Theme.portraitConnectingTextColor
|
||||||
|
|
|
@ -6,13 +6,14 @@ 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)
|
||||||
|
color: Theme.backgroundMainColor
|
||||||
|
|
||||||
property string message
|
property string message
|
||||||
property string rawMessage
|
property string rawMessage
|
||||||
|
@ -22,9 +23,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 +46,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 +84,110 @@ 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
|
||||||
|
|
||||||
|
anchors.left: fromMe ? undefined : (calendarEvent ? undefined : imgProfile.right) //parent.left
|
||||||
|
anchors.right: fromMe ? (calendarEvent ? undefined : parent.right) : undefined
|
||||||
|
anchors.horizontalCenter: calendarEvent ? parent.horizontalCenter : undefined
|
||||||
|
|
||||||
// the console will complain constantly about me setting these anchors, but qt only allows margins if they've been set to something
|
|
||||||
// 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.left: fromMe ? undefined : imgProfile.right //parent.left
|
|
||||||
anchors.right: fromMe ? parent.right : undefined
|
|
||||||
anchors.leftMargin: 5
|
|
||||||
anchors.rightMargin: 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
|
||||||
|
|
|
@ -0,0 +1,291 @@
|
||||||
|
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 "../opaque" as Opaque
|
||||||
|
import "../opaque/controls" as Awesome
|
||||||
|
import "../opaque/fonts/Twemoji.js" as T
|
||||||
|
import "../utils.js" as Utils
|
||||||
|
import "../widgets"
|
||||||
|
import "../opaque/theme"
|
||||||
|
import "../const"
|
||||||
|
import "../opaque/fonts"
|
||||||
|
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property int state: Const.state_disconnected
|
||||||
|
property string authorization: ""
|
||||||
|
|
||||||
|
signal sendClicked(string messageText)
|
||||||
|
|
||||||
|
|
||||||
|
function updateState() {
|
||||||
|
|
||||||
|
// TODO unapproved
|
||||||
|
if (root.authorization == Const.auth_blocked) {
|
||||||
|
statusSeperator.color = Theme.messageStatusBlockedColor
|
||||||
|
//: Peer is blocked
|
||||||
|
statusText.text = qsTr("peer-blocked-message")
|
||||||
|
statusText.color = Theme.messageStatusBlockedTextColor
|
||||||
|
txtMessage.enabled = false
|
||||||
|
btnSend.enabled = false
|
||||||
|
btnAttach.enabled = false
|
||||||
|
btnEmoji.enabled = false
|
||||||
|
} else if ( (Utils.isGroup(gcd.selectedConversation) && root.state == Const.state_synced) || (Utils.isPeer(gcd.selectedConversation) && root.state == Const.state_authenticated) ) {
|
||||||
|
statusSeperator.color = Theme.messageStatusNormalColor
|
||||||
|
statusText.text = ""
|
||||||
|
txtMessage.enabled = true
|
||||||
|
btnSend.enabled = true
|
||||||
|
btnSend.enabled = true
|
||||||
|
btnAttach.enabled = true
|
||||||
|
btnEmoji.enabled = true
|
||||||
|
} else {
|
||||||
|
statusSeperator.color = Theme.messageStatusAlertColor
|
||||||
|
//: Peer is offline, messages can't be delivered right now
|
||||||
|
statusText.text = qsTr("peer-offline-message")
|
||||||
|
statusText.color = Theme.messageStatusAlertTextColor
|
||||||
|
txtMessage.enabled = false
|
||||||
|
btnSend.enabled = false
|
||||||
|
btnSend.enabled = false
|
||||||
|
btnAttach.enabled = false
|
||||||
|
btnEmoji.enabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Opaque.EmojiDrawer {
|
||||||
|
id: emojiDrawer
|
||||||
|
Layout.fillWidth: true
|
||||||
|
size: 24 * gcd.themeScale
|
||||||
|
|
||||||
|
onPicked: function(shortcode) {
|
||||||
|
if (!txtMessage.enabled) return
|
||||||
|
txtMessage.insert(txtMessage.cursorPosition, ":" + shortcode + ":")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: statusSeperator
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
height: statusText.visible ? statusText.height + (4 * gcd.themeScale) : 3 * gcd.themeScale
|
||||||
|
implicitHeight: height
|
||||||
|
color: Theme.dividerColor
|
||||||
|
|
||||||
|
Opaque.ScalingLabel {
|
||||||
|
id: statusText
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: ""
|
||||||
|
visible: text != ""
|
||||||
|
size: Theme.chatMetaTextSize
|
||||||
|
font.family: Fonts.applicationFontRegular.name
|
||||||
|
font.styleName: "Bold"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout { // THE BOTTOM DRAWER
|
||||||
|
id: rowDrawer
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Rectangle { // MESSAGE ENTRY TEXTFIELD
|
||||||
|
id: rectMessage
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.minimumHeight: 120 * gcd.themeScale
|
||||||
|
Layout.maximumHeight: 120 * gcd.themeScale
|
||||||
|
color: Theme.backgroundMainColor
|
||||||
|
|
||||||
|
Opaque.Flickable {
|
||||||
|
id: flkMessage
|
||||||
|
anchors.fill: parent //this does nothing! bug in qt
|
||||||
|
contentWidth: txtMessage.width
|
||||||
|
contentHeight: txtMessage.height + txtma.height
|
||||||
|
|
||||||
|
TextArea {
|
||||||
|
id: txtMessage
|
||||||
|
font.pixelSize: Theme.chatSize * gcd.themeScale
|
||||||
|
text: ""
|
||||||
|
padding: 6 * gcd.themeScale
|
||||||
|
wrapMode: TextEdit.Wrap
|
||||||
|
textFormat: Text.RichText
|
||||||
|
width: rectMessage.width
|
||||||
|
color: Theme.mainTextColor
|
||||||
|
|
||||||
|
property bool skipOneUpdate: false
|
||||||
|
property int previousCursor
|
||||||
|
|
||||||
|
Keys.onReturnPressed: { // CTRL+ENTER = LINEBREAK // TODO: Broken
|
||||||
|
if ((event.modifiers & Qt.ControlModifier) && gcd.os != "android") {
|
||||||
|
txtMessage.insert(txtMessage.cursorPosition, "<br>")
|
||||||
|
} else if (event.modifiers == Qt.NoModifier) {
|
||||||
|
btnSend.clicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// welcome to the emoji parser! it is horrifying code that needs to leave in <img src="[emoji]">
|
||||||
|
// while also stripping any other tag, including other images.
|
||||||
|
// TODO: this probably breaks if people actually do want to paste html
|
||||||
|
onTextChanged: {
|
||||||
|
if (gcd.os == "android") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// we're taking advantage of TextEdit.getText()'s parsing capability, which means occasionally
|
||||||
|
// passing text into it to be filtered. this prevents recursive calls putting us into an
|
||||||
|
// infinite loop
|
||||||
|
if (skipOneUpdate) {
|
||||||
|
skipOneUpdate = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
previousCursor = cursorPosition
|
||||||
|
//console.log("onTextChanged() at position " + previousCursor)
|
||||||
|
|
||||||
|
//console.log("1: " + txtMessage.getText(0, txtMessage.text.length))
|
||||||
|
|
||||||
|
// convert <img> tags back to their emoji form
|
||||||
|
// Then parse out the rest of the HTML
|
||||||
|
var nt = restoreEmoji(txtMessage.text)
|
||||||
|
if (nt != txtMessage.text) {
|
||||||
|
skipOneUpdate = true
|
||||||
|
txtMessage.text = nt
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log("2: " + txtMessage.getText(0, txtMessage.text.length))
|
||||||
|
var preserveSpaces = txtMessage.text.replace(/<br \/>/g,"[:newline:]");
|
||||||
|
if (preserveSpaces != txtMessage.text) {
|
||||||
|
skipOneUpdate = true
|
||||||
|
txtMessage.text = preserveSpaces
|
||||||
|
}
|
||||||
|
// strip all HTML tags
|
||||||
|
var theText = Utils.htmlEscaped(txtMessage.getText(0, txtMessage.text.length))
|
||||||
|
//console.log("3: " + theText)
|
||||||
|
|
||||||
|
// convert emoji back to <img> tags
|
||||||
|
nt = parse(theText, 10)
|
||||||
|
//console.log("4: " + nt)
|
||||||
|
|
||||||
|
// preserve double spacing
|
||||||
|
nt = nt.replace(/\s\s/g, " ");
|
||||||
|
nt = nt.replace(/\[\:newline\:\]/g, "<br/>");
|
||||||
|
|
||||||
|
// then we actually put the updated text in
|
||||||
|
skipOneUpdate = true
|
||||||
|
txtMessage.text = nt
|
||||||
|
|
||||||
|
txtMessage.cursorPosition = previousCursor
|
||||||
|
|
||||||
|
// autoscroll down only when the scrollbar is already all the way down
|
||||||
|
if (flkMessage.contentY + flkMessage.height >= flkMessage.contentHeight - txtMessage.height && flkMessage.contentHeight > flkMessage.height) {
|
||||||
|
flkMessage.contentY = flkMessage.contentHeight - flkMessage.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: txtma
|
||||||
|
anchors.top: txtMessage.bottom
|
||||||
|
width: flkMessage.width
|
||||||
|
height: Math.max(rectMessage.height - txtMessage.height, 0)
|
||||||
|
|
||||||
|
onClicked: { txtMessage.focus = true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: colRight
|
||||||
|
spacing: 0
|
||||||
|
width: 100 * gcd.themeScale
|
||||||
|
|
||||||
|
Layout.minimumWidth: width
|
||||||
|
Layout.preferredWidth: width
|
||||||
|
Layout.maximumWidth: width
|
||||||
|
|
||||||
|
Opaque.Icon { // SEND MESSAGE BUTTON
|
||||||
|
id: btnSend
|
||||||
|
source: gcd.assetPath + "core/send-24px.svg"
|
||||||
|
width: colRight.width
|
||||||
|
height: 50 * gcd.themeScale
|
||||||
|
size: 36 * gcd.themeScale
|
||||||
|
|
||||||
|
backgroundColor: enabled ? Theme.defaultButtonColor : Theme.defaultButtonDisabledColor
|
||||||
|
hilightBackgroundColor: Theme.defaultButtonActiveColor
|
||||||
|
iconColor: Theme.defaultButtonTextColor
|
||||||
|
|
||||||
|
property int nextMessageID: 1
|
||||||
|
|
||||||
|
TextEdit {
|
||||||
|
id: txtHidden
|
||||||
|
visible: false
|
||||||
|
textFormat: Text.RichText
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
// Cannot use .text b/c in rich text mode it is always full of html
|
||||||
|
if (txtMessage.length != 0) {
|
||||||
|
txtHidden.text = restoreEmoji(txtMessage.text)
|
||||||
|
txtHidden.text = txtHidden.text.replace(/<br \/>/g,"[:newline:]");
|
||||||
|
|
||||||
|
var txt = txtHidden.text.trim()
|
||||||
|
if (txt.length > 0) {
|
||||||
|
var rawText = txtHidden.getText(0, txtHidden.text.length)
|
||||||
|
|
||||||
|
root.sendClicked(rawText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
txtMessage.text = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Opaque.Icon { // EMOJI DRAWER BUTTON
|
||||||
|
id: btnEmoji
|
||||||
|
source: gcd.assetPath + "core/mood-24px.svg"
|
||||||
|
|
||||||
|
size: 25
|
||||||
|
height: 36 * gcd.themeScale
|
||||||
|
width: 48 * gcd.themeScale
|
||||||
|
|
||||||
|
backgroundColor: enabled ? Theme.backgroundMainColor : Theme.backgroundPaneColor
|
||||||
|
hilightBackgroundColor: Theme.backgroundPaneColor
|
||||||
|
iconColor: Theme.dividerColor
|
||||||
|
|
||||||
|
onClicked: emojiDrawer.visible ? emojiDrawer.slideclosed() : emojiDrawer.slideopen()
|
||||||
|
}
|
||||||
|
|
||||||
|
Opaque.Icon {
|
||||||
|
id: btnAttach
|
||||||
|
source: gcd.assetPath + "core/attach_file-24px.svg"
|
||||||
|
|
||||||
|
size: 25
|
||||||
|
height: 36 * gcd.themeScale
|
||||||
|
width: 48 * gcd.themeScale
|
||||||
|
|
||||||
|
backgroundColor: enabled ? Theme.backgroundMainColor : Theme.backgroundPaneColor
|
||||||
|
hilightBackgroundColor: Theme.backgroundPaneColor
|
||||||
|
iconColor: Theme.dividerColor
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
gcd.popup("attachments not yet implemented, sorry")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: gcd
|
||||||
|
|
||||||
|
onClearMessages: function() {
|
||||||
|
txtMessage.text = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
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 "../opaque" as Opaque
|
||||||
|
import "../opaque/controls" as Awesome
|
||||||
|
import "../opaque/fonts/Twemoji.js" as T
|
||||||
|
import "../utils.js" as Utils
|
||||||
|
import "../widgets"
|
||||||
|
import "../opaque/theme"
|
||||||
|
import "../const"
|
||||||
|
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
Layout.fillWidth: true
|
||||||
|
property bool online: false
|
||||||
|
|
||||||
|
property int state: Const.state_disconnected
|
||||||
|
property string authorization: ""
|
||||||
|
|
||||||
|
|
||||||
|
signal sendClicked(string messateText)
|
||||||
|
property alias contentItem: control.contentItem
|
||||||
|
|
||||||
|
Control {
|
||||||
|
id: control
|
||||||
|
width: parent.width
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: 10 * gcd.themeScale
|
||||||
|
|
||||||
|
anchors.bottom: msgEd.top
|
||||||
|
anchors.bottomMargin: 10 * gcd.themeScale
|
||||||
|
|
||||||
|
horizontalPadding: 15 * gcd.themeScale
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MessageEditor {
|
||||||
|
id: msgEd
|
||||||
|
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.rightMargin: 15 * gcd.themeScale
|
||||||
|
anchors.leftMargin: 15 * gcd.themeScale
|
||||||
|
|
||||||
|
onSendClicked: function(messageText) {
|
||||||
|
root.sendClicked(messageText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateState() {
|
||||||
|
if (root.authorization == Const.auth_blocked) {
|
||||||
|
// Blocked
|
||||||
|
|
||||||
|
} else if ( (Utils.isGroup(gcd.selectedConversation) && root.state == Const.state_synced) || (Utils.isPeer(gcd.selectedConversation) && root.state == Const.state_authenticated) ) {
|
||||||
|
// Online
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Not Online
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: gcd
|
||||||
|
|
||||||
|
onUpdateContactStatus: function(_handle, _status, _loading) {
|
||||||
|
if (gcd.selectedConversation == _handle) {
|
||||||
|
root.state = _status
|
||||||
|
msgEd.state = _status
|
||||||
|
updateState()
|
||||||
|
msgEd.updateState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSupplyPeerSettings: function(onion, nick, authorization, storage) {
|
||||||
|
// TODO unknown
|
||||||
|
root.authorization = authorization
|
||||||
|
msgEd.authorization = authorization
|
||||||
|
updateState()
|
||||||
|
msgEd.updateState()
|
||||||
|
}
|
||||||
|
|
||||||
|
onSupplyGroupSettings: function(groupID, nick, groupServer, invite, accepted, contactnames, contactaddrs) {
|
||||||
|
if (accepted) {
|
||||||
|
root.authorization = Const.auth_approved
|
||||||
|
msgEd.authorization = Const.auth_approved
|
||||||
|
} else {
|
||||||
|
root.authorization = Const.auth_unknown
|
||||||
|
msgEd.authorization = Const.auth_unknown
|
||||||
|
}
|
||||||
|
updateState()
|
||||||
|
msgEd.updateState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,23 +18,16 @@ ColumnLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Flickable { // Profile List
|
Opaque.Flickable { // Profile List
|
||||||
id: sv
|
id: sv
|
||||||
clip: true
|
|
||||||
Layout.minimumHeight: 100
|
Layout.minimumHeight: 100
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.minimumWidth: parent.width
|
Layout.minimumWidth: parent.width
|
||||||
Layout.maximumWidth: parent.width
|
Layout.maximumWidth: parent.width
|
||||||
contentWidth: colContacts.width
|
contentWidth: colContacts.width
|
||||||
contentHeight: colContacts.height
|
contentHeight: colContacts.height
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
|
||||||
maximumFlickVelocity: 400
|
|
||||||
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBar {
|
|
||||||
policy: ScrollBar.AlwaysOn
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: colContacts
|
id: colContacts
|
||||||
width: sv.width
|
width: sv.width
|
||||||
|
|
Reference in New Issue