initial commit
This commit is contained in:
parent
65c50a50b0
commit
1011d4a4f9
|
@ -32,7 +32,11 @@ func (this *ChatChannelListener) OpenInbound() {
|
|||
}
|
||||
|
||||
func (this *ChatChannelListener) ChatMessage(messageID uint32, when time.Time, message string) bool {
|
||||
DeliverMessageToUI(this.rai.RemoteHostname, message, uint(messageID), false, when)
|
||||
DeliverMessageToUI(this.rai.RemoteHostname, this.rai.RemoteHostname, "", message, uint(messageID), false, when)
|
||||
go func() {
|
||||
time.Sleep(time.Second)
|
||||
peer.Save()
|
||||
}()
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
24
gcd.go
24
gcd.go
|
@ -18,7 +18,7 @@ type GrandCentralDispatcher struct {
|
|||
currentOpenConversation string
|
||||
|
||||
// messages pane stuff
|
||||
_ func(from, message string, mID uint, ts string) `signal:"AppendMessage"`
|
||||
_ func(from, message, displayname string, mID uint, ts, source string) `signal:"AppendMessage"`
|
||||
_ func() `signal:"ClearMessages"`
|
||||
_ func() `signal:"ResetMessagePane"`
|
||||
_ func(uint) `signal:"Acknowledged"`
|
||||
|
@ -78,7 +78,7 @@ func (this *GrandCentralDispatcher) sendMessage(message string, mID uint) {
|
|||
default:
|
||||
}
|
||||
|
||||
DeliverMessageToUI(gcd.currentOpenConversation, message, mID, true, time.Now())
|
||||
DeliverMessageToUI(gcd.currentOpenConversation, gcd.currentOpenConversation, "", message, mID, true, time.Now())
|
||||
}
|
||||
|
||||
func (this *GrandCentralDispatcher) loadMessagesPane(onion string) {
|
||||
|
@ -86,15 +86,27 @@ func (this *GrandCentralDispatcher) loadMessagesPane(onion string) {
|
|||
gcd.currentOpenConversation = onion
|
||||
gcd.SetUnread(onion, 0)
|
||||
|
||||
if len(onion) == 32 { // eg 48e7dcfc353e6d77da2c31d63654fd19
|
||||
if len(onion) == 32 { // LOAD GROUP
|
||||
log.Printf("LOADING GROUP %s", onion)
|
||||
tl := peer.GetGroup(onion).GetTimeline()
|
||||
log.Printf("messages: %d", len(tl))
|
||||
for i := range tl {
|
||||
gcd.AppendMessage(tl[i].PeerID, tl[i].Message, 0, tl[i].Timestamp.Format(TIME_FORMAT))
|
||||
var handle string
|
||||
if tl[i].PeerID == peer.GetProfile().Onion {
|
||||
handle = "me"
|
||||
} else {
|
||||
handle = tl[i].PeerID
|
||||
}
|
||||
var name string
|
||||
var exists bool
|
||||
name, exists = peer.GetProfile().GetCustomAttribute(tl[i].PeerID + "_name")
|
||||
if !exists || name == "" {
|
||||
name = tl[i].PeerID[:16] + "..."
|
||||
}
|
||||
gcd.AppendMessage(handle, tl[i].Message, name, 0, tl[i].Timestamp.Format(TIME_FORMAT), randomProfileImage(tl[i].PeerID))
|
||||
}
|
||||
return
|
||||
}
|
||||
} // ELSE LOAD CONTACT
|
||||
|
||||
_, exists := contactMgr[onion]
|
||||
if exists { // (if not, they haven't been accepted as a contact yet)
|
||||
|
@ -106,7 +118,7 @@ func (this *GrandCentralDispatcher) loadMessagesPane(onion string) {
|
|||
if messages[i].FromMe {
|
||||
from = "me"
|
||||
}
|
||||
gcd.AppendMessage(from, messages[i].Message, messages[i].MessageID, messages[i].Timestamp.Format(TIME_FORMAT))
|
||||
gcd.AppendMessage(from, messages[i].Message, "", messages[i].MessageID, messages[i].Timestamp.Format(TIME_FORMAT), randomProfileImage(onion))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
57
main.go
57
main.go
|
@ -52,21 +52,21 @@ type Message struct {
|
|||
Timestamp time.Time
|
||||
}
|
||||
|
||||
func DeliverMessageToUI(from, message string, mID uint, fromMe bool, ts time.Time) {
|
||||
_, found := contactMgr[from]
|
||||
func DeliverMessageToUI(handle, from, displayname, message string, mID uint, fromMe bool, ts time.Time) {
|
||||
_, found := contactMgr[handle]
|
||||
if !found {
|
||||
contactMgr[from] = &Contact{[]Message{}, 0, 0}
|
||||
contactMgr[handle] = &Contact{[]Message{}, 0, 0}
|
||||
}
|
||||
|
||||
contactMgr[from].AddMessage(Message{from, message, fromMe, mID, ts})
|
||||
if gcd.currentOpenConversation == from {
|
||||
contactMgr[handle].AddMessage(Message{from, message, fromMe, mID, ts})
|
||||
if gcd.currentOpenConversation == handle {
|
||||
if fromMe {
|
||||
from = "me"
|
||||
}
|
||||
gcd.AppendMessage(from, message, mID, ts.Format(TIME_FORMAT))
|
||||
gcd.AppendMessage(from, message, displayname, mID, ts.Format(TIME_FORMAT), randomProfileImage(from))
|
||||
} else {
|
||||
contactMgr[from].Unread++
|
||||
gcd.SetUnread(from, contactMgr[from].Unread)
|
||||
contactMgr[handle].Unread++
|
||||
gcd.SetUnread(handle, contactMgr[handle].Unread)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,9 @@ func main() {
|
|||
quickcontrols2.QQuickStyle_SetStyle("Universe")
|
||||
view := quick.NewQQuickView(nil)
|
||||
view.SetResizeMode(quick.QQuickView__SizeRootObjectToView)
|
||||
view.SetTitle("bounce")
|
||||
view.SetMinimumHeight(280)
|
||||
view.SetMinimumWidth(300)
|
||||
view.SetTitle("cwtch")
|
||||
gcd = NewGrandCentralDispatcher(nil)
|
||||
view.RootContext().SetContextProperty("gcd", gcd)
|
||||
|
||||
|
@ -113,11 +115,12 @@ func groupPoller() {
|
|||
groups := peer.GetGroups()
|
||||
for i := range groups {
|
||||
group := peer.GetGroup(groups[i])
|
||||
log.Printf("setting group %s to status %d", groups[i], int(servers[group.GroupServer]))
|
||||
//log.Printf("setting group %s to status %d", groups[i], int(servers[group.GroupServer]))
|
||||
gcd.SetConnectionStatus(groups[i], int(servers[group.GroupServer]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func presencePoller() { // TODO: make this subscribe-able in ricochet
|
||||
time.Sleep(time.Second * 4)
|
||||
for {
|
||||
|
@ -181,8 +184,22 @@ func torStatusPoller() {
|
|||
func cwtchListener(groupID string, channel chan model.Message) {
|
||||
for {
|
||||
m := <-channel
|
||||
log.Printf("GROUPMSG %s", m.Message)
|
||||
DeliverMessageToUI(groupID, m.Message, 0, m.PeerID == peer.GetProfile().Onion, m.Timestamp)
|
||||
log.Printf("GROUPMSG %s %s", m.Message, m.PeerID)
|
||||
name := m.PeerID
|
||||
if name == peer.GetProfile().Onion {
|
||||
name = "me"
|
||||
} else {
|
||||
var exists bool // lol this is a golang antifeature
|
||||
name, exists = peer.GetProfile().GetCustomAttribute(m.PeerID + "_name")
|
||||
if !exists {
|
||||
name = ""
|
||||
}
|
||||
}
|
||||
if name == "" {
|
||||
name = m.PeerID[:16] + "..."
|
||||
}
|
||||
DeliverMessageToUI(groupID, m.PeerID, name, m.Message, 0, m.PeerID == peer.GetProfile().Onion, m.Timestamp)
|
||||
peer.Save()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,19 +242,20 @@ func andHisBlackAndWhiteCat(incomingMessages chan Message) {
|
|||
}
|
||||
|
||||
func initialize(view *quick.QQuickView) {
|
||||
log.Printf(os.Args[0])
|
||||
//TODO: this section is ported over and has a lot of printf errors, need to show them in the ui
|
||||
var dirname, filename string
|
||||
if os.Getenv("SENDAFRIEND_FOLDER") != "" {
|
||||
dirname = os.Getenv("SENDAFRIEND_FOLDER")
|
||||
filename = path.Join(dirname, "identity.private")
|
||||
if os.Getenv("CWTCH_FOLDER") != "" {
|
||||
dirname = os.Getenv("CWTCH_FOLDER")
|
||||
filename = path.Join(dirname, "keep-this-file-private")
|
||||
} else {
|
||||
usr, err := user.Current()
|
||||
if err != nil {
|
||||
fmt.Printf("\nerror: could not load current user: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
dirname = path.Join(usr.HomeDir, ".sendafriend")
|
||||
filename = path.Join(dirname, "identity.private")
|
||||
dirname = path.Join(usr.HomeDir, ".cwtch")
|
||||
filename = path.Join(dirname, "keep-this-file-private")
|
||||
}
|
||||
|
||||
os.MkdirAll(dirname, 0700)
|
||||
|
@ -293,6 +311,11 @@ func initialize(view *quick.QQuickView) {
|
|||
|
||||
// temporary until we do real picture selection
|
||||
func randomProfileImage(onion string) string {
|
||||
//TODO: this is a hack, fix ever passing this in
|
||||
if onion == "me" {
|
||||
onion = peer.GetProfile().Onion
|
||||
}
|
||||
|
||||
choices := []string{"001-centaur", "002-kraken", "003-dinosaur", "004-tree-1", "005-hand", "006-echidna", "007-robot", "008-mushroom", "009-harpy", "010-phoenix", "011-dragon-1", "012-devil", "013-troll", "014-alien", "015-minotaur", "016-madre-monte", "017-satyr", "018-karakasakozou", "019-pirate", "020-werewolf", "021-scarecrow", "022-valkyrie", "023-curupira", "024-loch-ness-monster", "025-tree", "026-cerberus", "027-gryphon", "028-mermaid", "029-vampire", "030-goblin", "031-yeti", "032-leprechaun", "033-medusa", "034-chimera", "035-elf", "036-hydra", "037-cyclops", "038-pegasus", "039-narwhal", "040-woodcutter", "041-zombie", "042-dragon", "043-frankenstein", "044-witch", "045-fairy", "046-genie", "047-pinocchio", "048-ghost", "049-wizard", "050-unicorn"}
|
||||
barr, err := base32.StdEncoding.DecodeString(strings.ToUpper(onion))
|
||||
if err != nil || len(barr) != 35 {
|
||||
|
|
132
qml/main.qml
132
qml/main.qml
|
@ -8,17 +8,18 @@ import "fonts/Twemoji.js" as T
|
|||
import "widgets"
|
||||
|
||||
Item {
|
||||
id: windowItem
|
||||
width: 525
|
||||
height: 500
|
||||
id: root
|
||||
|
||||
readonly property real ratio: height / width
|
||||
|
||||
FontAwesome {
|
||||
FontAwesome { // PRETTY BUTTON ICONS
|
||||
id: awesome
|
||||
resource: "qrc:/qml/fonts/fontawesome.ttf"
|
||||
}
|
||||
|
||||
function parse(text, size) {
|
||||
function parse(text, size) { // REPLACE EMOJI WITH <IMG> TAGS
|
||||
T.twemoji.base = "qrc:/qml/fonts/twemoji/"
|
||||
T.twemoji.ext = ".png"
|
||||
T.twemoji.size = "72x72"
|
||||
|
@ -26,7 +27,7 @@ Item {
|
|||
return T.twemoji.parse(text)
|
||||
}
|
||||
|
||||
function restoreEmoji(text) {
|
||||
function restoreEmoji(text) { // REPLACE <IMG> TAGS WITH EMOJI
|
||||
var re = /<img src="qrc:\/qml\/fonts\/twemoji\/72x72\/([^"]*?)\.png" width="10" height="10" \/>/g
|
||||
var arr
|
||||
var newtext = text
|
||||
|
@ -42,7 +43,57 @@ Item {
|
|||
}
|
||||
|
||||
|
||||
RowLayout {
|
||||
/* Rectangle { // THE TOOLBAR
|
||||
id: toolbar
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
width: ratio >= 0.92 ? parent.width : 70
|
||||
height: ratio >= 0.92 ? 70 : parent.height
|
||||
color: "#4B3557"
|
||||
|
||||
GridLayout {
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
columns: ratio >= 0.92 ? children.length : 1
|
||||
|
||||
|
||||
ContactPicture {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
source: "qrc:/qml/images/profiles/001-centaur.png"
|
||||
status: -2
|
||||
}
|
||||
|
||||
ContactPicture {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
source: "qrc:/qml/images/profiles/002-kraken.png"
|
||||
status: -2
|
||||
}
|
||||
|
||||
ContactPicture {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
source: "qrc:/qml/images/profiles/003-dinosaur.png"
|
||||
status: -2
|
||||
}
|
||||
|
||||
ContactPicture {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
source: "qrc:/qml/images/profiles/004-tree-1.png"
|
||||
status: -2
|
||||
}
|
||||
|
||||
ContactPicture {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
source: "qrc:/qml/images/profiles/005-hand.png"
|
||||
status: -2
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
RowLayout { // CONTAINS EVERYTHING EXCEPT THE TOOLBAR
|
||||
/* anchors.left: ratio >= 0.92 ? parent.left : toolbar.right
|
||||
anchors.top: ratio >= 0.92 ? toolbar.bottom : parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom */
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
|
@ -50,8 +101,9 @@ Item {
|
|||
Rectangle { // THE LEFT PANE WITH TOOLS AND CONTACTS
|
||||
color: "#D2C0DD"
|
||||
Layout.fillHeight: true
|
||||
Layout.minimumWidth: 200
|
||||
Layout.maximumWidth: 200
|
||||
Layout.minimumWidth: Layout.maximumWidth
|
||||
Layout.maximumWidth: theStack.pane == theStack.emptyPane ? parent.width : 200
|
||||
visible: (ratio <= 1.08 && windowItem.width >= 500) || theStack.pane == theStack.emptyPane
|
||||
|
||||
|
||||
ContactList{
|
||||
|
@ -59,21 +111,79 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Rectangle { // THE RIGHT PANE WHERE THE MESSAGES GO
|
||||
Rectangle { // THE RIGHT PANE WHERE THE MESSAGES AND STuFF GO
|
||||
color: "#EEEEFF"
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
|
||||
MessageList{
|
||||
StackLayout {
|
||||
id: theStack
|
||||
anchors.fill: parent
|
||||
currentIndex: 0
|
||||
|
||||
property alias pane: theStack.currentIndex
|
||||
readonly property int emptyPane: 0
|
||||
readonly property int messagePane: 1
|
||||
readonly property int settingsPane: 2
|
||||
readonly property int userProfilePane: 3
|
||||
readonly property int groupProfilePane: 4
|
||||
|
||||
|
||||
Item {} // empty
|
||||
|
||||
MessageList { // messagePane
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
ColumnLayout { // settingsPane
|
||||
anchors.fill: parent
|
||||
|
||||
|
||||
StackToolbar {
|
||||
text: "Cwtch Settings"
|
||||
aux.visible: false
|
||||
}
|
||||
|
||||
Label { text: "welcome to the global app settings page!" }
|
||||
}
|
||||
|
||||
ColumnLayout { // userProfilePane
|
||||
anchors.fill: parent
|
||||
|
||||
|
||||
StackToolbar {
|
||||
text: "Settings for Sarah"
|
||||
aux.visible: false
|
||||
|
||||
back.onClicked: theStack.pane = theStack.messagePane
|
||||
}
|
||||
|
||||
Label { text: "per-user things like contact name and picture will be edited here" }
|
||||
}
|
||||
|
||||
Label { // groupProfilePane
|
||||
font.pixelSize: 12
|
||||
text: "invite new people or change the group name here"
|
||||
|
||||
|
||||
StackToolbar { text: "Group settings" }
|
||||
}
|
||||
|
||||
Label { // addGroupPane
|
||||
font.pixelSize: 12
|
||||
text: "add a new group"
|
||||
|
||||
|
||||
StackToolbar { text: "Create group" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PropertyAnimation { id: anmPopup; easing.type: Easing.InQuart; duration: 7000; target: popup; property: "opacity"; to: 0; }
|
||||
|
||||
Rectangle {
|
||||
Rectangle { // THE ERROR MESSAGE POPUP
|
||||
id: popup
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
@ -96,7 +206,7 @@ Item {
|
|||
}
|
||||
|
||||
|
||||
Connections {
|
||||
Connections { // POPUPS ARE INVOKED BY GO FUNCS
|
||||
target: gcd
|
||||
|
||||
onInvokePopup: function(str) {
|
||||
|
|
|
@ -57,7 +57,7 @@ RowLayout { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
|
|||
id: rectUnread
|
||||
anchors.right: parent.right
|
||||
height: 16
|
||||
width: childrenRect.width + 10
|
||||
width: lblUnread.width + 10
|
||||
radius: 8
|
||||
color: "#4B3557"
|
||||
visible: badge != "0"
|
||||
|
@ -65,6 +65,7 @@ RowLayout { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
|
|||
|
||||
|
||||
Label {
|
||||
id: lblUnread
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: "#FFFFFF"
|
||||
|
@ -82,6 +83,7 @@ RowLayout { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
|
|||
onClicked: {
|
||||
gcd.broadcast("ResetMessagePane")
|
||||
isActive = true
|
||||
theStack.pane = theStack.messagePane
|
||||
gcd.loadMessagesPane(onion)
|
||||
}
|
||||
|
||||
|
@ -108,7 +110,6 @@ RowLayout { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
|
|||
}
|
||||
|
||||
onSetConnectionStatus: function(foronion, x) {
|
||||
if (foronion.length == 32) console.log(onion+" setting status "+x+" for contact "+foronion)
|
||||
if (onion == foronion) {
|
||||
status = x
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -9,7 +9,6 @@ Item {
|
|||
id: imgProfile
|
||||
implicitWidth: 48
|
||||
implicitHeight: 48
|
||||
anchors.left: parent.left
|
||||
anchors.margins: 5
|
||||
|
||||
property alias source: img.source
|
||||
|
|
|
@ -8,12 +8,18 @@ import "controls" as Awesome
|
|||
|
||||
RowLayout {
|
||||
id: root
|
||||
Layout.alignment: from == "me" ? Qt.AlignRight : Qt.AlignLeft
|
||||
//Layout.alignment: from == "me" ? Qt.AlignRight : Qt.AlignLeft
|
||||
anchors.left: from == "me" ? undefined : parent.left
|
||||
anchors.right: from == "me" ? parent.right : undefined
|
||||
height: Math.max(imgProfile.height, rectMessageBubble.height)
|
||||
|
||||
property alias message: lbl.text
|
||||
property string from
|
||||
property string displayname
|
||||
property int messageID
|
||||
property alias timestamp: ts.text
|
||||
property alias source: imgProfile.source
|
||||
property alias status: imgProfile.status
|
||||
|
||||
|
||||
Connections {
|
||||
|
@ -27,15 +33,22 @@ RowLayout {
|
|||
}
|
||||
|
||||
|
||||
ContactPicture {
|
||||
id: imgProfile
|
||||
anchors.left: parent.left
|
||||
visible: from != "me"
|
||||
}
|
||||
|
||||
Rectangle { // THIS IS JUST A PRETTY MESSAGE-HOLDING RECTANGLE
|
||||
height: childrenRect.height + 3
|
||||
width: childrenRect.width + 6
|
||||
id: rectMessageBubble
|
||||
height: lbl.height + ts.height + 4
|
||||
width: colMessageBubble.width + 6
|
||||
color: from == "me" ? "#B09CBC" : "#4B3557"
|
||||
radius: 5
|
||||
|
||||
// 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: from == "me" ? undefined : parent.left
|
||||
anchors.left: from == "me" ? undefined : imgProfile.right //parent.left
|
||||
anchors.right: from == "me" ? parent.right : undefined
|
||||
anchors.leftMargin: 5
|
||||
anchors.rightMargin: 9
|
||||
|
@ -43,6 +56,9 @@ RowLayout {
|
|||
|
||||
|
||||
ColumnLayout {
|
||||
id: colMessageBubble
|
||||
|
||||
|
||||
Column { // combine these into one element or else childrenRect won't play nicely
|
||||
TextEdit { // this is used as a helper to calculate the message box width
|
||||
id: dummy
|
||||
|
@ -63,18 +79,19 @@ RowLayout {
|
|||
font.pixelSize: 12
|
||||
selectByMouse: true
|
||||
readOnly: true
|
||||
width: dummy.width > root.parent.width - 70 ? root.parent.width - 70 : dummy.width
|
||||
width: Math.min(dummy.width, root.parent.width - (imgProfile.visible ? imgProfile.width : 0) - 40)
|
||||
wrapMode: TextEdit.Wrap
|
||||
textFormat: Text.RichText
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: rowBottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
|
||||
Label {
|
||||
Label { // TIMESTAMP
|
||||
id: ts
|
||||
color: "#FFFFFF"
|
||||
font.pixelSize: 10
|
||||
|
@ -82,13 +99,15 @@ RowLayout {
|
|||
leftPadding: 10
|
||||
}
|
||||
|
||||
Label {
|
||||
Label { text: dummy.width+", "+root.width }
|
||||
|
||||
Label { // MESSAGE ACKNOWLEDGMENT
|
||||
id: ack
|
||||
color: "#FFFFFF"
|
||||
font.pixelSize: 10
|
||||
anchors.right: parent.right
|
||||
font.family: "FontAwesome"
|
||||
text: from == "me" ? awesome.icons.fa_ellipsis_h : ""
|
||||
text: from == "me" ? awesome.icons.fa_ellipsis_h : displayname
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -11,7 +11,13 @@ ColumnLayout {
|
|||
Layout.fillWidth: true
|
||||
|
||||
|
||||
Flickable {
|
||||
StackToolbar {
|
||||
text: "Sarah Jamie Lewis"
|
||||
|
||||
aux.onClicked: theStack.pane = theStack.userProfilePane
|
||||
}
|
||||
|
||||
Flickable { // THE MESSAGE LIST ITSELF
|
||||
id: sv
|
||||
clip: true
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
|
@ -32,12 +38,14 @@ ColumnLayout {
|
|||
messagesModel.clear()
|
||||
}
|
||||
|
||||
onAppendMessage: function(from, message, mid, ts) {
|
||||
onAppendMessage: function(from, message, displayname, mid, ts, source) {
|
||||
messagesModel.append({
|
||||
"f": from,
|
||||
"m": parse(message, 12),
|
||||
"d": displayname,
|
||||
"i": mid,
|
||||
"t": ts
|
||||
"t": ts,
|
||||
"src": source
|
||||
})
|
||||
|
||||
if (sv.contentY + sv.height >= sv.contentHeight - colMessages.height && sv.contentHeight > sv.height) {
|
||||
|
@ -67,8 +75,10 @@ ColumnLayout {
|
|||
delegate: Message {
|
||||
from: f
|
||||
message: m
|
||||
displayname: d
|
||||
messageID: i
|
||||
timestamp: t
|
||||
source: src
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,9 +108,7 @@ ColumnLayout {
|
|||
maximumFlickVelocity: 300
|
||||
|
||||
|
||||
ScrollBar.vertical: ScrollBar{
|
||||
policy: ScrollBar.AlwaysOn
|
||||
}
|
||||
ScrollBar.vertical: ScrollBar{}
|
||||
|
||||
TextEdit {
|
||||
id: txtMessage
|
||||
|
@ -116,7 +124,7 @@ ColumnLayout {
|
|||
|
||||
Keys.onReturnPressed: { // CTRL+ENTER = LINEBREAK
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
txtMessage.insert(txtMessage.cursorPosition, "\n")
|
||||
txtMessage.insert(txtMessage.cursorPosition, "<br>")
|
||||
} else if (event.modifiers == Qt.NoModifier) {
|
||||
btnSend.clicked()
|
||||
}
|
||||
|
@ -126,7 +134,7 @@ ColumnLayout {
|
|||
// while also stripping any other tag, including other images.
|
||||
// TODO: this probably breaks if people actually do want to paste html
|
||||
onTextChanged: {
|
||||
console.log("onTextChanged()")
|
||||
//console.log("onTextChanged()")
|
||||
|
||||
// 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
|
||||
|
@ -137,7 +145,7 @@ ColumnLayout {
|
|||
return
|
||||
}
|
||||
|
||||
console.log("1: " + txtMessage.getText(0, txtMessage.text.length))
|
||||
//console.log("1: " + txtMessage.getText(0, txtMessage.text.length))
|
||||
|
||||
// convert <img> tags back to their emoji form
|
||||
var nt = restoreEmoji(txtMessage.text)
|
||||
|
@ -146,15 +154,15 @@ ColumnLayout {
|
|||
txtMessage.text = nt
|
||||
}
|
||||
|
||||
console.log("2: " + txtMessage.getText(0, txtMessage.text.length))
|
||||
//console.log("2: " + txtMessage.getText(0, txtMessage.text.length))
|
||||
|
||||
// strip all HTML tags
|
||||
var theText = txtMessage.getText(0, txtMessage.text.length)
|
||||
console.log("3: " + theText)
|
||||
//console.log("3: " + theText)
|
||||
|
||||
// convert emoji back to <img> tags
|
||||
nt = parse(theText, 10)
|
||||
console.log("4: " + nt)
|
||||
//console.log("4: " + nt)
|
||||
|
||||
// if there were changes...
|
||||
if (nt != txtMessage.getText(0, txtMessage.text.length)) {
|
||||
|
|
Binary file not shown.
|
@ -2,6 +2,7 @@ import QtGraphicalEffects 1.0
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Controls.Material 2.0
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
ColumnLayout {
|
||||
|
@ -10,8 +11,8 @@ ColumnLayout {
|
|||
width: parent.width
|
||||
|
||||
property alias image: imgProfileImg.source
|
||||
property alias nick: lblNick.text
|
||||
property alias onion: lblOnion.text
|
||||
property string nick
|
||||
property string onion
|
||||
|
||||
|
||||
Item{ height: 6 }
|
||||
|
@ -93,23 +94,56 @@ ColumnLayout {
|
|||
}
|
||||
}
|
||||
|
||||
InplaceEditText { // USER NICKNAME
|
||||
id: lblNick
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: parent.width
|
||||
//InplaceEditText { // USER NICKNAME
|
||||
// id: lblNick
|
||||
// anchors.horizontalCenter: parent.horizontalCenter
|
||||
// width: parent.width
|
||||
//
|
||||
// onUpdated: {
|
||||
// gcd.updateNick(lblNick.text)
|
||||
// }
|
||||
//}
|
||||
|
||||
onUpdated: {
|
||||
gcd.updateNick(lblNick.text)
|
||||
Text {
|
||||
id: txtNick
|
||||
fontSizeMode: Text.HorizontalFit
|
||||
minimumPixelSize: 10
|
||||
font.pixelSize: 20
|
||||
width: 195
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: cbNick.editText
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
parent.visible = false
|
||||
cbNick.visible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ComboBox { // USER NICKNAME
|
||||
id: cbNick
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
popup.font.pixelSize: 12
|
||||
width: 200
|
||||
font.pixelSize: 20
|
||||
model: ["erinn", "erinn (open privacy)", "supergirl", "add new profile..."]
|
||||
visible: false
|
||||
|
||||
onCurrentTextChanged: {
|
||||
visible = false
|
||||
txtNick.visible = true
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this doesnt quite fit everything :{
|
||||
Label { // ONION ADDRESS
|
||||
id: lblOnion
|
||||
font.pixelSize: 6
|
||||
Layout.fillWidth: true
|
||||
padding: 3
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: "This is your address. You can give it out to people!\n" + onion
|
||||
}
|
||||
|
||||
RowLayout { // TOOLS FOR EDITING PROFILE
|
||||
|
@ -121,7 +155,7 @@ ColumnLayout {
|
|||
visible: false
|
||||
}
|
||||
|
||||
IconButton {
|
||||
IconButton { // COPY ONION ADDRESS BUTTON
|
||||
icon: awesome.icons.fa_clipboard
|
||||
label: "copy"
|
||||
|
||||
|
@ -133,20 +167,19 @@ ColumnLayout {
|
|||
}
|
||||
}
|
||||
|
||||
IconButton {
|
||||
IconButton { // SETTINGS BUTTON
|
||||
icon: awesome.icons.fa_cog
|
||||
//label: "settings"
|
||||
|
||||
onClicked: gcd.popup("not yet implemented, sorry :(")
|
||||
onClicked: theStack.pane = theStack.settingsPane
|
||||
}
|
||||
|
||||
IconButton {
|
||||
IconButton { // SIGN OUT BUTTON
|
||||
icon: awesome.icons.fa_sign_out
|
||||
//label: "sign out"
|
||||
|
||||
onClicked: {
|
||||
gcd.popup("not yet implemented, sorry :(")
|
||||
console.log(parse("💜", 20))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -199,7 +232,7 @@ ColumnLayout {
|
|||
|
||||
onUpdateMyProfile: function(_nick, _onion, _image) {
|
||||
nick = _nick
|
||||
onion = "This is your address. You should give it out to people!\n" + _onion
|
||||
onion = _onion
|
||||
image = _image
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,49 @@
|
|||
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 "controls" as Awesome
|
||||
import "../fonts/Twemoji.js" as T
|
||||
|
||||
Rectangle { // OVERHEAD BAR ON STACK PANE
|
||||
id: toolbar
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
height: 28
|
||||
color: "#EDEDED"
|
||||
|
||||
property alias text: lbl.text
|
||||
property alias aux: btnAux
|
||||
property alias back: btnBack
|
||||
|
||||
|
||||
IconButton {// BACK BUTTON
|
||||
id: btnBack
|
||||
icon: awesome.icons.fa_arrow_circle_o_left
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: 6
|
||||
visible: ratio >= 1.08 || windowItem.width < 500
|
||||
|
||||
onClicked: theStack.pane = theStack.emptyPane
|
||||
}
|
||||
|
||||
Label { // TEXT
|
||||
id: lbl
|
||||
font.pixelSize: 16
|
||||
text: "Sarah Jamie Lewis"
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
IconButton { // COG BUTTON
|
||||
id: btnAux
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 6
|
||||
icon: awesome.icons.fa_cog
|
||||
}
|
||||
}
|
Reference in New Issue