new message model #347
8
go.mod
|
@ -3,10 +3,16 @@ module cwtch.im/ui
|
|||
go 1.12
|
||||
|
||||
require (
|
||||
cwtch.im/cwtch v0.4.2
|
||||
cwtch.im/cwtch v0.4.3
|
||||
erinn marked this conversation as resolved
Outdated
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.3.1
|
||||
git.openprivacy.ca/openprivacy/log v1.0.1
|
||||
github.com/c-bata/go-prompt v0.2.3 // indirect
|
||||
github.com/google/go-cmp v0.4.0 // indirect
|
||||
github.com/gopherjs/gopherjs v0.0.0-20200209183636-89e6cbcd0b6d // indirect
|
||||
github.com/mattn/go-colorable v0.1.6 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/mattn/go-tty v0.0.3 // indirect
|
||||
github.com/pkg/term v0.0.0-20190109203006-aa71e9d9e942 // indirect
|
||||
github.com/therecipe/qt v0.0.0-20200126204426-5074eb6d8c41
|
||||
github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200126204426-5074eb6d8c41 // indirect
|
||||
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20200126204426-5074eb6d8c41 // indirect
|
||||
|
|
98
go.sum
|
@ -1,73 +1,31 @@
|
|||
cwtch.im/cwtch v0.3.10 h1:akrIwsc1KnLbT3K6ZIFkhmA7kI62L03EWna7Ul1vszU=
|
||||
erinn marked this conversation as resolved
dan
commented
did you delete the entire go.sum? did you delete the entire go.sum?
|
||||
cwtch.im/cwtch v0.3.10/go.mod h1:tmYeI2v0IEeBMbqzhcndXWZ2oyflhK4Afcf27+49rKU=
|
||||
cwtch.im/cwtch v0.3.11 h1:2+W2w9HDQowKwEGx4oRLywmn0NzQ0Sg9JEyBdR/V1mA=
|
||||
cwtch.im/cwtch v0.3.11/go.mod h1:PnMJb9CyzdrdbYjmL99pl6Nu34s6+lmeENVnGaY0hzk=
|
||||
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.15 h1:Z7fFREwXY728q2YmmwgHL357zAobrsWJ2oPkkGwzvo0=
|
||||
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/cwtch v0.4.0 h1:lhGQiYRBqSF0Pif9QttYVL4B1Oy1vc0v3cZejL7c7x4=
|
||||
cwtch.im/cwtch v0.4.0/go.mod h1:EvZQDbvXNu38m785dWF0MMljqJzwWrNTFT40HvoEAhI=
|
||||
cwtch.im/cwtch v0.4.1 h1:wjf/3Vw5fDByEwwnXqWrPtpKsXTLk0oz0PqNGYcR+MQ=
|
||||
cwtch.im/cwtch v0.4.1/go.mod h1:EvZQDbvXNu38m785dWF0MMljqJzwWrNTFT40HvoEAhI=
|
||||
cwtch.im/cwtch v0.4.2 h1:qIjTOwKkBf1tIsat27gXPriXSZXtKcTJ8Sf7E/2+GXc=
|
||||
cwtch.im/cwtch v0.4.2/go.mod h1:10gBkMSqAH95Pz4jTx5mpIHE+dkn+4kRC4BFTxWuQK8=
|
||||
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.17 h1:2jVZUe1a88tMI4aJPvRTO4Id3NN3PsM62cT5lntEChk=
|
||||
cwtch.im/tapir v0.1.17/go.mod h1:HzezugpEx+nZ3LdyDsl0w6n45IJYnOt8uqldkLWmaqs=
|
||||
cwtch.im/tapir v0.1.18 h1:Fs/jL9ZRyel/A1D/BYzIPEVQau8y5BJg44yA+GQDbSM=
|
||||
cwtch.im/tapir v0.1.18/go.mod h1:/IrAI6CBHfgzsfgRT8WHVb1P9fCCz7+45hfsdkKn8Zg=
|
||||
cwtch.im/cwtch v0.4.2-0.20201008200820-a2c5a28e092d h1:CuqoPJdfmKqvGnZhQtrv/9YqTRei3t06AvCGrCmD3gU=
|
||||
cwtch.im/cwtch v0.4.2-0.20201008200820-a2c5a28e092d/go.mod h1:EvZQDbvXNu38m785dWF0MMljqJzwWrNTFT40HvoEAhI=
|
||||
cwtch.im/cwtch v0.4.2-0.20201016053957-1933fb703fb0 h1:8d2hJyb6qupb9wS6px3734Hy1aHOrtwk4fpM1z/o3Tg=
|
||||
cwtch.im/cwtch v0.4.2-0.20201016053957-1933fb703fb0/go.mod h1:EvZQDbvXNu38m785dWF0MMljqJzwWrNTFT40HvoEAhI=
|
||||
cwtch.im/cwtch v0.4.3 h1:xf/jMW4+UJckzbYm5g9rPJKTP7fr6O6JC5pH1xjTs/A=
|
||||
cwtch.im/cwtch v0.4.3/go.mod h1:10gBkMSqAH95Pz4jTx5mpIHE+dkn+4kRC4BFTxWuQK8=
|
||||
cwtch.im/tapir v0.2.0 h1:7MkoR5+uEuPW34/O0GZRidnIjq/01Cfm8nl5IRuqpGc=
|
||||
cwtch.im/tapir v0.2.0/go.mod h1:xzzZ28adyUXNkYL1YodcHsAiTt3IJ8Loc29YVn9mIEQ=
|
||||
git.openprivacy.ca/openprivacy/bine v0.0.3 h1:PSHUmNqaW7BZUX8n2eTDeNbjsuRe+t5Ae0Og+P+jDM0=
|
||||
git.openprivacy.ca/openprivacy/bine v0.0.3/go.mod h1:13ZqhKyqakDsN/ZkQkIGNULsmLyqtXc46XBcnuXm/mU=
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.1.0/go.mod h1:4P8mirZZslKbo2zBrXXVjgEdqGwHo/6qoFBwFQW6d6E=
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.1.1 h1:hKxBOmxP7Jdu3K1BJ93mRtKNiWUoP6YHt/o2snE2Z0w=
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.1.1/go.mod h1:4P8mirZZslKbo2zBrXXVjgEdqGwHo/6qoFBwFQW6d6E=
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.1.2 h1:Bk8ul3+4/awpQGvskfLpp7/K3Lj8OAxBwlmQqeZy3Ok=
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.1.2/go.mod h1:4P8mirZZslKbo2zBrXXVjgEdqGwHo/6qoFBwFQW6d6E=
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.1.3 h1:iRGHS8RB4SZ9cjYK/yXt4R8PqQDVwwYJZ3iqe+w3IPE=
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.1.3/go.mod h1:4P8mirZZslKbo2zBrXXVjgEdqGwHo/6qoFBwFQW6d6E=
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.1.4 h1:/I9epvNNjM8rR/q5y9Y63D9/aPXpBFvngwNGLD8mvUk=
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.1.4/go.mod h1:4P8mirZZslKbo2zBrXXVjgEdqGwHo/6qoFBwFQW6d6E=
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.2.0 h1:dbZ5CRl11vg3BNHdzRKSlDP8OUtDB+mf6FkxMVf73qw=
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.2.0/go.mod h1:B7vzuVmChJtSKoh0ezph5vu6DQ0gIk0zHUNG6IgXCcA=
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.2.1 h1:oRL56TR9ZQnKkGkTIQ9wYbJ2IkOOsi/zLYExYiAS+sE=
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.2.1/go.mod h1:B7vzuVmChJtSKoh0ezph5vu6DQ0gIk0zHUNG6IgXCcA=
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.2.2 h1:CeuZB469xHMHxygxZD559CkRUAGR7ct4oeSlsAHQmKo=
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.2.2/go.mod h1:B7vzuVmChJtSKoh0ezph5vu6DQ0gIk0zHUNG6IgXCcA=
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.3.0 h1:e2EeV6CaMNwOb+PzAjF0hGCeOqAPagRaDL4en5ITf7U=
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.3.0/go.mod h1:s0/QhONuUqJQfYTAgUlu+ya7G3Ov6bKgpT5QkOhVxDI=
|
||||
git.openprivacy.ca/openprivacy/libricochet-go v1.0.11 h1:C7QFFzG0p5XKu0zcOIdLGwEpA9uU0BceBM7CfVK5D40=
|
||||
git.openprivacy.ca/openprivacy/libricochet-go v1.0.11/go.mod h1:yTMps/ZpYS+BNBBvANsNAft28FXrBvFHQauMYNWPrwE=
|
||||
git.openprivacy.ca/openprivacy/libricochet-go v1.0.13 h1:Z86uL9K47onznY1wP1P/wWfWMbbyvk6xnCp94R180os=
|
||||
git.openprivacy.ca/openprivacy/libricochet-go v1.0.13/go.mod h1:ZUuX1SOrgV4K18IEcp0hQJNPKszRr2oGb3UeK2iYe5U=
|
||||
git.openprivacy.ca/openprivacy/log v1.0.0 h1:Rvqm1weUdR4AOnJ79b1upHCc9vC/QF1rhSD2Um7sr1Y=
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.3.1 h1:d1t7rtzn+Fc63Z2M4mAGmGYU8hSeoZqglvfVBYkg0Lw=
|
||||
git.openprivacy.ca/openprivacy/connectivity v1.3.1/go.mod h1:s0/QhONuUqJQfYTAgUlu+ya7G3Ov6bKgpT5QkOhVxDI=
|
||||
git.openprivacy.ca/openprivacy/log v1.0.0/go.mod h1:gGYK8xHtndRLDymFtmjkG26GaMQNgyhioNS82m812Iw=
|
||||
git.openprivacy.ca/openprivacy/log v1.0.1 h1:NWV5oBTatvlSzUE6wtB+UQCulgyMOtm4BXGd34evMys=
|
||||
git.openprivacy.ca/openprivacy/log v1.0.1/go.mod h1:gGYK8xHtndRLDymFtmjkG26GaMQNgyhioNS82m812Iw=
|
||||
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI=
|
||||
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0=
|
||||
github.com/c-bata/go-prompt v0.2.3/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/cretz/bine v0.1.1-0.20200124154328-f9f678b84cca h1:Q2r7AxHdJwWfLtBZwvW621M3sPqxPc6ITv2j1FGsYpw=
|
||||
github.com/cretz/bine v0.1.1-0.20200124154328-f9f678b84cca/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20191106031601-ce3c9ade29de h1:F7WD09S8QB4LrkEpka0dFPLSotH11HRpCsLIbIcJ7sU=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20191106031601-ce3c9ade29de/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20200209183636-89e6cbcd0b6d h1:vr95xIx8Eg3vCzZPxY3rCwTfkjqNDt/FgVqTOk0WByk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20200209183636-89e6cbcd0b6d/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
|
||||
|
@ -77,27 +35,21 @@ github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uM
|
|||
github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0=
|
||||
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0=
|
||||
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/pkg/term v0.0.0-20190109203006-aa71e9d9e942/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
|
@ -105,41 +57,24 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
|||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/struCoder/pidusage v0.1.3/go.mod h1:pWBlW3YuSwRl6h7R5KbvA4N8oOqe9LjaKW5CwT1SPjI=
|
||||
github.com/therecipe/qt v0.0.0-20191101232336-18864661ae4f h1:06ICDSmDOBUC9jwgv44ngvyHzwudJNLa5H+rbCyDFRY=
|
||||
github.com/therecipe/qt v0.0.0-20191101232336-18864661ae4f/go.mod h1:SUUR2j3aE1z6/g76SdD6NwACEpvCxb3fvG82eKbD6us=
|
||||
github.com/therecipe/qt v0.0.0-20200126204426-5074eb6d8c41 h1:yBVcrpbaQYJBdKT2pxTdlL4hBE/eM4UPcyj9YpyvSok=
|
||||
github.com/therecipe/qt v0.0.0-20200126204426-5074eb6d8c41/go.mod h1:SUUR2j3aE1z6/g76SdD6NwACEpvCxb3fvG82eKbD6us=
|
||||
github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200126204426-5074eb6d8c41 h1:My9HYsfDI/fJPZGyilw6066buBiZ7pgKRRgAyvKK5lA=
|
||||
github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200126204426-5074eb6d8c41/go.mod h1:7m8PDYDEtEVqfjoUQc2UrFqhG0CDmoVJjRlQxexndFc=
|
||||
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20191002095216-73192f6811d0/go.mod h1:mH55Ek7AZcdns5KPp99O0bg+78el64YCYWHiQKrOdt4=
|
||||
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20191101232336-18864661ae4f h1:NLmalUtBOLr8mUB1/um4PO1KAx66AXlQF/lkrg5vTek=
|
||||
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20191101232336-18864661ae4f/go.mod h1:mH55Ek7AZcdns5KPp99O0bg+78el64YCYWHiQKrOdt4=
|
||||
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20200126204426-5074eb6d8c41 h1:jTzKrQ6EIPvKw1B9/wwoKJLrXF+ManMsXoUzufxAdsg=
|
||||
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20200126204426-5074eb6d8c41/go.mod h1:mH55Ek7AZcdns5KPp99O0bg+78el64YCYWHiQKrOdt4=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
|
||||
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72 h1:+ELyKg6m8UBf0nPFSqD0mi7zUfwPyXo23HNjMnXPz7w=
|
||||
golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200206161412-a0c6ece9d31a h1:aczoJ0HPNE92XKa7DrIzkNN6esOKO2TBwiiYoKcINhA=
|
||||
golang.org/x/crypto v0.0.0-20200206161412-a0c6ece9d31a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200210191831-6ca56c2f2e2b/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200210222208-86ce3cb69678 h1:wCWoJcFExDgyYx2m2hpHgwz8W3+FPdfldvIgzqDIhyg=
|
||||
golang.org/x/crypto v0.0.0-20200210222208-86ce3cb69678/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200320181102-891825fb96df h1:lDWgvUvNnaTnNBc/dwOty86cFeKoKWbwy2wQj0gIxbU=
|
||||
golang.org/x/crypto v0.0.0-20200320181102-891825fb96df/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200420104511-884d27f42877 h1:IhZPbxNd1UjBCaD5AfpSSbJTRlp+ZSuyuH5uoksNS04=
|
||||
golang.org/x/crypto v0.0.0-20200420104511-884d27f42877/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
|
@ -147,21 +82,17 @@ golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee h1:4yd7jl+vXjalO5ztz6Vc1V
|
|||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190420063019-afa5a82059c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200320181208-1c781a10960a h1:KaxWXSFrOaE2ptiOotI+zFdzHxBsg9MW6XfCv497IRo=
|
||||
golang.org/x/net v0.0.0-20200320181208-1c781a10960a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb h1:mUVeFHoDKis5nxCAzoAi7E8Ghb86EXh/RK6wtvJIqRY=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -169,16 +100,12 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a h1:XCr/YX7O0uxRkLq2k1ApNQMims9eCioF9UpzIPBDmuo=
|
||||
golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200320181252-af34d8274f85 h1:fD99hd4ciR6T3oPhr2EkmuKe9oHixHx9Hj/hND89j3g=
|
||||
golang.org/x/sys v0.0.0-20200320181252-af34d8274f85/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d h1:nc5K6ox/4lTFbMVSL9WRR81ixkcwXThoiF6yf+R9scA=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -187,21 +114,18 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190420181800-aa740d480789 h1:FF0rjo15h51+N6642mf5S3QuplmKo2aCrJUYkHTx85s=
|
||||
golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200420001825-978e26b7c37c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200625195345-7480c7b4547d h1:V1BGE5ZHrUIYZYNEm0i7jrPwSo3ks0HSn1TrartSqME=
|
||||
golang.org/x/tools v0.0.0-20200625195345-7480c7b4547d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"cwtch.im/ui/go/constants"
|
||||
"cwtch.im/ui/go/the"
|
||||
"cwtch.im/ui/go/ui"
|
||||
"encoding/hex"
|
||||
"git.openprivacy.ca/openprivacy/log"
|
||||
"strconv"
|
||||
"time"
|
||||
|
@ -54,14 +55,15 @@ func PeerHandler(onion string, uiManager ui.Manager, subscribed chan bool) {
|
|||
|
||||
case event.NewMessageFromPeer: //event.TimestampReceived, event.RemotePeer, event.Data
|
||||
ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampReceived])
|
||||
uiManager.AddMessage(e.Data[event.RemotePeer], e.Data[event.RemotePeer], e.Data[event.Data], false, e.EventID, ts, true)
|
||||
uiManager.StoreAndNotify(peer, e.Data[event.RemotePeer], e.Data[event.Data], ts, onion)
|
||||
|
||||
case event.PeerAcknowledgement:
|
||||
uiManager.Acknowledge(e.Data[event.EventID])
|
||||
uiManager.Acknowledge(e.Data[event.RemotePeer], e.Data[event.EventID])
|
||||
|
||||
case event.NewMessageFromGroup: //event.TimestampReceived, event.TimestampSent, event.Data, event.GroupID, event.RemotePeer
|
||||
ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampSent])
|
||||
uiManager.AddMessage(e.Data[event.GroupID], e.Data[event.RemotePeer], e.Data[event.Data], e.Data[event.RemotePeer] == peer.GetOnion(), e.Data[event.Signature], ts, true)
|
||||
uiManager.AddMessage(e.Data[event.GroupID], e.Data[event.RemotePeer], e.Data[event.Data], e.Data[event.RemotePeer] == peer.GetOnion(), hex.EncodeToString([]byte(e.Data[event.Signature])), ts, true)
|
||||
|
||||
case event.NewGroupInvite:
|
||||
gid, err := peer.ProcessInvite(e.Data[event.GroupInvite], e.Data[event.RemotePeer])
|
||||
group := peer.GetGroup(gid)
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"git.openprivacy.ca/openprivacy/connectivity"
|
||||
)
|
||||
|
||||
// Terrible, to be replaced when proper profile/password management comes in ~ 0.2
|
||||
// foundation block of the entire app. critical. never change, only obey
|
||||
erinn marked this conversation as resolved
Outdated
dan
commented
less accurate, it's now just the default password used in cases of "no encryption selected" for profiles and for the globals.ui file, so its... "safe"ish less accurate, it's now just the default password used in cases of "no encryption selected" for profiles and for the globals.ui file, so its... "safe"ish
dan
commented
thumbs up thumbs up
|
||||
const AppPassword = "be gay do crime"
|
||||
|
||||
var CwtchApp app.Application
|
||||
|
|
123
go/ui/gcd.go
|
@ -2,6 +2,7 @@ package ui
|
|||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"cwtch.im/cwtch/app"
|
||||
|
@ -12,13 +13,11 @@ import (
|
|||
"cwtch.im/ui/go/constants"
|
||||
"github.com/therecipe/qt/qml"
|
||||
|
||||
"encoding/base32"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"cwtch.im/ui/go/the"
|
||||
"encoding/base32"
|
||||
"git.openprivacy.ca/openprivacy/log"
|
||||
"github.com/therecipe/qt/core"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type GrandCentralDispatcher struct {
|
||||
|
@ -28,6 +27,7 @@ type GrandCentralDispatcher struct {
|
|||
Translator, OpaqueTranslator *core.QTranslator
|
||||
|
||||
uIManagers map[string]Manager // profile-onion : Manager
|
||||
TimelineInterface *MessageModel
|
||||
|
||||
GlobalSettings *GlobalSettings
|
||||
|
||||
|
@ -39,7 +39,7 @@ type GrandCentralDispatcher struct {
|
|||
|
||||
_ string `property:"os"`
|
||||
_ float32 `property:"themeScale,auto,changed"`
|
||||
_ string `property:"theme,auto,changed`
|
||||
_ string `property:"theme,auto,changed"`
|
||||
_ string `property:"locale,auto,changed"`
|
||||
_ string `property:"version"`
|
||||
_ string `property:"buildDate"`
|
||||
|
@ -65,8 +65,6 @@ type GrandCentralDispatcher struct {
|
|||
_ func(handle, key, value string) `signal:"UpdateContactAttribute"`
|
||||
|
||||
// messages pane stuff
|
||||
_ 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 int64, ackd bool, error bool) `signal:"PrependMessage"`
|
||||
_ func() `signal:"ClearMessages"`
|
||||
_ func() `signal:"ResetMessagePane"`
|
||||
_ func(mID string) `signal:"Acknowledged"`
|
||||
|
@ -95,7 +93,7 @@ type GrandCentralDispatcher struct {
|
|||
_ func(password string) `signal:"unlockProfiles,auto"`
|
||||
_ func() `signal:"reloadProfileList,auto"`
|
||||
_ func(onion string) `signal:"deleteProfile,auto"`
|
||||
_ 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"`
|
||||
// operating a profile
|
||||
_ func(message string) `signal:"sendMessage,auto"`
|
||||
|
@ -119,6 +117,8 @@ type GrandCentralDispatcher struct {
|
|||
_ func() `signal:"blockUnknownPeers,auto"`
|
||||
_ func(onion string) `signal:"storeHistoryForPeer,auto"`
|
||||
_ func(onion string) `signal:"deleteHistoryForPeer,auto"`
|
||||
// chat
|
||||
_ func(mID string) `slot:"peerAckAlert,auto"`
|
||||
dan
commented
acktest? acktest?
|
||||
|
||||
_ func(handle string) `signal:"requestServerSettings,auto"`
|
||||
|
||||
|
@ -174,6 +174,18 @@ func (this *GrandCentralDispatcher) DoIfProfile(profile string, fn func()) {
|
|||
}
|
||||
}
|
||||
|
||||
// Like DoIfProfile() but runs elseFn() if profile isn't the currently selected one in the UI
|
||||
func (this *GrandCentralDispatcher) DoIfProfileElse(profile string, fn func(), elseFn func()) {
|
||||
this.profileLock.Lock()
|
||||
defer this.profileLock.Unlock()
|
||||
|
||||
if this.m_selectedProfile == profile {
|
||||
fn()
|
||||
} else {
|
||||
elseFn()
|
||||
}
|
||||
}
|
||||
|
||||
func (this *GrandCentralDispatcher) selectedConversation() string {
|
||||
this.conversationLock.Lock()
|
||||
defer this.conversationLock.Unlock()
|
||||
|
@ -203,6 +215,18 @@ func (this *GrandCentralDispatcher) DoIfConversation(conversation string, fn fun
|
|||
}
|
||||
}
|
||||
|
||||
// like DoIfConversation() but
|
||||
func (this *GrandCentralDispatcher) DoIfConversationElse(conversation string, fn func(), elseFn func()) {
|
||||
this.conversationLock.Lock()
|
||||
defer this.conversationLock.Unlock()
|
||||
|
||||
if this.m_selectedConversation == conversation {
|
||||
fn()
|
||||
} else {
|
||||
elseFn()
|
||||
}
|
||||
}
|
||||
|
||||
func (this *GrandCentralDispatcher) sendMessage(message string) {
|
||||
if len(message) > 65530 {
|
||||
this.InvokePopup("message is too long")
|
||||
|
@ -223,19 +247,18 @@ func (this *GrandCentralDispatcher) sendMessage(message string) {
|
|||
}
|
||||
}
|
||||
|
||||
mID, err := the.Peer.SendMessageToGroupTracked(this.SelectedConversation(), message)
|
||||
|
||||
this.GetUiManager(this.selectedProfile()).AddMessage(this.SelectedConversation(), "me", message, true, mID, time.Now(), false)
|
||||
this.TimelineInterface.AddMessage(this.TimelineInterface.num())
|
||||
_, err := the.Peer.SendMessageToGroupTracked(this.SelectedConversation(), message)
|
||||
this.TimelineInterface.RequestEIR()
|
||||
|
||||
if err != nil {
|
||||
this.InvokePopup("failed to send message " + err.Error())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
to := this.SelectedConversation()
|
||||
mID := the.Peer.SendMessageToPeer(to, message)
|
||||
|
||||
this.GetUiManager(this.selectedProfile()).AddMessage(to, "me", message, true, mID, time.Now(), false)
|
||||
this.TimelineInterface.AddMessage(this.TimelineInterface.num())
|
||||
the.Peer.SendMessageToPeer(this.SelectedConversation(), message)
|
||||
this.TimelineInterface.RequestEIR()
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -262,8 +285,7 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
|
|||
this.UpdateContactStatus(group.GroupID, int(state), loading)
|
||||
this.requestGroupSettings(handle)
|
||||
|
||||
tl := group.GetTimeline()
|
||||
nick := getNick(handle)
|
||||
nick := GetNick(handle)
|
||||
updateLastReadTime(group.GroupID)
|
||||
if nick == "" {
|
||||
this.SetToolbarTitle(handle)
|
||||
|
@ -271,34 +293,6 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
|
|||
this.SetToolbarTitle(nick)
|
||||
}
|
||||
|
||||
go func() {
|
||||
// Janky hack to let the ui/qml respond to the status updates first before freezing under a deluge of new messages
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
for i := len(tl) - 1; i >= 0; i-- {
|
||||
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,
|
||||
)
|
||||
}
|
||||
}()
|
||||
|
||||
return
|
||||
} // ELSE LOAD CONTACT
|
||||
|
||||
|
@ -309,36 +303,10 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
|
|||
|
||||
var nick string
|
||||
if contact != nil {
|
||||
nick = getNick(contact.Onion)
|
||||
nick = GetNick(contact.Onion)
|
||||
}
|
||||
updateLastReadTime(contact.Onion)
|
||||
this.SetToolbarTitle(nick)
|
||||
|
||||
peer := the.Peer.GetContact(handle)
|
||||
messages := peer.Timeline.GetMessages()
|
||||
for i := range messages {
|
||||
from := messages[i].PeerID
|
||||
fromMe := messages[i].PeerID == the.Peer.GetOnion()
|
||||
if fromMe {
|
||||
from = "me"
|
||||
}
|
||||
|
||||
displayname := getNick(messages[i].PeerID)
|
||||
image := getProfilePic(messages[i].PeerID)
|
||||
|
||||
this.AppendMessage(
|
||||
from,
|
||||
messages[i].PeerID,
|
||||
displayname,
|
||||
messages[i].Message,
|
||||
image,
|
||||
string(messages[i].Signature),
|
||||
fromMe,
|
||||
messages[i].Timestamp.Unix(),
|
||||
messages[i].Acknowledged,
|
||||
messages[i].Error != "",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *GrandCentralDispatcher) requestSettings() {
|
||||
|
@ -357,7 +325,7 @@ func (this *GrandCentralDispatcher) requestPeerSettings(handle string) {
|
|||
return
|
||||
}
|
||||
|
||||
name := getNick(contact.Onion)
|
||||
name := GetNick(contact.Onion)
|
||||
|
||||
// Todo: Move to profile settings
|
||||
//blockunkownpeers, _ := the.Peer.GetAttribute(attr.GetPeerScope(constants.BlockUnknownPeersSetting))
|
||||
|
@ -417,13 +385,13 @@ func (this *GrandCentralDispatcher) requestGroupSettings(groupID string) {
|
|||
return
|
||||
}
|
||||
|
||||
nick := getNick(groupID)
|
||||
nick := GetNick(groupID)
|
||||
invite, _ := the.Peer.ExportGroup(groupID)
|
||||
|
||||
contactaddrs := the.Peer.GetContacts()
|
||||
contactnames := make([]string, len(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)
|
||||
status := connections.ConnectionStateToType[group.State]
|
||||
|
@ -756,3 +724,8 @@ func (this *GrandCentralDispatcher) deleteProfile(onion string) {
|
|||
log.Infof("deleteProfile %v\n", onion)
|
||||
the.CwtchApp.DeletePeer(onion)
|
||||
}
|
||||
|
||||
func (this *GrandCentralDispatcher) peerAckAlert(mID string) {
|
||||
idx, _ := strconv.Atoi(mID)
|
||||
this.TimelineInterface.EditMessage(idx)
|
||||
}
|
|
@ -4,6 +4,7 @@ import (
|
|||
"cwtch.im/cwtch/app"
|
||||
"cwtch.im/cwtch/model"
|
||||
"cwtch.im/cwtch/model/attr"
|
||||
"cwtch.im/cwtch/peer"
|
||||
"cwtch.im/cwtch/protocol/connections"
|
||||
"cwtch.im/ui/go/constants"
|
||||
"cwtch.im/ui/go/the"
|
||||
|
@ -62,7 +63,7 @@ func getWithSetDefault(id string, key string, defaultVal string) string {
|
|||
return val
|
||||
}
|
||||
|
||||
func getNick(id string) string {
|
||||
func GetNick(id string) string {
|
||||
if isGroup(id) {
|
||||
nick, exists := the.Peer.GetGroupAttribute(id, attr.GetLocalScope(constants.Name))
|
||||
if !exists || nick == "" {
|
||||
|
@ -100,8 +101,8 @@ func profilePicRelativize(filename string) string {
|
|||
return parts[len(parts)-1]
|
||||
}
|
||||
|
||||
// getProfilePic returns a string path to an image to display for hte given peer/group id
|
||||
func getProfilePic(id string) string {
|
||||
// GetProfilePic returns a string path to an image to display for hte given peer/group id
|
||||
func GetProfilePic(id string) string {
|
||||
if isGroup(id) {
|
||||
if picVal, exists := the.Peer.GetGroupAttribute(id, attr.GetLocalScope(constants.Picture)); exists {
|
||||
pic, err := StringToImage(picVal)
|
||||
|
@ -202,7 +203,7 @@ type manager struct {
|
|||
// manager also performs call filtering based on UI state: users of manager can safely always call it on events and not have to worry about weather the relevant ui is active
|
||||
// ie: you can always safely call AddMessage even if in the ui a different profile is selected. manager will check with gcd, and if the correct conditions are not met, it will not call on gcd to update the ui incorrectly
|
||||
type Manager interface {
|
||||
Acknowledge(mID string)
|
||||
Acknowledge(handle, mID string)
|
||||
AddContact(Handle string)
|
||||
AddSendMessageError(peer string, signature string, err string)
|
||||
AddMessage(handle string, from string, message string, fromMe bool, messageID string, timestamp time.Time, Acknowledged bool)
|
||||
|
@ -215,6 +216,10 @@ type Manager interface {
|
|||
UpdateContactAttribute(handle, key, value string)
|
||||
|
||||
ChangePasswordResponse(error bool)
|
||||
|
||||
AboutToAddMessage()
|
||||
MessageJustAdded()
|
||||
StoreAndNotify(peer.CwtchPeer, string, string, time.Time, string)
|
||||
}
|
||||
|
||||
// NewManager returns a new Manager interface for a profile to the gcd
|
||||
|
@ -223,9 +228,11 @@ func NewManager(profile string, gcd *GrandCentralDispatcher) Manager {
|
|||
}
|
||||
|
||||
// Acknowledge acknowledges the given message id in the UI
|
||||
func (this *manager) Acknowledge(mID string) {
|
||||
func (this *manager) Acknowledge(handle, mID string) {
|
||||
this.gcd.DoIfProfile(this.profile, func() {
|
||||
this.gcd.Acknowledged(mID)
|
||||
this.gcd.DoIfConversation(handle, func(){
|
||||
this.gcd.PeerAckAlert(mID)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -246,9 +253,9 @@ func (this *manager) AddContact(handle string) {
|
|||
if group != nil {
|
||||
lastRead := initLastReadTime(group.GroupID)
|
||||
unread := countUnread(group.Timeline.GetMessages(), lastRead)
|
||||
picture := getProfilePic(handle)
|
||||
picture := GetProfilePic(handle)
|
||||
|
||||
this.gcd.AddContact(handle, getNick(handle), picture, unread, int(connections.ConnectionStateToType[group.State]), string(model.AuthApproved), false, getLastMessageTime(&group.Timeline))
|
||||
this.gcd.AddContact(handle, GetNick(handle), picture, unread, int(connections.ConnectionStateToType[group.State]), string(model.AuthApproved), false, getLastMessageTime(&group.Timeline))
|
||||
}
|
||||
return
|
||||
} else if !isPeer(handle) {
|
||||
|
@ -261,9 +268,9 @@ func (this *manager) AddContact(handle string) {
|
|||
if contact != nil {
|
||||
lastRead := initLastReadTime(contact.Onion)
|
||||
unread := countUnread(contact.Timeline.GetMessages(), lastRead)
|
||||
picture := getProfilePic(handle)
|
||||
picture := GetProfilePic(handle)
|
||||
|
||||
this.gcd.AddContact(handle, getNick(handle), picture, unread, int(connections.ConnectionStateToType[contact.State]), string(contact.Authorization), false, getLastMessageTime(&contact.Timeline))
|
||||
this.gcd.AddContact(handle, GetNick(handle), picture, unread, int(connections.ConnectionStateToType[contact.State]), string(contact.Authorization), false, getLastMessageTime(&contact.Timeline))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -280,25 +287,41 @@ func (this *manager) AddSendMessageError(peer string, signature string, err stri
|
|||
})
|
||||
}
|
||||
|
||||
func (this *manager) AboutToAddMessage() {
|
||||
this.gcd.TimelineInterface.AddMessage(this.gcd.TimelineInterface.num())
|
||||
}
|
||||
|
||||
func (this *manager) MessageJustAdded() {
|
||||
this.gcd.TimelineInterface.RequestEIR()
|
||||
}
|
||||
|
||||
func (this *manager) StoreAndNotify(pere peer.CwtchPeer, onion string, messageTxt string, sent time.Time, profileOnion string) {
|
||||
erinn marked this conversation as resolved
Outdated
dan
commented
`pere` typo
erinn
commented
no it's the variable name version of Père aka Father CwtchPeer, preventer of naming conflicts with the peer library no it's the variable name version of Père aka Father CwtchPeer, preventer of naming conflicts with the peer library
|
||||
this.gcd.DoIfProfileElse(this.profile, func() {
|
||||
this.gcd.DoIfConversationElse(onion, func() {
|
||||
this.gcd.TimelineInterface.AddMessage(this.gcd.TimelineInterface.num())
|
||||
erinn marked this conversation as resolved
Outdated
dan
commented
Re: the comment below, since it's time based, maybe this call to updateLastReadTime() should be called after the message is added since num message new is calculated based on time? and if its updated before the message is added.. Re: the comment below, since it's time based, maybe this call to updateLastReadTime() should be called after the message is added since num message new is calculated based on time? and if its updated before the message is added..
erinn
commented
👍 :+1:
|
||||
pere.StoreMessage(onion, messageTxt, sent)
|
||||
this.gcd.TimelineInterface.RequestEIR()
|
||||
updateLastReadTime(onion)
|
||||
}, func() {
|
||||
pere.StoreMessage(onion, messageTxt, sent)
|
||||
erinn marked this conversation as resolved
Outdated
dan
commented
updateLastReadTime(onion) - sets the conversation's last read time to now (shouldbe called when the conversation is opened and or open, clearing notifications. we do it at Load messages so all the old ones aren't 1000 notifications in the conversation row bubble. but this is the else? so the conversation isn't open, so we dont want to update the lastReadTime here right? updateLastReadTime(onion) - sets the conversation's last read time to now (shouldbe called when the conversation is opened and or open, clearing notifications. we do it at Load messages so all the old ones aren't 1000 notifications in the conversation row bubble. but this is the else? so the conversation isn't open, so we dont want to update the lastReadTime here right?
erinn
commented
yep you're right good catch (i was thinking of it as "updateMostRecentMessageArrivalTime" for some reason) yep you're right good catch (i was thinking of it as "updateMostRecentMessageArrivalTime" for some reason)
|
||||
})
|
||||
this.gcd.IncContactUnreadCount(onion)
|
||||
}, func() {
|
||||
the.CwtchApp.GetPeer(profileOnion).StoreMessage(onion, messageTxt, sent)
|
||||
})
|
||||
}
|
||||
|
||||
// AddMessage adds a message to the message pane for the supplied conversation if it is active
|
||||
func (this *manager) AddMessage(handle string, from string, message string, fromMe bool, messageID string, timestamp time.Time, Acknowledged bool) {
|
||||
this.gcd.DoIfProfile(this.profile, func() {
|
||||
|
||||
nick := getNick(handle)
|
||||
image := getProfilePic(handle)
|
||||
|
||||
// If we have this group loaded already
|
||||
this.gcd.DoIfConversation(handle, func() {
|
||||
updateLastReadTime(handle)
|
||||
// If the message is not from the user then add it, otherwise, just acknowledge.
|
||||
if !fromMe {
|
||||
this.gcd.AppendMessage(handle, from, nick, message, image, messageID, fromMe, timestamp.Unix(), false, false)
|
||||
if !fromMe || !Acknowledged {
|
||||
this.gcd.TimelineInterface.AddMessage(this.gcd.TimelineInterface.num()-1)
|
||||
this.gcd.TimelineInterface.RequestEIR()
|
||||
} else {
|
||||
if !Acknowledged {
|
||||
this.gcd.AppendMessage(handle, from, nick, message, image, messageID, fromMe, timestamp.Unix(), false, false)
|
||||
} else {
|
||||
this.gcd.Acknowledged(messageID)
|
||||
}
|
||||
this.gcd.Acknowledged(messageID)
|
||||
}
|
||||
})
|
||||
this.gcd.IncContactUnreadCount(handle)
|
||||
|
@ -312,14 +335,14 @@ func (this *manager) ReloadProfiles() {
|
|||
// UpdateContactDisplayName updates a contact's display name in the contact list and conversations
|
||||
func (this *manager) UpdateContactDisplayName(handle string) {
|
||||
this.gcd.DoIfProfile(this.profile, func() {
|
||||
this.gcd.UpdateContactDisplayName(handle, getNick(handle))
|
||||
this.gcd.UpdateContactDisplayName(handle, GetNick(handle))
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateContactPicture updates a contact's picture in the contact list and conversations
|
||||
func (this *manager) UpdateContactPicture(handle string) {
|
||||
this.gcd.DoIfProfile(this.profile, func() {
|
||||
this.gcd.UpdateContactPicture(handle, getProfilePic(handle))
|
||||
this.gcd.UpdateContactPicture(handle, GetProfilePic(handle))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
package ui
|
||||
|
||||
import (
|
||||
"cwtch.im/cwtch/model"
|
||||
"cwtch.im/ui/go/the"
|
||||
"encoding/hex"
|
||||
"git.openprivacy.ca/openprivacy/log"
|
||||
"github.com/therecipe/qt/core"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type MessageModel struct {
|
||||
core.QAbstractTableModel
|
||||
|
||||
ackIdx int
|
||||
handle string
|
||||
_ func(string) `signal:"setHandle,auto"`
|
||||
|
||||
_ map[int]*core.QByteArray `property:"roles"`
|
||||
_ func() `constructor:"init"`
|
||||
|
||||
_ func(int) `signal:"addMessage,auto"`
|
||||
_ func(int) `signal:"editMessage,auto"`
|
||||
_ func() `signal:"requestEIR,auto"`
|
||||
|
||||
_ func(string) string `slot:"getNick,auto"`
|
||||
_ func(string) string `slot:"getImage,auto"`
|
||||
}
|
||||
|
||||
type MessageWrapper struct {
|
||||
model.Message
|
||||
core.QObject
|
||||
|
||||
Timestamp int64
|
||||
PeerID string
|
||||
Acknowledged bool
|
||||
RawMessage string
|
||||
Error string
|
||||
Day string
|
||||
Signature string
|
||||
_ bool `property:"ackd"`
|
||||
}
|
||||
|
||||
func (this *MessageModel) Handle() string{
|
||||
return this.handle
|
||||
}
|
||||
|
||||
func (this *MessageModel) setHandle(handle string) {
|
||||
this.handle = handle
|
||||
}
|
||||
|
||||
|
||||
func (this *MessageModel) init() {
|
||||
mdt := reflect.TypeOf([]MessageWrapper{}).Elem()
|
||||
roles := make(map[int]*core.QByteArray)
|
||||
for i := 0; i < mdt.NumField(); i++ {
|
||||
if mdt.Field(i).Name == "Acknowledged" {
|
||||
this.ackIdx = int(core.Qt__UserRole) + 1 + i
|
||||
}
|
||||
roles[int(core.Qt__UserRole) + 1 + i] = core.NewQByteArray2(mdt.Field(i).Name, -1)
|
||||
}
|
||||
roles[int(core.Qt__DisplayRole)] = core.NewQByteArray2("display", -1)
|
||||
this.SetRoles(roles)
|
||||
|
||||
this.ConnectData(this.data)
|
||||
this.ConnectRowCount(this.rowCount)
|
||||
this.ConnectColumnCount(this.columnCount)
|
||||
this.ConnectHeaderData(this.headerData)
|
||||
this.ConnectRoleNames(this.roleNames)
|
||||
}
|
||||
|
||||
func (this *MessageModel) roleNames() map[int]*core.QByteArray {
|
||||
return this.Roles()
|
||||
}
|
||||
|
||||
func (this *MessageModel) isGroup() bool {
|
||||
return len(this.Handle()) == 32
|
||||
}
|
||||
|
||||
func (this *MessageModel) getNick(handle string) string {
|
||||
return GetNick(handle)
|
||||
}
|
||||
|
||||
func (this *MessageModel) getImage(handle string) string {
|
||||
return GetProfilePic(handle)
|
||||
}
|
||||
|
||||
func (this *MessageModel) num() int {
|
||||
if this.Handle() == "" || the.Peer == nil {
|
||||
log.Debugf("MessageModel.num: early returning 0")
|
||||
return 0
|
||||
}
|
||||
|
||||
if this.isGroup() {
|
||||
group := the.Peer.GetGroup(this.Handle())
|
||||
if group != nil {
|
||||
return len(group.Timeline.Messages) + len(group.UnacknowledgedMessages)
|
||||
}
|
||||
} else {
|
||||
contact := the.Peer.GetContact(this.Handle())
|
||||
if contact != nil {
|
||||
return len(contact.Timeline.Messages)
|
||||
}
|
||||
}
|
||||
|
||||
log.Warnf("MessageModel.num: group/contact was nil, returning 0")
|
||||
return 0
|
||||
}
|
||||
|
||||
func (this *MessageModel) getMessage(idx int) *MessageWrapper {
|
||||
modelmsg := model.Message{Message:"[an unexpected cwtch error occurred]"}
|
||||
var ackd bool
|
||||
|
||||
if this.isGroup() {
|
||||
group := the.Peer.GetGroup(this.Handle())
|
||||
if idx >= len(group.Timeline.Messages) {
|
||||
modelmsg = group.UnacknowledgedMessages[idx - len(group.Timeline.Messages)]
|
||||
} else {
|
||||
modelmsg = group.Timeline.Messages[idx]
|
||||
ackd = true
|
||||
}
|
||||
} else {
|
||||
if this.Handle() != "" && the.Peer != nil {
|
||||
contact := the.Peer.GetContact(this.Handle())
|
||||
if contact != nil {
|
||||
erinn marked this conversation as resolved
Outdated
dan
commented
error? error?
|
||||
if idx >= len(contact.Timeline.Messages) {
|
||||
log.Errorf("requested message[%d] of only %d", idx, len(contact.Timeline.Messages))
|
||||
erinn marked this conversation as resolved
Outdated
dan
commented
modelmsg = someDummy template? otherwise the return statement below will segfault? modelmsg = someDummy template? otherwise the return statement below will segfault?
|
||||
} else {
|
||||
modelmsg = contact.Timeline.Messages[idx]
|
||||
ackd = modelmsg.Acknowledged
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &MessageWrapper {
|
||||
Message: modelmsg,
|
||||
Timestamp: modelmsg.Timestamp.Unix(),
|
||||
RawMessage: modelmsg.Message,
|
||||
PeerID: modelmsg.PeerID,
|
||||
Error: modelmsg.Error,
|
||||
Acknowledged: ackd,
|
||||
Day: modelmsg.Timestamp.Format("January 2, 2006"),
|
||||
Signature: hex.EncodeToString(modelmsg.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
func (this *MessageModel) data(index *core.QModelIndex, role int) *core.QVariant {
|
||||
if !index.IsValid() {
|
||||
return core.NewQVariant()
|
||||
}
|
||||
if index.Row() >= this.num() {
|
||||
return core.NewQVariant()
|
||||
}
|
||||
|
||||
if role == int(core.Qt__DisplayRole) {
|
||||
role = index.Column() + int(core.Qt__UserRole) + 1
|
||||
}
|
||||
|
||||
// modelData-element [role]-field value (aka the data ~_~)
|
||||
mderfv := reflect.ValueOf(*this.getMessage(index.Row())).Field(role - int(core.Qt__UserRole) - 1)
|
||||
typeStr := reflect.TypeOf([]MessageWrapper{}).Elem().Field(role - int(core.Qt__UserRole) - 1).Type.String()
|
||||
if typeStr == "string" {
|
||||
return core.NewQVariant1(mderfv.String())
|
||||
} else if strings.HasPrefix(typeStr, "int") {
|
||||
return core.NewQVariant1(mderfv.Int())
|
||||
} else if strings.HasPrefix(typeStr, "float") {
|
||||
return core.NewQVariant1(mderfv.Float())
|
||||
} else if typeStr == "bool" {
|
||||
return core.NewQVariant1(mderfv.Bool())
|
||||
}
|
||||
|
||||
return core.NewQVariant1("unknown type " + typeStr)
|
||||
}
|
||||
|
||||
func (this *MessageModel) headerData(section int, orientation core.Qt__Orientation, role int) *core.QVariant {
|
||||
if role != int(core.Qt__DisplayRole) || orientation == core.Qt__Vertical {
|
||||
return this.HeaderDataDefault(section, orientation, role)
|
||||
}
|
||||
|
||||
mdt := reflect.TypeOf([]MessageWrapper{}).Elem()
|
||||
return core.NewQVariant12(mdt.Field(section).Name)
|
||||
}
|
||||
|
||||
func (this *MessageModel) rowCount(parent *core.QModelIndex) int {
|
||||
return this.num()
|
||||
}
|
||||
|
||||
func (this *MessageModel) columnCount(parent *core.QModelIndex) int {
|
||||
return reflect.TypeOf(MessageWrapper{}).NumField()
|
||||
}
|
||||
|
||||
// perform this.BeginInsertRows() on the gui thread
|
||||
// important:
|
||||
// 1. idx MUST be set to this.num()'s value *before* calling addMessage()
|
||||
// 2. insert the message yourself
|
||||
// 3. this.RequestEIR() *must* be called afterward
|
||||
func (this *MessageModel) addMessage(idx int) {
|
||||
this.BeginInsertRows(core.NewQModelIndex(), idx, idx)
|
||||
}
|
||||
|
||||
// perform this.EndInsertRows() on the gui thread after an AddMessage()
|
||||
func (this *MessageModel) requestEIR() {
|
||||
this.EndInsertRows()
|
||||
}
|
||||
|
||||
// notify the gui that the message acknowledgement at index idx has been modified
|
||||
func (this *MessageModel) editMessage(idx int) {
|
||||
if idx < 0 || idx >= this.num() {
|
||||
log.Errorf("cant edit message %v. probably fine", idx)
|
||||
return
|
||||
}
|
||||
|
||||
log.Debugf("editMessage(%v, %v)", idx, this.ackIdx)
|
||||
indexObject := this.Index(idx, 0, core.NewQModelIndex())
|
||||
// replace third param with []int{} to update all attributes instead
|
||||
this.DataChanged(indexObject, indexObject, []int{this.ackIdx})
|
||||
}
|
14
main.go
|
@ -3,6 +3,8 @@ package main
|
|||
import (
|
||||
"crypto/rand"
|
||||
libapp "cwtch.im/cwtch/app"
|
||||
"cwtch.im/cwtch/event"
|
||||
"cwtch.im/cwtch/peer"
|
||||
"cwtch.im/cwtch/event/bridge"
|
||||
"cwtch.im/ui/go/handlers"
|
||||
os2 "cwtch.im/ui/go/os"
|
||||
|
@ -40,6 +42,16 @@ func init() {
|
|||
}
|
||||
|
||||
func main() {
|
||||
// suppress event.NewMessageFromPeer so we can handle it ourselves
|
||||
peer.DefaultEventsToHandle = []event.Type{
|
||||
erinn marked this conversation as resolved
Outdated
sarah
commented
delete delete
|
||||
event.EncryptedGroupMessage,
|
||||
event.PeerAcknowledgement,
|
||||
event.NewGroupInvite,
|
||||
event.PeerError,
|
||||
event.SendMessageToGroupError,
|
||||
event.NewGetValMessageFromPeer,
|
||||
}
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
filelogger, err := log.NewFile(log.LevelInfo, "cwtch_log.txt")
|
||||
if err == nil {
|
||||
|
@ -200,6 +212,8 @@ func mainUi(flagLocal bool, flagClientUI bool) {
|
|||
engine.SetNetworkAccessManagerFactory(factory)
|
||||
|
||||
engine.RootContext().SetContextProperty("gcd", gcd)
|
||||
gcd.TimelineInterface = ui.NewMessageModel(nil)
|
||||
erinn marked this conversation as resolved
Outdated
dan
commented
? ?
|
||||
engine.RootContext().SetContextProperty("mm", gcd.TimelineInterface)
|
||||
|
||||
var androidCwtchActivity = android.NewCwtchActivity(nil)
|
||||
engine.RootContext().SetContextProperty("androidCwtchActivity", androidCwtchActivity)
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 5c33d6ed2c46f5fe039fc6fee3cb690cb562cb23
|
||||
Subproject commit 12b7e51497868515401edc68be5514c020472da9
|
|
@ -8,19 +8,38 @@ import "../opaque" as Opaque
|
|||
import "../opaque/controls" as Awesome
|
||||
import "../opaque/fonts/Twemoji.js" as T
|
||||
import "../utils.js" as Utils
|
||||
import "../widgets"
|
||||
import "../widgets" as W
|
||||
import "../opaque/theme"
|
||||
|
||||
Overlay {
|
||||
W.Overlay {
|
||||
property bool loading
|
||||
|
||||
//horizontalPadding: 15 * gcd.themeScale
|
||||
|
||||
ListModel { // MESSAGE OBJECTS ARE STORED HERE ...
|
||||
id: messagesModel
|
||||
Connections {
|
||||
target: mm
|
||||
onRowsInserted: {
|
||||
if (messagesListView.atYEnd) thymer.running = true
|
||||
|
||||
//todo: this won't fire for non-active convos
|
||||
erinn marked this conversation as resolved
Outdated
sarah
commented
this still a todo? this still a todo?
erinn
commented
it's a bugfix i preserved. created #348 to track it it's a bugfix i preserved. created #348 to track it
erinn
commented
bug* bug*
|
||||
windowItem.alert(0)
|
||||
if (gcd.os == "android" && windowItem.activeFocusItem == null) {
|
||||
androidCwtchActivity.notification = "New Content"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// onRowsInserted is firing after the model is updated but before the delegate is inflated
|
||||
// causing positionViewAtEnd() to scroll to "just above the last message"
|
||||
// so we use this timer to delay scrolling by a few milliseconds
|
||||
Timer {
|
||||
id: thymer
|
||||
interval: 30
|
||||
onTriggered: {
|
||||
thymer.running = false
|
||||
messagesListView.positionViewAtEnd()
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: ListView {
|
||||
id: messagesListView
|
||||
|
@ -28,140 +47,85 @@ Overlay {
|
|||
Layout.fillWidth: true
|
||||
|
||||
width: parent.width
|
||||
model: messagesModel
|
||||
model: mm
|
||||
spacing: 6
|
||||
|
||||
clip: true
|
||||
ScrollBar.vertical: Opaque.ScrollBar {}
|
||||
maximumFlickVelocity: 1250
|
||||
|
||||
delegate: Message {
|
||||
handle: _handle
|
||||
from: _from
|
||||
displayName: _displayName
|
||||
message: _message
|
||||
rawMessage: _rawMessage
|
||||
image: _image
|
||||
messageID: _mid
|
||||
fromMe: _fromMe
|
||||
timestamp: _ts
|
||||
ackd: _ackd
|
||||
error: _error
|
||||
calendarEvent: _handle == "calendar"
|
||||
section.delegate: sectionHeading
|
||||
section.property: "Day"
|
||||
|
||||
|
||||
delegate: W.Message {
|
||||
handle: PeerID
|
||||
from: PeerID
|
||||
displayName: mm.getNick(PeerID)
|
||||
message: JSON.parse(RawMessage).d
|
||||
rawMessage: RawMessage
|
||||
image: mm.getImage(PeerID)
|
||||
messageID: Signature
|
||||
fromMe: PeerID == gcd.selectedProfile
|
||||
timestamp: parseInt(Timestamp)
|
||||
ackd: Acknowledged
|
||||
error: Error
|
||||
calendarEvent: PeerID == "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
|
||||
}
|
||||
|
||||
Component {
|
||||
id: sectionHeading
|
||||
Rectangle {// ⟵ outer rect because anchors._Margin isnt supported here
|
||||
// with qt 5.15+ this↓ can be changed to...
|
||||
// required property string section
|
||||
property string txt: section
|
||||
color: Theme.backgroundMainColor
|
||||
width: parent.width
|
||||
height: texmet.height + 6 + 12 * gcd.themeScale
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
|
||||
Rectangle {
|
||||
opacity: 1
|
||||
erinn marked this conversation as resolved
Outdated
dan
commented
Most of the numbers in qml all tediuslyget * gcd.themeScale so the whole ui should scale appropriately Most of the numbers in qml all tediuslyget * gcd.themeScale so the whole ui should scale appropriately
|
||||
width: texmet.width + radius * 4 + 6
|
||||
height: texmet.height + 6
|
||||
color: Theme.messageFromOtherBackgroundColor
|
||||
radius: texmet.height / 2
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
|
||||
Text {
|
||||
id: txtDate
|
||||
// ... and this can be changed to
|
||||
// text: parent.parent.section
|
||||
text: parent.parent.txt
|
||||
font.pixelSize: Theme.chatSize * gcd.themeScale
|
||||
color: Theme.messageFromOtherTextColor
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: texmet
|
||||
text: txtDate.text
|
||||
font.pixelSize: Theme.chatSize * gcd.themeScale
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: gcd
|
||||
|
||||
onClearMessages: function() {
|
||||
messagesModel.clear()
|
||||
}
|
||||
|
||||
onAppendMessage: function(handle, from, displayName, message, image, mid, fromMe, ts, ackd, error) {
|
||||
var msg
|
||||
try {
|
||||
msg = JSON.parse(message)
|
||||
} catch (e) {
|
||||
msg = {"o": 1, "d": "(legacy message type) " + message}
|
||||
}
|
||||
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({
|
||||
"_handle": handle,
|
||||
"_from": from,
|
||||
"_displayName": displayName,
|
||||
"_message": msg.d,
|
||||
"_rawMessage":msg.d,
|
||||
"_image": image,
|
||||
"_mid": mid,
|
||||
"_fromMe": fromMe,
|
||||
"_ts": ts,
|
||||
"_ackd": ackd,
|
||||
"_error": error == true ? "this message failed to send" : "",
|
||||
})
|
||||
|
||||
messagesListView.positionViewAtEnd()
|
||||
|
||||
// If the window is out of focus, alert the user (makes taskbar light up)
|
||||
windowItem.alert(0)
|
||||
if (gcd.os == "android" && windowItem.activeFocusItem == null) {
|
||||
androidCwtchActivity.notification = "New Content"
|
||||
}
|
||||
}
|
||||
|
||||
onPrependMessage: function(handle, from, displayName, message, image, mid, fromMe, ts, ackd, error) {
|
||||
var msg
|
||||
try {
|
||||
msg = JSON.parse(message)
|
||||
} catch (e) {
|
||||
msg = {"o": 1, "d": "(legacy message type) " + message}
|
||||
}
|
||||
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, {
|
||||
"_handle": handle,
|
||||
"_from": from,
|
||||
"_displayName": displayName,
|
||||
"_message": msg.d,
|
||||
"_rawMessage":msg.d,
|
||||
"_image": image,
|
||||
"_mid": mid,
|
||||
"_fromMe": fromMe,
|
||||
"_ts": ts,
|
||||
"_ackd": ackd,
|
||||
"_error": error == true ? "this message failed to send" : "",
|
||||
})
|
||||
|
||||
messagesListView.positionViewAtEnd()
|
||||
messagesListView.model = null
|
||||
messagesListView.model = mm
|
||||
messagesListView.positionViewAtEnd()
|
||||
thymer.running = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -171,8 +135,6 @@ Overlay {
|
|||
var msg = JSON.stringify({"o":1, "d":messageText.replace(/\[\:newline\:\]/g,"\n")})
|
||||
gcd.sendMessage(msg)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -98,6 +98,7 @@ Opaque.PortraitRow {
|
|||
gcd.broadcast("ResetMessagePane")
|
||||
isActive = true
|
||||
theStack.pane = theStack.messagePane
|
||||
mm.setHandle(handle)
|
||||
gcd.loadMessagesPane(handle)
|
||||
badge = 0
|
||||
}
|
||||
|
|
will need to cut a new release in Cwtch and update this...