Reviewed-on: #347
This commit is contained in:
commit
4580d616de
8
go.mod
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
|
||||
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
98
go.sum
|
@ -1,73 +1,31 @@
|
|||
cwtch.im/cwtch v0.3.10 h1:akrIwsc1KnLbT3K6ZIFkhmA7kI62L03EWna7Ul1vszU=
|
||||
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
|
||||
const AppPassword = "be gay do crime"
|
||||
|
||||
var CwtchApp app.Application
|
||||
|
|
123
go/ui/gcd.go
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"`
|
||||
|
||||
_ 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) {
|
||||
this.gcd.DoIfProfileElse(this.profile, func() {
|
||||
this.gcd.DoIfConversationElse(onion, func() {
|
||||
this.gcd.TimelineInterface.AddMessage(this.gcd.TimelineInterface.num())
|
||||
pere.StoreMessage(onion, messageTxt, sent)
|
||||
this.gcd.TimelineInterface.RequestEIR()
|
||||
updateLastReadTime(onion)
|
||||
}, func() {
|
||||
pere.StoreMessage(onion, messageTxt, sent)
|
||||
})
|
||||
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 {
|
||||
if idx >= len(contact.Timeline.Messages) {
|
||||
log.Errorf("requested message[%d] of only %d", idx, len(contact.Timeline.Messages))
|
||||
} 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
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{
|
||||
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)
|
||||
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
|
||||
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
|
||||
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
|
||||
}
|
||||
|
|
Reference in New Issue