merge to master
the build was successful
Details
the build was successful
Details
This commit is contained in:
commit
78f4d96a9b
26
.drone.yml
26
.drone.yml
|
@ -14,15 +14,16 @@ pipeline:
|
||||||
- QT_DIR=/opt/Qt
|
- QT_DIR=/opt/Qt
|
||||||
- QT_DOCKER='true'
|
- QT_DOCKER='true'
|
||||||
- QT_API=5.13.0
|
- QT_API=5.13.0
|
||||||
|
- GO111MODULE=on
|
||||||
commands:
|
commands:
|
||||||
- export GOPATH=$GOPATH:/media/sf_GOPATH1/
|
|
||||||
- export PATH=$PATH:/home/user/work/bin:/media/sf_GOPATH1/bin
|
- export PATH=$PATH:/home/user/work/bin:/media/sf_GOPATH1/bin
|
||||||
- apt-get -qq update && apt-get --no-install-recommends -qq -y install ca-certificates curl git openssh-client
|
- apt-get -qq update && apt-get --no-install-recommends -qq -y install ca-certificates curl git openssh-client
|
||||||
- go get -d
|
- go mod download
|
||||||
- $QT_DIR/$QT_API/gcc_64/bin/lrelease ui.pro
|
- $QT_DIR/$QT_API/gcc_64/bin/lrelease ui.pro
|
||||||
- git fetch --tags
|
- git fetch --tags
|
||||||
- export VERSION=`git describe --tags`
|
- export VERSION=`git describe --tags`
|
||||||
- export BUILDDATE=`date +%G-%m-%d-%H-%M`
|
- export BUILDDATE=`date +%G-%m-%d-%H-%M`
|
||||||
|
- go mod vendor
|
||||||
- qtdeploy -ldflags "-X main.buildVer=$VERSION -X main.buildDate=$BUILDDATE" build linux
|
- qtdeploy -ldflags "-X main.buildVer=$VERSION -X main.buildDate=$BUILDDATE" build linux
|
||||||
- cp README.md deploy/linux
|
- cp README.md deploy/linux
|
||||||
- export FILENAME=cwtch-linux-$BUILDDATE.tar.gz
|
- export FILENAME=cwtch-linux-$BUILDDATE.tar.gz
|
||||||
|
@ -44,16 +45,18 @@ pipeline:
|
||||||
- QT_API=5.13.0
|
- QT_API=5.13.0
|
||||||
- ANDROID_NDK_DIR=/home/user/android-ndk-r18b
|
- ANDROID_NDK_DIR=/home/user/android-ndk-r18b
|
||||||
- ANDROID_SDK_DIR=/home/user/android-sdk-linux
|
- ANDROID_SDK_DIR=/home/user/android-sdk-linux
|
||||||
|
- GO111MODULE=on
|
||||||
commands:
|
commands:
|
||||||
- export GOPATH=$GOPATH:/media/sf_GOPATH1/
|
|
||||||
- export PATH=$PATH:/home/user/work/bin:/media/sf_GOPATH1/bin
|
- export PATH=$PATH:/home/user/work/bin:/media/sf_GOPATH1/bin
|
||||||
- apt-get -qq update && apt-get --no-install-recommends -qq -y install ca-certificates curl git
|
- apt-get -qq update && apt-get --no-install-recommends -qq -y install ca-certificates curl git
|
||||||
- find -iname 'moc*' | xargs rm
|
- rm -r vendor/
|
||||||
- find -iname 'rcc*' | xargs rm
|
- make clean
|
||||||
- go get -d
|
- go mod download
|
||||||
- export VERSION=`git describe --tags`
|
- export VERSION=`git describe --tags`
|
||||||
- export BUILDDATE=`date +%G-%m-%d-%H-%M`
|
- export BUILDDATE=`date +%G-%m-%d-%H-%M`
|
||||||
- qtdeploy -ldflags "-X main.buildVer=$VERSION -X main.buildDate=$BUILDDATE" build android
|
- go mod vendor
|
||||||
|
- qtsetup generate android
|
||||||
|
- qtdeploy -ldflags "-X main.buildVer=$VERSION -X main.buildDate=$BUILDDATE" build android
|
||||||
- cd deploy
|
- cd deploy
|
||||||
- export FILENAME=cwtch-android-$BUILDDATE.apk
|
- export FILENAME=cwtch-android-$BUILDDATE.apk
|
||||||
- cp android/build-debug.apk $FILENAME
|
- cp android/build-debug.apk $FILENAME
|
||||||
|
@ -69,15 +72,16 @@ pipeline:
|
||||||
- QT_DIR=/opt/Qt
|
- QT_DIR=/opt/Qt
|
||||||
- QT_DOCKER='true'
|
- QT_DOCKER='true'
|
||||||
- QT_API=5.13.0
|
- QT_API=5.13.0
|
||||||
|
- GO111MODULE=on
|
||||||
commands:
|
commands:
|
||||||
- export GOPATH=$GOPATH:/media/sf_GOPATH1/
|
|
||||||
- export PATH=$PATH:/home/user/work/bin:/media/sf_GOPATH1/bin
|
- export PATH=$PATH:/home/user/work/bin:/media/sf_GOPATH1/bin
|
||||||
- apt-get -qq update && apt-get --no-install-recommends -qq -y install ca-certificates curl git zip
|
- apt-get -qq update && apt-get --no-install-recommends -qq -y install ca-certificates curl git zip
|
||||||
- find -iname 'moc*' | xargs rm
|
- rm -r vendor
|
||||||
- find -iname 'rcc*' | xargs rm
|
- make clean
|
||||||
- go get -d
|
- go mod download
|
||||||
- export VERSION=`git describe --tags`
|
- export VERSION=`git describe --tags`
|
||||||
- export BUILDDATE=`date +%G-%m-%d-%H-%M`
|
- export BUILDDATE=`date +%G-%m-%d-%H-%M`
|
||||||
|
- go mod vendor
|
||||||
- qtdeploy -ldflags "-X main.buildVer=$VERSION -X main.buildDate=$BUILDDATE" build windows
|
- qtdeploy -ldflags "-X main.buildVer=$VERSION -X main.buildDate=$BUILDDATE" build windows
|
||||||
- cp README.md deploy/windows
|
- cp README.md deploy/windows
|
||||||
- cp -r windows/* deploy/windows
|
- cp -r windows/* deploy/windows
|
||||||
|
|
6
Makefile
6
Makefile
|
@ -1,9 +1,9 @@
|
||||||
.PHONY: all clean linux android
|
.PHONY: all clean linux android
|
||||||
all:
|
all: clean linux android
|
||||||
|
default: linux
|
||||||
default: all
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
rm -r vendor || true
|
||||||
find -type f -iname "moc*" | xargs rm
|
find -type f -iname "moc*" | xargs rm
|
||||||
find -iname "rcc*" | xargs rm
|
find -iname "rcc*" | xargs rm
|
||||||
|
|
||||||
|
|
|
@ -15,11 +15,11 @@ The UI is built using QT so you will need the development libraries and tools fo
|
||||||
|
|
||||||
This code relies on [therecipe/qt](https://github.com/therecipe/qt) before getting started consult the [Installation](https://github.com/therecipe/qt/wiki/Installation) and [Getting Started](https://github.com/therecipe/qt/wiki/Getting-Started) documentation to get that up and running. It will make building this much easier.
|
This code relies on [therecipe/qt](https://github.com/therecipe/qt) before getting started consult the [Installation](https://github.com/therecipe/qt/wiki/Installation) and [Getting Started](https://github.com/therecipe/qt/wiki/Getting-Started) documentation to get that up and running. It will make building this much easier.
|
||||||
|
|
||||||
We are aiming to use Go module support for versioning but it has some issues working with therecipe/qt so we aren't there yet. For now build with GO111MODULE=off using just the GOPATH for dependancies.
|
Cwtch UI uses the Go module system for dependancies
|
||||||
|
|
||||||
## Linux
|
## Linux
|
||||||
|
|
||||||
go get -d
|
go mod vendor
|
||||||
qtdeploy build linux
|
qtdeploy build linux
|
||||||
./deploy/linux/ui -local -debug 2>&1 | grep -v 'Detected anchors on an item that is managed by a layout.'
|
./deploy/linux/ui -local -debug 2>&1 | grep -v 'Detected anchors on an item that is managed by a layout.'
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ The grep statement filters out some QML noise.
|
||||||
|
|
||||||
We supply an arm-pie version of tor in `android/libs/armeabi-v7a` with the name `libtor.so`
|
We supply an arm-pie version of tor in `android/libs/armeabi-v7a` with the name `libtor.so`
|
||||||
|
|
||||||
go get -d
|
go mod vendor
|
||||||
qtdeploy -docker build android
|
qtdeploy -docker build android
|
||||||
adb install deploy/android/build-debug.apk
|
adb install deploy/android/build-debug.apk
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ We supply an arm-pie version of tor in `android/libs/armeabi-v7a` with the name
|
||||||
|
|
||||||
If all that is done, then check out cwtch.im/ui
|
If all that is done, then check out cwtch.im/ui
|
||||||
|
|
||||||
go get -d
|
go mod vendor
|
||||||
qtdeploy
|
qtdeploy
|
||||||
deploy/windows/ui
|
deploy/windows/ui
|
||||||
|
|
||||||
|
|
9
go.mod
9
go.mod
|
@ -3,14 +3,13 @@ module cwtch.im/ui
|
||||||
go 1.12
|
go 1.12
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cwtch.im/cwtch v0.3.0
|
cwtch.im/cwtch v0.3.8
|
||||||
git.openprivacy.ca/openprivacy/libricochet-go v1.0.6
|
git.openprivacy.ca/openprivacy/libricochet-go v1.0.8
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f // indirect
|
github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f // indirect
|
||||||
github.com/kr/pretty v0.1.0 // indirect
|
github.com/kr/pretty v0.1.0 // indirect
|
||||||
github.com/stretchr/testify v1.4.0 // indirect
|
github.com/stretchr/testify v1.4.0 // indirect
|
||||||
github.com/therecipe/qt v0.0.0-20191221221430-5e239f03fa53
|
github.com/therecipe/qt v0.0.0-20191101232336-18864661ae4f
|
||||||
github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200103041036-2b818d970888 // indirect
|
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20191002095216-73192f6811d0 // indirect; Required - do not delete or `go tidy` away
|
||||||
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20191221221430-5e239f03fa53 // indirect
|
|
||||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 // indirect
|
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 // indirect
|
||||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 // indirect
|
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 // indirect
|
||||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // indirect
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // indirect
|
||||||
|
|
36
go.sum
36
go.sum
|
@ -1,10 +1,10 @@
|
||||||
cwtch.im/cwtch v0.3.0 h1:RFZyc2m9BowFNdngBs7GcQE41w75jMp3Ku5zEE92v9I=
|
cwtch.im/cwtch v0.3.8 h1:QxuDu+sH5VIcLQZGGfah3zuseq02Iyqhm7O2+ATtA9M=
|
||||||
cwtch.im/cwtch v0.3.0/go.mod h1:8tmtp3c7fccWw9H7s9u6E8GD2PKI3ar21i0fjN8pzd0=
|
cwtch.im/cwtch v0.3.8/go.mod h1:/CAGNdgidvJ0sOfsWeU2hxlYCXv8usf6kspsfhG8gtQ=
|
||||||
cwtch.im/tapir v0.1.10 h1:V+TkmwXNd6gySZqlVw468wMYEkmDwMSyvhkkpOfUw7w=
|
cwtch.im/tapir v0.1.14 h1:lg+reZNT998l++4Q4RQBLXYv3ukqWffhI0Wed9RSjuA=
|
||||||
cwtch.im/tapir v0.1.10/go.mod h1:EuRYdVrwijeaGBQ4OijDDRHf7R2MDSypqHkSl5DxI34=
|
cwtch.im/tapir v0.1.14/go.mod h1:QwERb982YIes9UOxDqIthm1HZ1xy0YQetD2+XxDbg9Y=
|
||||||
git.openprivacy.ca/openprivacy/libricochet-go v1.0.4/go.mod h1:yMSG1gBaP4f1U+RMZXN85d29D39OK5s8aTpyVRoH5FY=
|
git.openprivacy.ca/openprivacy/libricochet-go v1.0.4/go.mod h1:yMSG1gBaP4f1U+RMZXN85d29D39OK5s8aTpyVRoH5FY=
|
||||||
git.openprivacy.ca/openprivacy/libricochet-go v1.0.6 h1:5o4K2qn3otEE1InC5v5CzU0yL7Wl7DhVp4s8H3K6mXY=
|
git.openprivacy.ca/openprivacy/libricochet-go v1.0.8 h1:HVoyxfivFaEtkfO5K3piD6oq6MQB1qGF5IB2EYXeCW8=
|
||||||
git.openprivacy.ca/openprivacy/libricochet-go v1.0.6/go.mod h1:yMSG1gBaP4f1U+RMZXN85d29D39OK5s8aTpyVRoH5FY=
|
git.openprivacy.ca/openprivacy/libricochet-go v1.0.8/go.mod h1:6I+vO9Aagv3/yUWv+e7A57H8tgXgR67FCjfSj9Pp970=
|
||||||
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI=
|
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/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/c-bata/go-prompt v0.2.3/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
|
||||||
|
@ -19,6 +19,10 @@ github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f h1:KMlcu9X58lhTA/KrfX8Bi1LQSO4pzoVjTiL3h4Jk+Zk=
|
github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f h1:KMlcu9X58lhTA/KrfX8Bi1LQSO4pzoVjTiL3h4Jk+Zk=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is=
|
||||||
|
github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s=
|
||||||
|
github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc=
|
||||||
|
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.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/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
|
@ -30,6 +34,8 @@ github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-tty v0.0.0-20190424173100-523744f04859/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
github.com/mattn/go-tty v0.0.0-20190424173100-523744f04859/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
||||||
|
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/pkg/term v0.0.0-20190109203006-aa71e9d9e942/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
|
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
@ -43,17 +49,11 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/struCoder/pidusage v0.1.2/go.mod h1:pWBlW3YuSwRl6h7R5KbvA4N8oOqe9LjaKW5CwT1SPjI=
|
github.com/struCoder/pidusage v0.1.2/go.mod h1:pWBlW3YuSwRl6h7R5KbvA4N8oOqe9LjaKW5CwT1SPjI=
|
||||||
github.com/therecipe/qt v0.0.0-20190824160953-615e084bab56 h1:CAFR/rHptsl8gEP6igtp6VbuQpPALEJ/B+gl9QkyFXU=
|
github.com/therecipe/qt v0.0.0-20191101232336-18864661ae4f h1:06ICDSmDOBUC9jwgv44ngvyHzwudJNLa5H+rbCyDFRY=
|
||||||
github.com/therecipe/qt v0.0.0-20190824160953-615e084bab56/go.mod h1:SUUR2j3aE1z6/g76SdD6NwACEpvCxb3fvG82eKbD6us=
|
github.com/therecipe/qt v0.0.0-20191101232336-18864661ae4f/go.mod h1:SUUR2j3aE1z6/g76SdD6NwACEpvCxb3fvG82eKbD6us=
|
||||||
github.com/therecipe/qt v0.0.0-20191221221430-5e239f03fa53 h1:vmHLq7TFJ0OQLZzJF0mnCQW6o7NKV319X4F9ImMcLv4=
|
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 v0.0.0-20191221221430-5e239f03fa53/go.mod h1:SUUR2j3aE1z6/g76SdD6NwACEpvCxb3fvG82eKbD6us=
|
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
|
||||||
github.com/therecipe/qt v0.0.0-20200103041036-2b818d970888 h1:kwDtZGIbjPGYzvs4Dk/4O4E2nnJugQkccLyfFUHpHk0=
|
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200103041036-2b818d970888 h1:GnH3hKsPT8vfSw6LQ6+gHoYdJw7Zd5bifdXzP/Z1tus=
|
|
||||||
github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200103041036-2b818d970888/go.mod h1:7m8PDYDEtEVqfjoUQc2UrFqhG0CDmoVJjRlQxexndFc=
|
|
||||||
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20191221221430-5e239f03fa53 h1:nnH71oC0mqkEFEZT8hxykAV+7/yQXial8gbJuxNQNdY=
|
|
||||||
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20191221221430-5e239f03fa53/go.mod h1:mH55Ek7AZcdns5KPp99O0bg+78el64YCYWHiQKrOdt4=
|
|
||||||
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20200103041036-2b818d970888 h1:4tZ5WKqMm1U6iOM3kaRvD+mndR5flF61YMXr7gxQ9TU=
|
|
||||||
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20200103041036-2b818d970888/go.mod h1:mH55Ek7AZcdns5KPp99O0bg+78el64YCYWHiQKrOdt4=
|
|
||||||
golang.org/x/crypto v0.0.0-20190128193316-c7b33c32a30b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20190128193316-c7b33c32a30b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
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-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||||
|
@ -69,6 +69,7 @@ golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA=
|
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA=
|
||||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
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/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
@ -78,7 +79,6 @@ golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
|
||||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
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-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
|
|
|
@ -1,135 +0,0 @@
|
||||||
package characters
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cwtch.im/cwtch/app/plugins"
|
|
||||||
"cwtch.im/cwtch/event"
|
|
||||||
"cwtch.im/ui/go/constants"
|
|
||||||
"cwtch.im/ui/go/cwutil"
|
|
||||||
"cwtch.im/ui/go/gobjects"
|
|
||||||
"cwtch.im/ui/go/gothings"
|
|
||||||
"cwtch.im/ui/go/the"
|
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
func AppEventListener(gcd *gothings.GrandCentralDispatcher, subscribed chan bool) {
|
|
||||||
q := event.NewQueue()
|
|
||||||
the.AppBus.Subscribe(event.NewPeer, q)
|
|
||||||
the.AppBus.Subscribe(event.PeerError, q)
|
|
||||||
the.AppBus.Subscribe(event.AppError, q)
|
|
||||||
the.AppBus.Subscribe(event.ACNStatus, q)
|
|
||||||
the.AppBus.Subscribe(event.ReloadDone, q)
|
|
||||||
subscribed <- true
|
|
||||||
|
|
||||||
for {
|
|
||||||
e := q.Next()
|
|
||||||
|
|
||||||
switch e.EventType {
|
|
||||||
case event.ACNStatus:
|
|
||||||
progStr := e.Data[event.Progreess]
|
|
||||||
percent, _ := strconv.Atoi(progStr)
|
|
||||||
message := e.Data[event.Status]
|
|
||||||
var statuscode int
|
|
||||||
if percent >= 0 && percent <= 25 {
|
|
||||||
statuscode = 1
|
|
||||||
message = "Connecting to network"
|
|
||||||
} else if percent < 100 {
|
|
||||||
statuscode = 2
|
|
||||||
message = "Establishng Tor circut"
|
|
||||||
} else if percent == 100 {
|
|
||||||
statuscode = 3
|
|
||||||
message = "tor appears to be running just fine!"
|
|
||||||
} else {
|
|
||||||
statuscode = 0
|
|
||||||
message = "can't find tor. is it running? is the controlport configured?"
|
|
||||||
}
|
|
||||||
|
|
||||||
gcd.TorStatus(statuscode, message)
|
|
||||||
case event.PeerError:
|
|
||||||
// current only case
|
|
||||||
log.Errorf("couldn't load profiles: %v", e.Data[event.Error])
|
|
||||||
os.Exit(1)
|
|
||||||
|
|
||||||
case event.AppError:
|
|
||||||
|
|
||||||
if e.Data[event.Error] == event.AppErrLoaded0 {
|
|
||||||
// TODO: only an error if other profiles are not loaded
|
|
||||||
log.Infoln("couldn't load your config file. attempting to create one now")
|
|
||||||
|
|
||||||
the.CwtchApp.CreatePeer("alice", the.AppPassword)
|
|
||||||
}
|
|
||||||
|
|
||||||
case event.ReloadDone:
|
|
||||||
if the.Peer == nil {
|
|
||||||
the.CwtchApp.LoadProfiles(the.AppPassword)
|
|
||||||
}
|
|
||||||
case event.NewPeer:
|
|
||||||
if the.Peer != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
onion := e.Data[event.Identity]
|
|
||||||
|
|
||||||
the.CwtchApp.AddPeerPlugin(onion, plugins.CONTACTRETRY)
|
|
||||||
|
|
||||||
the.Peer = the.CwtchApp.GetPeer(onion)
|
|
||||||
the.EventBus = the.CwtchApp.GetEventBus(onion)
|
|
||||||
|
|
||||||
incSubscribed := make(chan bool)
|
|
||||||
go IncomingListener(&gcd.UIState, incSubscribed)
|
|
||||||
<-incSubscribed
|
|
||||||
|
|
||||||
gcd.UpdateMyProfile(the.Peer.GetProfile().Name, the.Peer.GetProfile().Onion, cwutil.RandomProfileImage(the.Peer.GetProfile().Onion))
|
|
||||||
|
|
||||||
contacts := the.Peer.GetContacts()
|
|
||||||
for i := range contacts {
|
|
||||||
contact, _ := the.Peer.GetProfile().GetContact(contacts[i])
|
|
||||||
displayName, _ := contact.GetAttribute("nick")
|
|
||||||
|
|
||||||
gcd.UIState.AddContact(&gobjects.Contact{
|
|
||||||
Handle: contacts[i],
|
|
||||||
DisplayName: displayName,
|
|
||||||
Image: cwutil.RandomProfileImage(contacts[i]),
|
|
||||||
Trusted: contact.Trusted,
|
|
||||||
Blocked: contact.Blocked,
|
|
||||||
Loading: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
groups := the.Peer.GetGroups()
|
|
||||||
for i := range groups {
|
|
||||||
group := the.Peer.GetGroup(groups[i])
|
|
||||||
nick, exists := group.GetAttribute("nick")
|
|
||||||
if !exists {
|
|
||||||
nick = group.GroupID[:12]
|
|
||||||
}
|
|
||||||
// Only join servers for active and explicitly accepted groups.
|
|
||||||
gcd.UIState.AddContact(&gobjects.Contact{
|
|
||||||
Handle: group.GroupID,
|
|
||||||
DisplayName: nick,
|
|
||||||
Image: cwutil.RandomGroupImage(group.GroupID),
|
|
||||||
Server: group.GroupServer,
|
|
||||||
Trusted: group.Accepted,
|
|
||||||
Loading: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.Data[event.Status] != "running" {
|
|
||||||
the.CwtchApp.LaunchPeers()
|
|
||||||
}
|
|
||||||
|
|
||||||
// load ui preferences
|
|
||||||
gcd.RequestSettings()
|
|
||||||
locale, exists := the.Peer.GetProfile().GetAttribute(constants.LocaleSetting)
|
|
||||||
if exists {
|
|
||||||
gcd.SetLocale_helper(locale)
|
|
||||||
}
|
|
||||||
|
|
||||||
blockUnkownPeers, exists := the.Peer.GetProfile().GetAttribute(constants.BlockUnknownPeersSetting)
|
|
||||||
if exists && blockUnkownPeers == "true" {
|
|
||||||
the.EventBus.Publish(event.NewEvent(event.BlockUnknownPeers, map[event.Field]string{}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,154 +0,0 @@
|
||||||
package characters
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cwtch.im/cwtch/event"
|
|
||||||
"cwtch.im/cwtch/protocol/connections"
|
|
||||||
"cwtch.im/ui/go/cwutil"
|
|
||||||
"cwtch.im/ui/go/gobjects"
|
|
||||||
"cwtch.im/ui/go/gothings"
|
|
||||||
"cwtch.im/ui/go/the"
|
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func IncomingListener(uiState *gothings.InterfaceState, subscribed chan bool) {
|
|
||||||
q := event.NewQueue()
|
|
||||||
the.EventBus.Subscribe(event.NewMessageFromPeer, q)
|
|
||||||
the.EventBus.Subscribe(event.PeerAcknowledgement, q)
|
|
||||||
the.EventBus.Subscribe(event.NewMessageFromGroup, q)
|
|
||||||
the.EventBus.Subscribe(event.NewGroupInvite, q)
|
|
||||||
the.EventBus.Subscribe(event.SendMessageToGroupError, q)
|
|
||||||
the.EventBus.Subscribe(event.SendMessageToPeerError, q)
|
|
||||||
the.EventBus.Subscribe(event.ServerStateChange, q)
|
|
||||||
the.EventBus.Subscribe(event.PeerStateChange, q)
|
|
||||||
subscribed <- true
|
|
||||||
|
|
||||||
for {
|
|
||||||
e := q.Next()
|
|
||||||
|
|
||||||
switch e.EventType {
|
|
||||||
case event.NewMessageFromPeer: //event.TimestampReceived, event.RemotePeer, event.Data
|
|
||||||
ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampReceived])
|
|
||||||
uiState.AddMessage(&gobjects.Message{
|
|
||||||
Handle: e.Data[event.RemotePeer],
|
|
||||||
From: e.Data[event.RemotePeer],
|
|
||||||
Message: e.Data[event.Data],
|
|
||||||
Image: cwutil.RandomProfileImage(e.Data[event.RemotePeer]),
|
|
||||||
Timestamp: ts,
|
|
||||||
})
|
|
||||||
if the.Peer.GetContact(e.Data[event.RemotePeer]) == nil {
|
|
||||||
the.Peer.AddContact(e.Data[event.RemotePeer], e.Data[event.RemotePeer], false)
|
|
||||||
}
|
|
||||||
|
|
||||||
case event.PeerAcknowledgement:
|
|
||||||
ackI, ok := the.AcknowledgementIDs.Load(e.Data[event.EventID])
|
|
||||||
if ok {
|
|
||||||
ack := ackI.(*the.AckId)
|
|
||||||
if ack.Peer == e.Data[event.RemotePeer] {
|
|
||||||
ack.Ack = true
|
|
||||||
uiState.Acknowledge(e.Data[event.EventID])
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Debugf("Received Ack ID for unknown message or peer: %v", e)
|
|
||||||
case event.NewMessageFromGroup: //event.TimestampReceived, event.TimestampSent, event.Data, event.GroupID, event.RemotePeer
|
|
||||||
var name string
|
|
||||||
var exists bool
|
|
||||||
ctc := the.Peer.GetContact(e.Data[event.RemotePeer])
|
|
||||||
if ctc != nil {
|
|
||||||
name, exists = ctc.GetAttribute("nick")
|
|
||||||
if !exists || name == "" {
|
|
||||||
name = e.Data[event.RemotePeer]
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
name = e.Data[event.RemotePeer]
|
|
||||||
}
|
|
||||||
|
|
||||||
ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampSent])
|
|
||||||
uiState.AddMessage(&gobjects.Message{
|
|
||||||
MessageID: e.Data[event.Signature],
|
|
||||||
Handle: e.Data[event.GroupID],
|
|
||||||
From: e.Data[event.RemotePeer],
|
|
||||||
Message: e.Data[event.Data],
|
|
||||||
Image: cwutil.RandomProfileImage(e.Data[event.RemotePeer]),
|
|
||||||
FromMe: e.Data[event.RemotePeer] == the.Peer.GetProfile().Onion,
|
|
||||||
Timestamp: ts,
|
|
||||||
Acknowledged: true,
|
|
||||||
DisplayName: name,
|
|
||||||
})
|
|
||||||
case event.NewGroupInvite:
|
|
||||||
gid, err := the.Peer.GetProfile().ProcessInvite(e.Data[event.GroupInvite], e.Data[event.RemotePeer])
|
|
||||||
group := the.Peer.GetGroup(gid)
|
|
||||||
if err == nil && group != nil {
|
|
||||||
uiState.AddContact(&gobjects.Contact{
|
|
||||||
Handle: gid,
|
|
||||||
DisplayName: gid,
|
|
||||||
Image: cwutil.RandomGroupImage(gid),
|
|
||||||
Server: group.GroupServer,
|
|
||||||
Trusted: false,
|
|
||||||
Loading: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
case event.SendMessageToGroupError:
|
|
||||||
uiState.AddSendMessageError(e.Data[event.GroupServer], e.Data[event.Signature], e.Data[event.Error])
|
|
||||||
case event.SendMessageToPeerError:
|
|
||||||
uiState.AddSendMessageError(e.Data[event.RemotePeer], e.Data[event.Signature], e.Data[event.Error])
|
|
||||||
case event.PeerStateChange:
|
|
||||||
cxnState := connections.ConnectionStateToType[e.Data[event.ConnectionState]]
|
|
||||||
|
|
||||||
// if it's not in the.Peer it's new. Only add once Authed
|
|
||||||
_, exists := the.Peer.GetProfile().Contacts[e.Data[event.RemotePeer]]
|
|
||||||
if !exists {
|
|
||||||
// Contact does not exist, we will add them but we won't know who they are until they are authenticated
|
|
||||||
// So if we get any other state from an unknown contact we do nothing
|
|
||||||
// (the next exists check will fail)
|
|
||||||
if cxnState == connections.AUTHENTICATED {
|
|
||||||
the.Peer.AddContact(e.Data[event.RemotePeer], e.Data[event.RemotePeer], false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if it's in the.Peer its either existing and needs an update or not in the UI and needs to be added
|
|
||||||
if contact, exists := the.Peer.GetProfile().Contacts[e.Data[event.RemotePeer]]; exists {
|
|
||||||
contact.State = e.Data[event.ConnectionState]
|
|
||||||
uiContact := uiState.GetContact(contact.Onion)
|
|
||||||
if uiContact != nil {
|
|
||||||
if uiContact.Status != int(cxnState) {
|
|
||||||
uiContact.Status = int(cxnState)
|
|
||||||
uiState.UpdateContact(contact.Onion)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
uiState.AddContact(&gobjects.Contact{
|
|
||||||
e.Data[event.RemotePeer],
|
|
||||||
e.Data[event.RemotePeer],
|
|
||||||
cwutil.RandomProfileImage(e.Data[event.RemotePeer]),
|
|
||||||
"",
|
|
||||||
0,
|
|
||||||
int(cxnState),
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case event.ServerStateChange:
|
|
||||||
serverOnion := e.Data[event.GroupServer]
|
|
||||||
state := connections.ConnectionStateToType[e.Data[event.ConnectionState]]
|
|
||||||
groups := the.Peer.GetGroups()
|
|
||||||
for _, groupID := range groups {
|
|
||||||
group := the.Peer.GetGroup(groupID)
|
|
||||||
group.State = e.Data[event.ConnectionState]
|
|
||||||
if group != nil && group.GroupServer == serverOnion {
|
|
||||||
uiState.GetContact(group.GroupID).Status = int(state)
|
|
||||||
if state == connections.AUTHENTICATED {
|
|
||||||
uiState.GetContact(group.GroupID).Loading = true
|
|
||||||
} else {
|
|
||||||
uiState.GetContact(group.GroupID).Loading = false
|
|
||||||
}
|
|
||||||
uiState.UpdateContact(group.GroupID)
|
|
||||||
} else {
|
|
||||||
log.Errorf("found group that is nil :/")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package constants
|
||||||
|
|
||||||
|
const Nick = "nick"
|
||||||
|
const LastRead = "last-read"
|
||||||
|
const Picture = "picture"
|
||||||
|
const DefaultPassword = "default-password"
|
||||||
|
|
||||||
|
const ProfileTypeV1DefaultPassword = "v1-defaultPassword"
|
||||||
|
const ProfileTypeV1Password = "v1-userPassword"
|
|
@ -1,13 +0,0 @@
|
||||||
package gobjects
|
|
||||||
|
|
||||||
type Contact struct {
|
|
||||||
Handle string
|
|
||||||
DisplayName string
|
|
||||||
Image string
|
|
||||||
Server string
|
|
||||||
Badge int
|
|
||||||
Status int
|
|
||||||
Trusted bool
|
|
||||||
Blocked bool
|
|
||||||
Loading bool
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
package gobjects
|
|
||||||
|
|
||||||
// a Letter is a very simple message object passed to us from the UI
|
|
||||||
type Letter struct {
|
|
||||||
To, Message string
|
|
||||||
MID string
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
package gobjects
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type Message struct {
|
|
||||||
Handle string
|
|
||||||
From string
|
|
||||||
DisplayName string
|
|
||||||
Message string
|
|
||||||
Image string
|
|
||||||
FromMe bool
|
|
||||||
MessageID string
|
|
||||||
Timestamp time.Time
|
|
||||||
Acknowledged bool
|
|
||||||
Error bool
|
|
||||||
}
|
|
|
@ -1,195 +0,0 @@
|
||||||
package gothings
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cwtch.im/ui/go/constants"
|
|
||||||
"cwtch.im/ui/go/cwutil"
|
|
||||||
"cwtch.im/ui/go/gobjects"
|
|
||||||
"cwtch.im/ui/go/the"
|
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
|
||||||
"runtime/debug"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type InterfaceState struct {
|
|
||||||
parentGcd *GrandCentralDispatcher
|
|
||||||
contacts sync.Map // string : *gobjects.Contact
|
|
||||||
messages sync.Map
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewUIState(gcd *GrandCentralDispatcher) (uis InterfaceState) {
|
|
||||||
uis = InterfaceState{gcd, sync.Map{}, sync.Map{}}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *InterfaceState) Acknowledge(mID string) {
|
|
||||||
this.parentGcd.Acknowledged(mID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *InterfaceState) AddContact(c *gobjects.Contact) {
|
|
||||||
if len(c.Handle) == 32 { // ADD GROUP
|
|
||||||
if _, found := this.contacts.Load(c.Handle); !found {
|
|
||||||
this.parentGcd.AddContact(c.Handle, c.DisplayName, c.Image, c.Server, c.Badge, c.Status, c.Trusted, c.Blocked, c.Loading)
|
|
||||||
this.contacts.Store(c.Handle, c)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
} else if len(c.Handle) != 56 {
|
|
||||||
log.Errorf("sorry, unable to handle AddContact(%v)", c.Handle)
|
|
||||||
debug.PrintStack()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, found := this.contacts.Load(c.Handle); !found {
|
|
||||||
this.contacts.Store(c.Handle, c)
|
|
||||||
this.parentGcd.AddContact(c.Handle, c.DisplayName, c.Image, c.Server, c.Badge, c.Status, c.Trusted, c.Blocked, false)
|
|
||||||
if the.Peer.GetContact(c.Handle) == nil {
|
|
||||||
the.Peer.AddContact(c.DisplayName, c.Handle, c.Trusted)
|
|
||||||
go the.Peer.PeerWithOnion(c.Handle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *InterfaceState) DeleteContact(id string) {
|
|
||||||
this.contacts.Delete(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *InterfaceState) GetContact(handle string) *gobjects.Contact {
|
|
||||||
if _, found := this.contacts.Load(handle); !found {
|
|
||||||
if len(handle) == 32 {
|
|
||||||
group := the.Peer.GetGroup(handle)
|
|
||||||
if group != nil {
|
|
||||||
nick, exists := group.GetAttribute("nick")
|
|
||||||
if !exists {
|
|
||||||
nick = group.GroupID[:12]
|
|
||||||
}
|
|
||||||
this.AddContact(&gobjects.Contact{
|
|
||||||
handle,
|
|
||||||
nick,
|
|
||||||
cwutil.RandomGroupImage(handle),
|
|
||||||
group.GroupServer,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
group.Accepted,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
log.Errorf("Attempting to add non existent group to ui %v", handle)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
contact := the.Peer.GetContact(handle)
|
|
||||||
if contact != nil && handle != contact.Onion {
|
|
||||||
nick, exists := contact.GetAttribute("name")
|
|
||||||
if !exists {
|
|
||||||
nick = contact.Onion
|
|
||||||
}
|
|
||||||
this.AddContact(&gobjects.Contact{
|
|
||||||
handle,
|
|
||||||
nick,
|
|
||||||
cwutil.RandomProfileImage(handle),
|
|
||||||
"",
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
false,
|
|
||||||
contact.Blocked,
|
|
||||||
false,
|
|
||||||
})
|
|
||||||
} else if contact == nil {
|
|
||||||
//log.Errorf("Attempting to add non existent contact to ui %v", handle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
contactIntf, _ := this.contacts.Load(handle)
|
|
||||||
if contactIntf == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
contact := contactIntf.(*gobjects.Contact)
|
|
||||||
return contact
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *InterfaceState) AddSendMessageError(peer string, signature string, err string) {
|
|
||||||
ackI, ok := the.AcknowledgementIDs.Load(signature)
|
|
||||||
if ok {
|
|
||||||
ack := ackI.(*the.AckId)
|
|
||||||
ack.Error = true
|
|
||||||
}
|
|
||||||
|
|
||||||
messages, _ := this.messages.Load(peer)
|
|
||||||
messageList, _ := messages.([]*gobjects.Message)
|
|
||||||
|
|
||||||
for _, message := range messageList {
|
|
||||||
if message.MessageID == signature {
|
|
||||||
message.Error = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Debugf("Received Error Sending Message: %v", err)
|
|
||||||
// FIXME: Sometimes, for the first Peer message we send our error beats our message to the UI
|
|
||||||
time.Sleep(time.Second * 1)
|
|
||||||
this.parentGcd.GroupSendError(signature, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *InterfaceState) AddMessage(m *gobjects.Message) {
|
|
||||||
this.GetContact(m.From)
|
|
||||||
|
|
||||||
_, found := this.messages.Load(m.Handle)
|
|
||||||
if !found {
|
|
||||||
this.messages.Store(m.Handle, make([]*gobjects.Message, 0))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ack message sent to group
|
|
||||||
this.parentGcd.Acknowledged(m.MessageID)
|
|
||||||
|
|
||||||
messages, _ := this.messages.Load(m.Handle)
|
|
||||||
messageList, _ := messages.([]*gobjects.Message)
|
|
||||||
this.messages.Store(m.Handle, append(messageList, m))
|
|
||||||
|
|
||||||
// If we have this group loaded already
|
|
||||||
if this.parentGcd.CurrentOpenConversation() == m.Handle {
|
|
||||||
// If the message is not from the user then add it, otherwise, just acknowledge.
|
|
||||||
if !m.FromMe || !m.Acknowledged {
|
|
||||||
this.parentGcd.AppendMessage(m.Handle, m.From, m.DisplayName, m.Message, m.Image, m.MessageID, m.FromMe, m.Timestamp.Format(constants.TIME_FORMAT), m.Acknowledged, m.Error)
|
|
||||||
} else {
|
|
||||||
this.parentGcd.Acknowledged(m.MessageID)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
c := this.GetContact(m.Handle)
|
|
||||||
if c != nil {
|
|
||||||
c.Badge++
|
|
||||||
this.UpdateContact(c.Handle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *InterfaceState) GetMessages(handle string) []*gobjects.Message {
|
|
||||||
_, found := this.messages.Load(handle)
|
|
||||||
if !found {
|
|
||||||
this.messages.Store(handle, make([]*gobjects.Message, 0))
|
|
||||||
}
|
|
||||||
messages, found := this.messages.Load(handle)
|
|
||||||
messageList, _ := messages.([]*gobjects.Message)
|
|
||||||
return messageList
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *InterfaceState) UpdateContact(handle string) {
|
|
||||||
contact := the.Peer.GetContact(handle)
|
|
||||||
if contact != nil {
|
|
||||||
cif, found := this.contacts.Load(handle)
|
|
||||||
if found {
|
|
||||||
c := cif.(*gobjects.Contact)
|
|
||||||
c.Blocked = contact.Blocked
|
|
||||||
this.parentGcd.UpdateContact(c.Handle, c.DisplayName, c.Image, c.Server, c.Badge, c.Status, c.Trusted, c.Blocked, c.Loading)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cif, found := this.contacts.Load(handle)
|
|
||||||
if found {
|
|
||||||
c := cif.(*gobjects.Contact)
|
|
||||||
this.parentGcd.UpdateContact(c.Handle, c.DisplayName, c.Image, c.Server, c.Badge, c.Status, c.Trusted, c.Blocked, c.Loading)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *InterfaceState) UpdateContactAttribute(handle, key, value string) {
|
|
||||||
this.parentGcd.UpdateContactAttribute(handle, key, value)
|
|
||||||
}
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cwtch.im/cwtch/app"
|
||||||
|
"cwtch.im/cwtch/app/plugins"
|
||||||
|
"cwtch.im/cwtch/event"
|
||||||
|
"cwtch.im/ui/go/constants"
|
||||||
|
"cwtch.im/ui/go/the"
|
||||||
|
"cwtch.im/ui/go/ui"
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func App(gcd *ui.GrandCentralDispatcher, subscribed chan bool, reloadingAccounts bool) {
|
||||||
|
q := event.NewQueue()
|
||||||
|
the.AppBus.Subscribe(event.NewPeer, q)
|
||||||
|
the.AppBus.Subscribe(event.PeerError, q)
|
||||||
|
the.AppBus.Subscribe(event.AppError, q)
|
||||||
|
the.AppBus.Subscribe(event.ACNStatus, q)
|
||||||
|
the.AppBus.Subscribe(event.NetworkStatus, q)
|
||||||
|
the.AppBus.Subscribe(event.ReloadDone, q)
|
||||||
|
subscribed <- true
|
||||||
|
|
||||||
|
networkOffline := false
|
||||||
|
timeSinceLastSuccess := time.Unix(0, 0)
|
||||||
|
|
||||||
|
gcd.Loaded()
|
||||||
|
|
||||||
|
for {
|
||||||
|
e := q.Next()
|
||||||
|
|
||||||
|
switch e.EventType {
|
||||||
|
case event.NetworkStatus:
|
||||||
|
status := e.Data[event.Status]
|
||||||
|
if status == "Error" && !networkOffline {
|
||||||
|
networkOffline = true
|
||||||
|
// if it has been more that 5 minutes since we received any kind of success, then we should kill tor
|
||||||
|
// anything less that this i.e. transient networking failures, should allow us to reconnect without issue
|
||||||
|
if time.Now().Sub(timeSinceLastSuccess) > (time.Minute * 5) {
|
||||||
|
the.ACN.Restart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == "Success" && networkOffline {
|
||||||
|
timeSinceLastSuccess = time.Now()
|
||||||
|
networkOffline = false
|
||||||
|
}
|
||||||
|
|
||||||
|
case event.ACNStatus:
|
||||||
|
progStr := e.Data[event.Progreess]
|
||||||
|
percent, _ := strconv.Atoi(progStr)
|
||||||
|
message := e.Data[event.Status]
|
||||||
|
var statuscode int
|
||||||
|
if percent >= 0 && percent <= 25 {
|
||||||
|
statuscode = 1
|
||||||
|
message = "Connecting to network"
|
||||||
|
} else if percent < 100 {
|
||||||
|
statuscode = 2
|
||||||
|
message = "Establishing Tor circuit"
|
||||||
|
} else if percent == 100 {
|
||||||
|
statuscode = 3
|
||||||
|
message = "tor appears to be running just fine!"
|
||||||
|
} else {
|
||||||
|
statuscode = 0
|
||||||
|
message = "can't find tor. is it running? is the controlport configured?"
|
||||||
|
}
|
||||||
|
|
||||||
|
gcd.TorStatus(statuscode, message)
|
||||||
|
|
||||||
|
case event.PeerError:
|
||||||
|
// current only case
|
||||||
|
log.Errorf("couldn't load profiles: %v", e.Data[event.Error])
|
||||||
|
os.Exit(1)
|
||||||
|
|
||||||
|
case event.AppError:
|
||||||
|
|
||||||
|
if e.Data[event.Error] == event.AppErrLoaded0 {
|
||||||
|
if reloadingAccounts {
|
||||||
|
reloadingAccounts = false
|
||||||
|
} else {
|
||||||
|
gcd.ErrorLoaded0()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case event.ReloadDone:
|
||||||
|
reloadingAccounts = false
|
||||||
|
if len(the.CwtchApp.ListPeers()) == 0 {
|
||||||
|
the.CwtchApp.LoadProfiles(the.AppPassword)
|
||||||
|
}
|
||||||
|
case event.NewPeer:
|
||||||
|
onion := e.Data[event.Identity]
|
||||||
|
peer := the.CwtchApp.GetPeer(onion)
|
||||||
|
|
||||||
|
if tag, exists := peer.GetAttribute(app.AttributeTag); !exists || tag == "" {
|
||||||
|
peer.SetAttribute(app.AttributeTag, constants.ProfileTypeV1DefaultPassword)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("NewPeer for %v\n", onion)
|
||||||
|
ui.AddProfile(gcd, onion)
|
||||||
|
|
||||||
|
the.CwtchApp.AddPeerPlugin(onion, plugins.CONNECTIONRETRY)
|
||||||
|
the.CwtchApp.AddPeerPlugin(onion, plugins.NETWORKCHECK)
|
||||||
|
|
||||||
|
incSubscribed := make(chan bool)
|
||||||
|
go PeerHandler(onion, gcd.GetUiManager(peer.GetProfile().Onion), incSubscribed)
|
||||||
|
<-incSubscribed
|
||||||
|
|
||||||
|
if e.Data[event.Status] != "running" {
|
||||||
|
peer.Listen()
|
||||||
|
peer.StartPeersConnections()
|
||||||
|
peer.StartGroupConnections()
|
||||||
|
}
|
||||||
|
|
||||||
|
blockUnkownPeers, exists := peer.GetProfile().GetAttribute(constants.BlockUnknownPeersSetting)
|
||||||
|
if exists && blockUnkownPeers == "true" {
|
||||||
|
the.EventBus.Publish(event.NewEvent(event.BlockUnknownPeers, map[event.Field]string{}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,124 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cwtch.im/cwtch/app"
|
||||||
|
"cwtch.im/cwtch/event"
|
||||||
|
"cwtch.im/cwtch/protocol/connections"
|
||||||
|
"cwtch.im/ui/go/constants"
|
||||||
|
"cwtch.im/ui/go/the"
|
||||||
|
"cwtch.im/ui/go/ui"
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PeerHandler(onion string, uiManager ui.Manager, subscribed chan bool) {
|
||||||
|
peer := the.CwtchApp.GetPeer(onion)
|
||||||
|
eventBus := the.CwtchApp.GetEventBus(onion)
|
||||||
|
q := event.NewQueue()
|
||||||
|
eventBus.Subscribe(event.NewMessageFromPeer, q)
|
||||||
|
eventBus.Subscribe(event.PeerAcknowledgement, q)
|
||||||
|
eventBus.Subscribe(event.NewMessageFromGroup, q)
|
||||||
|
eventBus.Subscribe(event.NewGroupInvite, q)
|
||||||
|
eventBus.Subscribe(event.SendMessageToGroupError, q)
|
||||||
|
eventBus.Subscribe(event.SendMessageToPeerError, q)
|
||||||
|
eventBus.Subscribe(event.ServerStateChange, q)
|
||||||
|
eventBus.Subscribe(event.PeerStateChange, q)
|
||||||
|
eventBus.Subscribe(event.PeerCreated, q)
|
||||||
|
eventBus.Subscribe(event.NetworkStatus, q)
|
||||||
|
eventBus.Subscribe(event.ChangePasswordSuccess, q)
|
||||||
|
eventBus.Subscribe(event.ChangePasswordError, q)
|
||||||
|
|
||||||
|
subscribed <- true
|
||||||
|
|
||||||
|
networkOffline := false
|
||||||
|
|
||||||
|
for {
|
||||||
|
e := q.Next()
|
||||||
|
|
||||||
|
switch e.EventType {
|
||||||
|
|
||||||
|
case event.NetworkStatus:
|
||||||
|
the.AppBus.Publish(*e)
|
||||||
|
if e.Data["Status"] == "Success" && networkOffline {
|
||||||
|
networkOffline = false
|
||||||
|
// TODO we may have to reinitialize the peer
|
||||||
|
} else {
|
||||||
|
networkOffline = true
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
if peer.GetContact(e.Data[event.RemotePeer]) == nil {
|
||||||
|
peer.AddContact(e.Data[event.RemotePeer], e.Data[event.RemotePeer], false)
|
||||||
|
}
|
||||||
|
|
||||||
|
case event.PeerAcknowledgement:
|
||||||
|
uiManager.Acknowledge(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.GetProfile().Onion, e.Data[event.Signature], ts, true)
|
||||||
|
case event.NewGroupInvite:
|
||||||
|
gid, err := peer.GetProfile().ProcessInvite(e.Data[event.GroupInvite], e.Data[event.RemotePeer])
|
||||||
|
group := peer.GetGroup(gid)
|
||||||
|
if err == nil && group != nil {
|
||||||
|
uiManager.AddContact(gid)
|
||||||
|
}
|
||||||
|
case event.PeerCreated:
|
||||||
|
onion := e.Data[event.RemotePeer]
|
||||||
|
uiManager.AddContact(onion)
|
||||||
|
case event.SendMessageToGroupError:
|
||||||
|
uiManager.AddSendMessageError(e.Data[event.GroupServer], e.Data[event.Signature], e.Data[event.Error])
|
||||||
|
case event.SendMessageToPeerError:
|
||||||
|
uiManager.AddSendMessageError(e.Data[event.RemotePeer], e.Data[event.EventID], e.Data[event.Error])
|
||||||
|
case event.PeerStateChange:
|
||||||
|
cxnState := connections.ConnectionStateToType[e.Data[event.ConnectionState]]
|
||||||
|
|
||||||
|
// if it's not in the.PeerHandler it's new. Only add once Authed
|
||||||
|
if _, exists := peer.GetProfile().Contacts[e.Data[event.RemotePeer]]; !exists {
|
||||||
|
// Contact does not exist, we will add them but we won't know who they are until they are authenticated
|
||||||
|
// So if we get any other state from an unknown contact we do nothing
|
||||||
|
// (the next exists check will fail)
|
||||||
|
if cxnState == connections.AUTHENTICATED {
|
||||||
|
peer.AddContact(e.Data[event.RemotePeer], e.Data[event.RemotePeer], false)
|
||||||
|
uiManager.AddContact(e.Data[event.RemotePeer])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it's in the.PeerHandler its either existing and needs an update or not in the UI and needs to be added
|
||||||
|
if contact, exists := peer.GetProfile().Contacts[e.Data[event.RemotePeer]]; exists {
|
||||||
|
contact.State = e.Data[event.ConnectionState]
|
||||||
|
uiManager.UpdateContactStatus(contact.Onion, int(cxnState), false)
|
||||||
|
|
||||||
|
}
|
||||||
|
case event.ServerStateChange:
|
||||||
|
serverOnion := e.Data[event.GroupServer]
|
||||||
|
state := connections.ConnectionStateToType[e.Data[event.ConnectionState]]
|
||||||
|
groups := peer.GetGroups()
|
||||||
|
for _, groupID := range groups {
|
||||||
|
group := peer.GetGroup(groupID)
|
||||||
|
if group != nil && group.GroupServer == serverOnion {
|
||||||
|
group.State = e.Data[event.ConnectionState]
|
||||||
|
loading := false
|
||||||
|
if state == connections.AUTHENTICATED {
|
||||||
|
loading = true
|
||||||
|
}
|
||||||
|
uiManager.UpdateContactStatus(group.GroupID, int(state), loading)
|
||||||
|
} else {
|
||||||
|
log.Errorf("found group that is nil :/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case event.DeletePeer:
|
||||||
|
log.Infof("PeerHandler got DeletePeer, SHUTTING down!\n")
|
||||||
|
uiManager.ReloadProfiles()
|
||||||
|
return
|
||||||
|
case event.ChangePasswordSuccess:
|
||||||
|
peer.SetAttribute(app.AttributeTag, constants.ProfileTypeV1Password)
|
||||||
|
uiManager.ChangePasswordResponse(false)
|
||||||
|
case event.ChangePasswordError:
|
||||||
|
uiManager.ChangePasswordResponse(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"cwtch.im/cwtch/event"
|
"cwtch.im/cwtch/event"
|
||||||
libPeer "cwtch.im/cwtch/peer"
|
libPeer "cwtch.im/cwtch/peer"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Terrible, to be replaced when proper profile/password management comes in ~ 0.2
|
// Terrible, to be replaced when proper profile/password management comes in ~ 0.2
|
||||||
|
@ -19,12 +18,3 @@ var ACN connectivity.ACN
|
||||||
var Peer libPeer.CwtchPeer
|
var Peer libPeer.CwtchPeer
|
||||||
var CwtchDir string
|
var CwtchDir string
|
||||||
var IPCBridge event.IPCBridge
|
var IPCBridge event.IPCBridge
|
||||||
|
|
||||||
type AckId struct {
|
|
||||||
ID string
|
|
||||||
Peer string
|
|
||||||
Ack bool
|
|
||||||
Error bool
|
|
||||||
}
|
|
||||||
|
|
||||||
var AcknowledgementIDs sync.Map
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
package gothings
|
package ui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cwtch.im/cwtch/app"
|
||||||
"cwtch.im/cwtch/event"
|
"cwtch.im/cwtch/event"
|
||||||
|
"cwtch.im/cwtch/protocol/connections"
|
||||||
"cwtch.im/ui/go/constants"
|
"cwtch.im/ui/go/constants"
|
||||||
"cwtch.im/ui/go/cwutil"
|
|
||||||
"github.com/therecipe/qt/qml"
|
"github.com/therecipe/qt/qml"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"cwtch.im/ui/go/gobjects"
|
|
||||||
"cwtch.im/ui/go/the"
|
"cwtch.im/ui/go/the"
|
||||||
"encoding/base32"
|
"encoding/base32"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
||||||
|
@ -18,23 +19,41 @@ import (
|
||||||
type GrandCentralDispatcher struct {
|
type GrandCentralDispatcher struct {
|
||||||
core.QObject
|
core.QObject
|
||||||
|
|
||||||
OutgoingMessages chan gobjects.Letter
|
QMLEngine *qml.QQmlApplicationEngine
|
||||||
UIState InterfaceState
|
Translator *core.QTranslator
|
||||||
QMLEngine *qml.QQmlApplicationEngine
|
|
||||||
Translator *core.QTranslator
|
uIManagers map[string]Manager // profile-onion : Manager
|
||||||
|
|
||||||
|
profileLock sync.Mutex
|
||||||
|
conversationLock sync.Mutex
|
||||||
|
|
||||||
|
m_selectedProfile string
|
||||||
|
m_selectedConversation string
|
||||||
|
|
||||||
_ string `property:"os"`
|
_ string `property:"os"`
|
||||||
_ string `property:"currentOpenConversation"`
|
|
||||||
_ float32 `property:"themeScale"`
|
_ float32 `property:"themeScale"`
|
||||||
_ string `property:"version"`
|
_ string `property:"version"`
|
||||||
_ string `property:"buildDate"`
|
_ string `property:"buildDate"`
|
||||||
_ string `property:"assetPath"`
|
_ string `property:"assetPath"`
|
||||||
|
_ string `property:"selectedProfile,auto"`
|
||||||
|
_ string `property:"selectedConversation,auto"`
|
||||||
|
|
||||||
|
// profile management stuff
|
||||||
|
_ func() `signal:"Loaded"`
|
||||||
|
_ func(handle, displayname, image, tag string) `signal:"AddProfile"`
|
||||||
|
_ func() `signal:"ErrorLoaded0"`
|
||||||
|
_ func() `signal:"ResetProfile"`
|
||||||
|
_ func() `signal:"ResetProfileList"`
|
||||||
|
_ func(failed bool) `signal:"ChangePasswordResponse"`
|
||||||
|
|
||||||
// contact list stuff
|
// contact list stuff
|
||||||
_ func(handle, displayName, image, server string, badge, status int, trusted bool, blocked bool, loading bool) `signal:"AddContact"`
|
_ func(handle, displayName, image, server string, badge, status int, blocked bool, loading bool, lastMsgTime int) `signal:"AddContact"`
|
||||||
_ func(handle, displayName, image, server string, badge, status int, trusted bool, blocked bool, loading bool) `signal:"UpdateContact"`
|
_ func(handle, displayName string) `signal:"UpdateContactDisplayName"`
|
||||||
_ func(handle string) `signal:"RemoveContact"`
|
_ func(handle string, status int, loading bool) `signal:"UpdateContactStatus"`
|
||||||
_ func(handle, key, value string) `signal:"UpdateContactAttribute"`
|
_ func(handle string, blocked bool) `signal:"UpdateContactBlocked"`
|
||||||
|
_ func(handle string) `signal:"IncContactUnreadCount"`
|
||||||
|
_ func(handle string) `signal:"RemoveContact"`
|
||||||
|
_ func(handle, key, value string) `signal:"UpdateContactAttribute"`
|
||||||
|
|
||||||
// messages pane stuff
|
// messages pane stuff
|
||||||
_ func(handle, from, displayName, message, image string, mID string, fromMe bool, ts string, ackd bool, error bool) `signal:"AppendMessage"`
|
_ func(handle, from, displayName, message, image string, mID string, fromMe bool, ts string, ackd bool, error bool) `signal:"AppendMessage"`
|
||||||
|
@ -57,14 +76,26 @@ type GrandCentralDispatcher struct {
|
||||||
_ func(onion, nick string, blocked bool) `signal:"SupplyPeerSettings"`
|
_ func(onion, nick string, blocked bool) `signal:"SupplyPeerSettings"`
|
||||||
|
|
||||||
// signals emitted from the ui (written in go, below)
|
// signals emitted from the ui (written in go, below)
|
||||||
|
// ui
|
||||||
|
_ func() `signal:"onActivate,auto"`
|
||||||
|
_ func(locale string) `signal:"setLocale,auto"`
|
||||||
|
// profile managemenet
|
||||||
|
_ func(onion, nick string) `signal:"updateNick,auto"`
|
||||||
|
_ func(handle string) `signal:"loadProfile,auto"`
|
||||||
|
_ func(nick string, defaultPass bool, password string) `signal:"createProfile,auto"`
|
||||||
|
_ 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""`
|
||||||
|
// operating a profile
|
||||||
_ func(message string, mid string) `signal:"sendMessage,auto"`
|
_ func(message string, mid string) `signal:"sendMessage,auto"`
|
||||||
_ func(onion string) `signal:"blockPeer,auto"`
|
_ func(onion string) `signal:"blockPeer,auto"`
|
||||||
_ func(onion string) `signal:"unblockPeer,auto"`
|
_ func(onion string) `signal:"unblockPeer,auto"`
|
||||||
_ func(onion string) `signal:"loadMessagesPane,auto"`
|
_ func(onion string) `signal:"loadMessagesPane,auto"`
|
||||||
_ func(signal string) `signal:"broadcast,auto"` // convenience relay signal
|
_ func(signal string) `signal:"broadcast,auto"` // convenience relay signal
|
||||||
_ func(str string) `signal:"importString,auto"`
|
_ func(str string) `signal:"importString,auto"`
|
||||||
|
_ func(str string) `signal:"createContact,auto"`
|
||||||
_ func(str string) `signal:"popup,auto"`
|
_ func(str string) `signal:"popup,auto"`
|
||||||
_ func(nick string) `signal:"updateNick,auto"`
|
|
||||||
_ func(server, groupName string) `signal:"createGroup,auto"`
|
_ func(server, groupName string) `signal:"createGroup,auto"`
|
||||||
_ func(groupID string) `signal:"leaveGroup,auto"`
|
_ func(groupID string) `signal:"leaveGroup,auto"`
|
||||||
_ func(groupID string) `signal:"acceptGroup,auto"`
|
_ func(groupID string) `signal:"acceptGroup,auto"`
|
||||||
|
@ -77,9 +108,85 @@ type GrandCentralDispatcher struct {
|
||||||
_ func(onion, groupID string) `signal:"inviteToGroup,auto"`
|
_ func(onion, groupID string) `signal:"inviteToGroup,auto"`
|
||||||
_ func(onion, key, nick string) `signal:"setAttribute,auto"`
|
_ func(onion, key, nick string) `signal:"setAttribute,auto"`
|
||||||
_ func(onion string) `signal:"deleteContact,auto"`
|
_ func(onion string) `signal:"deleteContact,auto"`
|
||||||
_ func(locale string) `signal:"setLocale,auto"`
|
|
||||||
_ func() `signal:"allowUnknownPeers,auto"`
|
_ func() `signal:"allowUnknownPeers,auto"`
|
||||||
_ func() `signal:"blockUnknownPeers,auto"`
|
_ func() `signal:"blockUnknownPeers,auto"`
|
||||||
|
|
||||||
|
_ func() `constructor:"init"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *GrandCentralDispatcher) init() {
|
||||||
|
this.uIManagers = make(map[string]Manager)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUiManager gets (and creates if required) a ui Manager for the supplied profile id
|
||||||
|
func (this *GrandCentralDispatcher) GetUiManager(profile string) Manager {
|
||||||
|
this.profileLock.Lock()
|
||||||
|
defer this.profileLock.Unlock()
|
||||||
|
|
||||||
|
if manager, exists := this.uIManagers[profile]; exists {
|
||||||
|
return manager
|
||||||
|
} else {
|
||||||
|
this.uIManagers[profile] = NewManager(profile, this)
|
||||||
|
return this.uIManagers[profile]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *GrandCentralDispatcher) selectedProfile() string {
|
||||||
|
this.profileLock.Lock()
|
||||||
|
defer this.profileLock.Unlock()
|
||||||
|
|
||||||
|
return this.m_selectedProfile
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *GrandCentralDispatcher) setSelectedProfile(onion string) {
|
||||||
|
this.profileLock.Lock()
|
||||||
|
defer this.profileLock.Unlock()
|
||||||
|
|
||||||
|
this.m_selectedProfile = onion
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *GrandCentralDispatcher) selectedProfileChanged(onion string) {
|
||||||
|
this.SelectedProfileChanged(onion)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoIfProfile performs a gcd action for a profile IF it is the currently selected profile in the UI
|
||||||
|
// otherwise it does nothing. it also locks profile switching for the duration of the action
|
||||||
|
func (this *GrandCentralDispatcher) DoIfProfile(profile string, fn func()) {
|
||||||
|
this.profileLock.Lock()
|
||||||
|
defer this.profileLock.Unlock()
|
||||||
|
|
||||||
|
if this.m_selectedProfile == profile {
|
||||||
|
fn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *GrandCentralDispatcher) selectedConversation() string {
|
||||||
|
this.conversationLock.Lock()
|
||||||
|
defer this.conversationLock.Unlock()
|
||||||
|
|
||||||
|
return this.m_selectedConversation
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *GrandCentralDispatcher) setSelectedConversation(handle string) {
|
||||||
|
this.conversationLock.Lock()
|
||||||
|
defer this.conversationLock.Unlock()
|
||||||
|
|
||||||
|
this.m_selectedConversation = handle
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *GrandCentralDispatcher) selectedConversationChanged(handle string) {
|
||||||
|
this.SelectedConversationChanged(handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoIfConversation performs a gcd action for a conversation IF it is the currently selected conversation in the UI
|
||||||
|
// otherwise it does nothing. it also locks conversation switching for the duration of the action
|
||||||
|
func (this *GrandCentralDispatcher) DoIfConversation(conversation string, fn func()) {
|
||||||
|
this.conversationLock.Lock()
|
||||||
|
defer this.conversationLock.Unlock()
|
||||||
|
|
||||||
|
if this.m_selectedConversation == conversation {
|
||||||
|
fn()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) sendMessage(message string, mID string) {
|
func (this *GrandCentralDispatcher) sendMessage(message string, mID string) {
|
||||||
|
@ -88,72 +195,34 @@ func (this *GrandCentralDispatcher) sendMessage(message string, mID string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if this.CurrentOpenConversation() == "" {
|
if this.SelectedConversation() == "" {
|
||||||
this.InvokePopup("ui error")
|
this.InvokePopup("ui error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(this.CurrentOpenConversation()) == 32 { // SEND TO GROUP
|
if isGroup(this.SelectedConversation()) {
|
||||||
if !the.Peer.GetGroup(this.CurrentOpenConversation()).Accepted {
|
if !the.Peer.GetGroup(this.SelectedConversation()).Accepted {
|
||||||
err := the.Peer.AcceptInvite(this.CurrentOpenConversation())
|
err := the.Peer.AcceptInvite(this.SelectedConversation())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("tried to mark a nonexistent group as existed. bad!")
|
log.Errorf("tried to mark a nonexistent group as existed. bad!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c := this.UIState.GetContact(this.CurrentOpenConversation())
|
|
||||||
c.Trusted = true
|
|
||||||
this.UIState.UpdateContact(c.Handle)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
mID, err = the.Peer.SendMessageToGroupTracked(this.CurrentOpenConversation(), message)
|
mID, err = the.Peer.SendMessageToGroupTracked(this.SelectedConversation(), message)
|
||||||
|
|
||||||
this.UIState.AddMessage(&gobjects.Message{
|
this.GetUiManager(this.selectedProfile()).AddMessage(this.SelectedConversation(), "me", message, true, mID, time.Now(), false)
|
||||||
this.CurrentOpenConversation(),
|
|
||||||
"me",
|
|
||||||
"",
|
|
||||||
message,
|
|
||||||
"",
|
|
||||||
true,
|
|
||||||
mID,
|
|
||||||
time.Now(),
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.InvokePopup("failed to send message " + err.Error())
|
this.InvokePopup("failed to send message " + err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
to := this.SelectedConversation()
|
||||||
// TODO: require explicit invite accept/reject instead of implicitly trusting on send
|
|
||||||
if !this.UIState.GetContact(this.CurrentOpenConversation()).Trusted {
|
|
||||||
this.UIState.GetContact(this.CurrentOpenConversation()).Trusted = true
|
|
||||||
this.UIState.UpdateContact(this.CurrentOpenConversation())
|
|
||||||
}
|
|
||||||
|
|
||||||
to := this.CurrentOpenConversation()
|
|
||||||
mID = the.Peer.SendMessageToPeer(to, message)
|
mID = the.Peer.SendMessageToPeer(to, message)
|
||||||
|
|
||||||
this.UIState.AddMessage(&gobjects.Message{
|
this.GetUiManager(this.selectedProfile()).AddMessage(to, "me", message, true, mID, time.Now(), false)
|
||||||
to,
|
|
||||||
"me",
|
|
||||||
"",
|
|
||||||
message,
|
|
||||||
"",
|
|
||||||
true,
|
|
||||||
mID,
|
|
||||||
time.Now(),
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
})
|
|
||||||
|
|
||||||
ackID := new(the.AckId)
|
|
||||||
ackID.ID = mID
|
|
||||||
ackID.Ack = false
|
|
||||||
ackID.Peer = to
|
|
||||||
the.AcknowledgementIDs.Store(mID, ackID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -167,30 +236,21 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.ClearMessages()
|
this.ClearMessages()
|
||||||
this.SetCurrentOpenConversation(handle)
|
this.SetSelectedConversation(handle)
|
||||||
c := this.UIState.GetContact(handle)
|
|
||||||
|
|
||||||
if c == nil {
|
if isGroup(handle) { // LOAD GROUP
|
||||||
this.UIState.AddContact(&gobjects.Contact{
|
|
||||||
handle,
|
|
||||||
handle,
|
|
||||||
cwutil.RandomProfileImage(handle),
|
|
||||||
"",
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
c.Badge = 0
|
|
||||||
this.UIState.UpdateContact(handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(handle) == 32 { // LOAD GROUP
|
|
||||||
group := the.Peer.GetGroup(handle)
|
group := the.Peer.GetGroup(handle)
|
||||||
|
|
||||||
|
loading := false
|
||||||
|
state := connections.ConnectionStateToType[group.State]
|
||||||
|
if state == connections.AUTHENTICATED {
|
||||||
|
loading = true
|
||||||
|
}
|
||||||
|
this.UpdateContactStatus(group.GroupID, int(state), loading)
|
||||||
|
|
||||||
tl := group.GetTimeline()
|
tl := group.GetTimeline()
|
||||||
nick, _ := group.GetAttribute("nick")
|
nick, _ := group.GetAttribute(constants.Nick)
|
||||||
|
updateLastReadTime(group.GroupID)
|
||||||
if nick == "" {
|
if nick == "" {
|
||||||
this.SetToolbarTitle(handle)
|
this.SetToolbarTitle(handle)
|
||||||
} else {
|
} else {
|
||||||
|
@ -203,24 +263,16 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
|
||||||
} else {
|
} else {
|
||||||
handle = tl[i].PeerID
|
handle = tl[i].PeerID
|
||||||
}
|
}
|
||||||
var name string
|
|
||||||
var exists bool
|
name := getOrDefault(tl[i].PeerID, constants.Nick, tl[i].PeerID)
|
||||||
ctc := the.Peer.GetContact(tl[i].PeerID)
|
image := getProfilePic(tl[i].PeerID)
|
||||||
if ctc != nil {
|
|
||||||
name, exists = ctc.GetAttribute("nick")
|
|
||||||
if !exists || name == "" {
|
|
||||||
name = tl[i].PeerID
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
name = tl[i].PeerID
|
|
||||||
}
|
|
||||||
|
|
||||||
this.PrependMessage(
|
this.PrependMessage(
|
||||||
handle,
|
handle,
|
||||||
tl[i].PeerID,
|
tl[i].PeerID,
|
||||||
name,
|
name,
|
||||||
tl[i].Message,
|
tl[i].Message,
|
||||||
cwutil.RandomProfileImage(tl[i].PeerID),
|
image,
|
||||||
string(tl[i].Signature),
|
string(tl[i].Signature),
|
||||||
tl[i].PeerID == the.Peer.GetProfile().Onion,
|
tl[i].PeerID == the.Peer.GetProfile().Onion,
|
||||||
tl[i].Timestamp.Format(constants.TIME_FORMAT),
|
tl[i].Timestamp.Format(constants.TIME_FORMAT),
|
||||||
|
@ -232,42 +284,43 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
|
||||||
} // ELSE LOAD CONTACT
|
} // ELSE LOAD CONTACT
|
||||||
|
|
||||||
contact, _ := the.Peer.GetProfile().GetContact(handle)
|
contact, _ := the.Peer.GetProfile().GetContact(handle)
|
||||||
|
|
||||||
|
this.UpdateContactStatus(handle, int(connections.ConnectionStateToType[contact.State]), false)
|
||||||
|
|
||||||
|
var nick string
|
||||||
if contact != nil {
|
if contact != nil {
|
||||||
nick, _ := contact.GetAttribute("nick")
|
nick, _ = contact.GetAttribute(constants.Nick)
|
||||||
if nick == "" {
|
if nick == "" {
|
||||||
this.SetToolbarTitle(handle)
|
nick = handle
|
||||||
} else {
|
|
||||||
this.SetToolbarTitle(nick)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
updateLastReadTime(contact.Onion)
|
||||||
|
this.SetToolbarTitle(nick)
|
||||||
|
|
||||||
messages := this.UIState.GetMessages(handle)
|
peer := the.Peer.GetContact(handle)
|
||||||
|
messages := peer.Timeline.GetMessages()
|
||||||
for i := range messages {
|
for i := range messages {
|
||||||
from := messages[i].From
|
from := messages[i].PeerID
|
||||||
if messages[i].FromMe {
|
fromMe := messages[i].PeerID == the.Peer.GetProfile().Onion
|
||||||
|
if fromMe {
|
||||||
from = "me"
|
from = "me"
|
||||||
}
|
}
|
||||||
|
|
||||||
ackI, ok := the.AcknowledgementIDs.Load(messages[i].MessageID)
|
displayname := getOrDefault(messages[i].PeerID, constants.Nick, messages[i].PeerID)
|
||||||
acked := false
|
image := getProfilePic(messages[i].PeerID)
|
||||||
if ok {
|
|
||||||
ack := ackI.(*the.AckId)
|
|
||||||
acked = ack.Ack
|
|
||||||
}
|
|
||||||
|
|
||||||
this.AppendMessage(
|
this.AppendMessage(
|
||||||
messages[i].Handle,
|
|
||||||
from,
|
from,
|
||||||
messages[i].DisplayName,
|
messages[i].PeerID,
|
||||||
|
displayname,
|
||||||
messages[i].Message,
|
messages[i].Message,
|
||||||
cwutil.RandomProfileImage(handle),
|
image,
|
||||||
messages[i].MessageID,
|
string(messages[i].Signature),
|
||||||
messages[i].FromMe,
|
fromMe,
|
||||||
messages[i].Timestamp.Format(constants.TIME_FORMAT),
|
messages[i].Timestamp.Format(constants.TIME_FORMAT),
|
||||||
acked,
|
messages[i].Acknowledged,
|
||||||
messages[i].Error,
|
messages[i].Error != "",
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,25 +338,22 @@ func (this *GrandCentralDispatcher) saveSettings(zoom, locale string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
the.EventBus.Publish(event.NewEvent(event.SetAttribute, map[event.Field]string{
|
the.Peer.SetAttribute(constants.ZoomSetting, zoom)
|
||||||
event.Key: constants.ZoomSetting,
|
|
||||||
event.Data: zoom,
|
|
||||||
}))
|
|
||||||
the.Peer.GetProfile().SetAttribute(constants.ZoomSetting, zoom)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) requestPeerSettings() {
|
func (this *GrandCentralDispatcher) requestPeerSettings() {
|
||||||
contact := the.Peer.GetContact(this.CurrentOpenConversation())
|
contact := the.Peer.GetContact(this.SelectedConversation())
|
||||||
if contact == nil {
|
if contact == nil {
|
||||||
log.Errorf("error: requested settings for unknown contact %v?", this.CurrentOpenConversation())
|
log.Errorf("error: requested settings for unknown contact %v?", this.SelectedConversation())
|
||||||
this.SupplyPeerSettings(this.CurrentOpenConversation(), this.CurrentOpenConversation(), false)
|
this.SupplyPeerSettings(this.SelectedConversation(), this.SelectedConversation(), false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
name, exists := contact.GetAttribute("nick")
|
name, exists := contact.GetAttribute(constants.Nick)
|
||||||
if !exists {
|
if !exists {
|
||||||
log.Errorf("error: couldn't find contact %v", this.CurrentOpenConversation())
|
log.Errorf("error: couldn't find contact %v", this.SelectedConversation())
|
||||||
this.SupplyPeerSettings(this.CurrentOpenConversation(), this.CurrentOpenConversation(), contact.Blocked)
|
this.SupplyPeerSettings(this.SelectedConversation(), this.SelectedConversation(), contact.Blocked)
|
||||||
|
this.SupplyPeerSettings(this.SelectedConversation(), this.SelectedConversation(), contact.Blocked)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,23 +361,8 @@ func (this *GrandCentralDispatcher) requestPeerSettings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) savePeerSettings(onion, nick string) {
|
func (this *GrandCentralDispatcher) savePeerSettings(onion, nick string) {
|
||||||
contact := the.Peer.GetContact(onion)
|
the.Peer.SetContactAttribute(onion, constants.Nick, nick)
|
||||||
if contact == nil {
|
this.UpdateContactDisplayName(onion, nick)
|
||||||
log.Errorf("error: tried to save settings for unknown peer %v", onion)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
contact.SetAttribute("nick", nick)
|
|
||||||
the.EventBus.Publish(event.NewEvent(event.SetPeerAttribute, map[event.Field]string{
|
|
||||||
event.RemotePeer: onion,
|
|
||||||
event.Key: "nick",
|
|
||||||
event.Data: nick,
|
|
||||||
}))
|
|
||||||
|
|
||||||
cif, _ := this.UIState.contacts.Load(onion)
|
|
||||||
c := cif.(*gobjects.Contact)
|
|
||||||
c.DisplayName = nick
|
|
||||||
this.UIState.UpdateContact(onion)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) requestGroupSettings(groupID string) {
|
func (this *GrandCentralDispatcher) requestGroupSettings(groupID string) {
|
||||||
|
@ -338,13 +373,13 @@ func (this *GrandCentralDispatcher) requestGroupSettings(groupID string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
nick, _ := group.GetAttribute("nick")
|
nick, _ := group.GetAttribute(constants.Nick)
|
||||||
invite, _ := the.Peer.ExportGroup(groupID)
|
invite, _ := the.Peer.ExportGroup(groupID)
|
||||||
|
|
||||||
contactaddrs := the.Peer.GetContacts()
|
contactaddrs := the.Peer.GetContacts()
|
||||||
contactnames := make([]string, len(contactaddrs))
|
contactnames := make([]string, len(contactaddrs))
|
||||||
for i, contact := range contactaddrs {
|
for i, contact := range contactaddrs {
|
||||||
name, hasname := the.Peer.GetContact(contact).GetAttribute("nick")
|
name, hasname := the.Peer.GetContact(contact).GetAttribute(constants.Nick)
|
||||||
if hasname {
|
if hasname {
|
||||||
contactnames[i] = name
|
contactnames[i] = name
|
||||||
} else {
|
} else {
|
||||||
|
@ -356,24 +391,8 @@ func (this *GrandCentralDispatcher) requestGroupSettings(groupID string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) saveGroupSettings(groupID, nick string) {
|
func (this *GrandCentralDispatcher) saveGroupSettings(groupID, nick string) {
|
||||||
group := the.Peer.GetGroup(groupID)
|
the.Peer.SetGroupAttribute(groupID, constants.Nick, nick)
|
||||||
|
this.UpdateContactDisplayName(groupID, nick)
|
||||||
if group == nil {
|
|
||||||
log.Errorf("couldn't find group %v", groupID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
group.SetAttribute("nick", nick)
|
|
||||||
the.EventBus.Publish(event.NewEvent(event.SetGroupAttribute, map[event.Field]string{
|
|
||||||
event.GroupID: groupID,
|
|
||||||
event.Key: "nick",
|
|
||||||
event.Data: nick,
|
|
||||||
}))
|
|
||||||
|
|
||||||
cif, _ := this.UIState.contacts.Load(groupID)
|
|
||||||
c := cif.(*gobjects.Contact)
|
|
||||||
c.DisplayName = nick
|
|
||||||
this.UIState.UpdateContact(groupID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) broadcast(signal string) {
|
func (this *GrandCentralDispatcher) broadcast(signal string) {
|
||||||
|
@ -382,9 +401,19 @@ func (this *GrandCentralDispatcher) broadcast(signal string) {
|
||||||
log.Debugf("unhandled broadcast signal: %v", signal)
|
log.Debugf("unhandled broadcast signal: %v", signal)
|
||||||
case "ResetMessagePane":
|
case "ResetMessagePane":
|
||||||
this.ResetMessagePane()
|
this.ResetMessagePane()
|
||||||
|
case "ResetProfile":
|
||||||
|
this.ResetProfile()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *GrandCentralDispatcher) createContact(onion string) {
|
||||||
|
if contact := the.Peer.GetContact(onion); contact != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
the.Peer.AddContact(onion, onion, false)
|
||||||
|
the.Peer.PeerWithOnion(onion)
|
||||||
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) importString(str string) {
|
func (this *GrandCentralDispatcher) importString(str string) {
|
||||||
if len(str) < 5 {
|
if len(str) < 5 {
|
||||||
log.Debugf("ignoring short string")
|
log.Debugf("ignoring short string")
|
||||||
|
@ -435,7 +464,7 @@ func (this *GrandCentralDispatcher) importString(str string) {
|
||||||
_, err := base32.StdEncoding.DecodeString(strings.ToUpper(onion[:56]))
|
_, err := base32.StdEncoding.DecodeString(strings.ToUpper(onion[:56]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugln(err)
|
log.Debugln(err)
|
||||||
this.InvokePopup("bad format. missing characters?")
|
this.InvokePopup("bad format. missing handlers?")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,25 +472,26 @@ func (this *GrandCentralDispatcher) importString(str string) {
|
||||||
if checkc != nil {
|
if checkc != nil {
|
||||||
this.InvokePopup("already have this contact")
|
this.InvokePopup("already have this contact")
|
||||||
return //TODO: bring them to the duplicate
|
return //TODO: bring them to the duplicate
|
||||||
|
} else {
|
||||||
|
the.Peer.AddContact(name, onion, false)
|
||||||
|
the.Peer.PeerWithOnion(onion)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.UIState.AddContact(&gobjects.Contact{
|
this.GetUiManager(this.selectedProfile()).AddContact(onion)
|
||||||
Handle: onion,
|
|
||||||
DisplayName: name,
|
|
||||||
Image: cwutil.RandomProfileImage(onion),
|
|
||||||
Trusted: true,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) popup(str string) {
|
func (this *GrandCentralDispatcher) popup(str string) {
|
||||||
this.InvokePopup(str)
|
this.InvokePopup(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) updateNick(nick string) {
|
func (this *GrandCentralDispatcher) updateNick(onion, nick string) {
|
||||||
the.Peer.GetProfile().Name = nick
|
peer := the.CwtchApp.GetPeer(onion)
|
||||||
the.EventBus.Publish(event.NewEvent(event.SetProfileName, map[event.Field]string{
|
if peer != nil {
|
||||||
event.ProfileName: nick,
|
peer.GetProfile().Name = nick
|
||||||
}))
|
the.CwtchApp.GetEventBus(onion).Publish(event.NewEvent(event.SetProfileName, map[event.Field]string{
|
||||||
|
event.ProfileName: nick,
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) createGroup(server, groupName string) {
|
func (this *GrandCentralDispatcher) createGroup(server, groupName string) {
|
||||||
|
@ -471,21 +501,9 @@ func (this *GrandCentralDispatcher) createGroup(server, groupName string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.UIState.AddContact(&gobjects.Contact{
|
this.GetUiManager(this.selectedProfile()).AddContact(groupID)
|
||||||
Handle: groupID,
|
|
||||||
DisplayName: groupName,
|
|
||||||
Image: cwutil.RandomGroupImage(groupID),
|
|
||||||
Server: server,
|
|
||||||
Trusted: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
group := the.Peer.GetGroup(groupID)
|
the.Peer.SetGroupAttribute(groupID, constants.Nick, groupName)
|
||||||
group.SetAttribute("nick", groupName)
|
|
||||||
the.EventBus.Publish(event.NewEvent(event.SetGroupAttribute, map[event.Field]string{
|
|
||||||
event.GroupID: groupID,
|
|
||||||
event.Key: "nick",
|
|
||||||
event.Data: groupName,
|
|
||||||
}))
|
|
||||||
|
|
||||||
the.Peer.JoinServer(server)
|
the.Peer.JoinServer(server)
|
||||||
}
|
}
|
||||||
|
@ -495,7 +513,7 @@ func (this *GrandCentralDispatcher) blockPeer(onion string) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.InvokePopup("Error Blocking Peer: " + err.Error())
|
this.InvokePopup("Error Blocking Peer: " + err.Error())
|
||||||
}
|
}
|
||||||
this.UIState.UpdateContact(onion)
|
this.UpdateContactBlocked(onion, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) unblockPeer(onion string) {
|
func (this *GrandCentralDispatcher) unblockPeer(onion string) {
|
||||||
|
@ -504,7 +522,7 @@ func (this *GrandCentralDispatcher) unblockPeer(onion string) {
|
||||||
this.InvokePopup("Error Unblocking Peer: " + err.Error())
|
this.InvokePopup("Error Unblocking Peer: " + err.Error())
|
||||||
}
|
}
|
||||||
the.Peer.PeerWithOnion(onion)
|
the.Peer.PeerWithOnion(onion)
|
||||||
this.UIState.UpdateContact(onion)
|
this.UpdateContactBlocked(onion, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) inviteToGroup(onion, groupID string) {
|
func (this *GrandCentralDispatcher) inviteToGroup(onion, groupID string) {
|
||||||
|
@ -527,54 +545,28 @@ func (this *GrandCentralDispatcher) deleteContact(onion string) {
|
||||||
func (this *GrandCentralDispatcher) acceptGroup(groupID string) {
|
func (this *GrandCentralDispatcher) acceptGroup(groupID string) {
|
||||||
if the.Peer.GetGroup(groupID) != nil {
|
if the.Peer.GetGroup(groupID) != nil {
|
||||||
the.Peer.AcceptInvite(groupID)
|
the.Peer.AcceptInvite(groupID)
|
||||||
this.UIState.UpdateContact(groupID)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) setAttribute(onion, key, value string) {
|
func (this *GrandCentralDispatcher) setAttribute(onion, key, value string) {
|
||||||
pp, _ := the.Peer.GetProfile().GetContact(onion)
|
the.Peer.SetContactAttribute(onion, key, value)
|
||||||
if pp != nil {
|
this.GetUiManager(this.selectedProfile()).UpdateContactAttribute(onion, key, value)
|
||||||
pp.SetAttribute(key, value)
|
|
||||||
the.EventBus.Publish(event.NewEvent(event.SetPeerAttribute, map[event.Field]string{
|
|
||||||
event.RemotePeer: onion,
|
|
||||||
event.Key: key,
|
|
||||||
event.Data: value,
|
|
||||||
}))
|
|
||||||
this.UIState.UpdateContactAttribute(onion, key, value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) blockUnknownPeers() {
|
func (this *GrandCentralDispatcher) blockUnknownPeers() {
|
||||||
|
the.Peer.SetAttribute(constants.BlockUnknownPeersSetting, "true")
|
||||||
// Save this setting
|
|
||||||
the.EventBus.Publish(event.NewEvent(event.SetAttribute, map[event.Field]string{
|
|
||||||
event.Key: constants.BlockUnknownPeersSetting,
|
|
||||||
event.Data: "true",
|
|
||||||
}))
|
|
||||||
|
|
||||||
the.Peer.GetProfile().SetAttribute(constants.BlockUnknownPeersSetting, "true")
|
|
||||||
the.EventBus.Publish(event.NewEvent(event.BlockUnknownPeers, map[event.Field]string{}))
|
the.EventBus.Publish(event.NewEvent(event.BlockUnknownPeers, map[event.Field]string{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) allowUnknownPeers() {
|
func (this *GrandCentralDispatcher) allowUnknownPeers() {
|
||||||
|
the.Peer.SetAttribute(constants.BlockUnknownPeersSetting, "false")
|
||||||
// Save this setting
|
|
||||||
the.EventBus.Publish(event.NewEvent(event.SetAttribute, map[event.Field]string{
|
|
||||||
event.Key: constants.BlockUnknownPeersSetting,
|
|
||||||
event.Data: "false",
|
|
||||||
}))
|
|
||||||
|
|
||||||
the.Peer.GetProfile().SetAttribute(constants.BlockUnknownPeersSetting, "false")
|
|
||||||
the.EventBus.Publish(event.NewEvent(event.AllowUnknownPeers, map[event.Field]string{}))
|
the.EventBus.Publish(event.NewEvent(event.AllowUnknownPeers, map[event.Field]string{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) setLocale(locale string) {
|
func (this *GrandCentralDispatcher) setLocale(locale string) {
|
||||||
this.SetLocale_helper(locale)
|
this.SetLocale_helper(locale)
|
||||||
|
|
||||||
the.EventBus.Publish(event.NewEvent(event.SetAttribute, map[event.Field]string{
|
the.Peer.SetAttribute(constants.LocaleSetting, locale)
|
||||||
event.Key: constants.LocaleSetting,
|
|
||||||
event.Data: locale,
|
|
||||||
}))
|
|
||||||
|
|
||||||
zoom, _ := the.Peer.GetProfile().GetAttribute(constants.ZoomSetting)
|
zoom, _ := the.Peer.GetProfile().GetAttribute(constants.ZoomSetting)
|
||||||
blockunkownpeers, _ := the.Peer.GetProfile().GetAttribute(constants.BlockUnknownPeersSetting)
|
blockunkownpeers, _ := the.Peer.GetProfile().GetAttribute(constants.BlockUnknownPeersSetting)
|
||||||
|
@ -582,6 +574,13 @@ func (this *GrandCentralDispatcher) setLocale(locale string) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *GrandCentralDispatcher) onActivate() {
|
||||||
|
log.Debugln("onActivate")
|
||||||
|
if the.CwtchApp != nil {
|
||||||
|
the.CwtchApp.QueryACNStatus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) SetLocale_helper(locale string) {
|
func (this *GrandCentralDispatcher) SetLocale_helper(locale string) {
|
||||||
core.QCoreApplication_RemoveTranslator(this.Translator)
|
core.QCoreApplication_RemoveTranslator(this.Translator)
|
||||||
this.Translator = core.NewQTranslator(nil)
|
this.Translator = core.NewQTranslator(nil)
|
||||||
|
@ -589,3 +588,72 @@ func (this *GrandCentralDispatcher) SetLocale_helper(locale string) {
|
||||||
core.QCoreApplication_InstallTranslator(this.Translator)
|
core.QCoreApplication_InstallTranslator(this.Translator)
|
||||||
this.QMLEngine.Retranslate()
|
this.QMLEngine.Retranslate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *GrandCentralDispatcher) unlockProfiles(password string) {
|
||||||
|
the.CwtchApp.LoadProfiles(password)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *GrandCentralDispatcher) loadProfile(onion string) {
|
||||||
|
the.Peer = the.CwtchApp.GetPeer(onion)
|
||||||
|
the.EventBus = the.CwtchApp.GetEventBus(onion)
|
||||||
|
|
||||||
|
pic, exists := the.Peer.GetAttribute(constants.Picture)
|
||||||
|
if !exists {
|
||||||
|
pic = RandomProfileImage(the.Peer.GetProfile().Onion)
|
||||||
|
the.Peer.SetAttribute(constants.Picture, pic)
|
||||||
|
}
|
||||||
|
this.UpdateMyProfile(the.Peer.GetProfile().Name, the.Peer.GetProfile().Onion, pic)
|
||||||
|
|
||||||
|
contacts := the.Peer.GetContacts()
|
||||||
|
for i := range contacts {
|
||||||
|
this.GetUiManager(this.selectedProfile()).AddContact(contacts[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
groups := the.Peer.GetGroups()
|
||||||
|
for i := range groups {
|
||||||
|
// Only join servers for active and explicitly accepted groups.
|
||||||
|
this.GetUiManager(this.selectedProfile()).AddContact(groups[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// load ui preferences
|
||||||
|
this.RequestSettings()
|
||||||
|
locale, exists := the.Peer.GetProfile().GetAttribute(constants.LocaleSetting)
|
||||||
|
if exists {
|
||||||
|
this.SetLocale_helper(locale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *GrandCentralDispatcher) createProfile(nick string, defaultPass bool, password string) {
|
||||||
|
if defaultPass {
|
||||||
|
the.CwtchApp.CreateTaggedPeer(nick, the.AppPassword, constants.ProfileTypeV1DefaultPassword)
|
||||||
|
} else {
|
||||||
|
the.CwtchApp.CreateTaggedPeer(nick, password, constants.ProfileTypeV1Password)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *GrandCentralDispatcher) changePassword(onion, currentPassword, newPassword string, defaultPass bool) {
|
||||||
|
tag, _ := the.CwtchApp.GetPeer(onion).GetAttribute(app.AttributeTag)
|
||||||
|
|
||||||
|
if tag == constants.ProfileTypeV1DefaultPassword {
|
||||||
|
currentPassword = the.AppPassword
|
||||||
|
}
|
||||||
|
|
||||||
|
if defaultPass {
|
||||||
|
newPassword = the.AppPassword
|
||||||
|
}
|
||||||
|
|
||||||
|
the.CwtchApp.ChangePeerPassword(onion, currentPassword, newPassword)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *GrandCentralDispatcher) reloadProfileList() {
|
||||||
|
this.ResetProfileList()
|
||||||
|
|
||||||
|
for onion, _ := range the.CwtchApp.ListPeers() {
|
||||||
|
AddProfile(this, onion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *GrandCentralDispatcher) deleteProfile(onion string) {
|
||||||
|
log.Infof("deleteProfile %v\n", onion)
|
||||||
|
the.CwtchApp.DeletePeer(onion)
|
||||||
|
}
|
|
@ -0,0 +1,281 @@
|
||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cwtch.im/cwtch/app"
|
||||||
|
"cwtch.im/cwtch/model"
|
||||||
|
"cwtch.im/cwtch/protocol/connections"
|
||||||
|
"cwtch.im/ui/go/constants"
|
||||||
|
"cwtch.im/ui/go/the"
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
||||||
|
"runtime/debug"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func isGroup(id string) bool {
|
||||||
|
return len(id) == 32
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPeer(id string) bool {
|
||||||
|
return len(id) == 56
|
||||||
|
}
|
||||||
|
|
||||||
|
func getOrDefault(id, key, defaultVal string) string {
|
||||||
|
var val string
|
||||||
|
var ok bool
|
||||||
|
if isGroup(id) {
|
||||||
|
val, ok = the.Peer.GetGroupAttribute(id, key)
|
||||||
|
} else {
|
||||||
|
val, ok = the.Peer.GetContactAttribute(id, key)
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
return val
|
||||||
|
} else {
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getWithSetDefault(id string, key, defaultVal string) string {
|
||||||
|
var val string
|
||||||
|
var ok bool
|
||||||
|
if isGroup(id) {
|
||||||
|
val, ok = the.Peer.GetGroupAttribute(id, key)
|
||||||
|
} else {
|
||||||
|
val, ok = the.Peer.GetContactAttribute(id, key)
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
val = defaultVal
|
||||||
|
if isGroup(id) {
|
||||||
|
the.Peer.SetGroupAttribute(id, key, defaultVal)
|
||||||
|
} else {
|
||||||
|
the.Peer.SetContactAttribute(id, key, defaultVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
// initLastReadTime checks and gets the Attributable's LastRead time or sets it to now
|
||||||
|
func initLastReadTime(id string) time.Time {
|
||||||
|
nowStr, _ := time.Now().MarshalText()
|
||||||
|
lastReadStr := getWithSetDefault(id, constants.LastRead, string(nowStr))
|
||||||
|
var lastRead time.Time
|
||||||
|
lastRead.UnmarshalText([]byte(lastReadStr))
|
||||||
|
return lastRead
|
||||||
|
}
|
||||||
|
|
||||||
|
func initProfilePicture(id string) string {
|
||||||
|
if isGroup(id) {
|
||||||
|
return getWithSetDefault(id, constants.Picture, RandomGroupImage(id))
|
||||||
|
} else {
|
||||||
|
return getWithSetDefault(id, constants.Picture, RandomProfileImage(id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getProfilePic supplies a profile pic to use. In groups we may not have a contact so it will generate one
|
||||||
|
func getProfilePic(id string) string {
|
||||||
|
if isGroup(id) {
|
||||||
|
if pic, exists := the.Peer.GetGroupAttribute(id, constants.Picture); !exists {
|
||||||
|
return RandomGroupImage(id)
|
||||||
|
} else {
|
||||||
|
return pic
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if pic, exists := the.Peer.GetContactAttribute(id, constants.Picture); !exists {
|
||||||
|
return RandomProfileImage(id)
|
||||||
|
} else {
|
||||||
|
return pic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateLastReadTime(id string) {
|
||||||
|
lastRead, _ := time.Now().MarshalText()
|
||||||
|
if isGroup(id) {
|
||||||
|
the.Peer.SetGroupAttribute(id, constants.LastRead, string(lastRead))
|
||||||
|
} else {
|
||||||
|
the.Peer.SetContactAttribute(id, constants.LastRead, string(lastRead))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func countUnread(messages []model.Message, lastRead time.Time) int {
|
||||||
|
count := 0
|
||||||
|
for i := len(messages) - 1; i >= 0; i-- {
|
||||||
|
if messages[i].Timestamp.After(lastRead) || messages[i].Timestamp.Equal(lastRead) {
|
||||||
|
count++
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddProfile adds a new profile to the UI
|
||||||
|
func AddProfile(gcd *GrandCentralDispatcher, handle string) {
|
||||||
|
peer := the.CwtchApp.GetPeer(handle)
|
||||||
|
if peer != nil {
|
||||||
|
nick := peer.GetProfile().Name
|
||||||
|
if nick == "" {
|
||||||
|
nick = handle
|
||||||
|
peer.SetAttribute(constants.Nick, nick)
|
||||||
|
}
|
||||||
|
|
||||||
|
pic, ok := peer.GetAttribute(constants.Picture)
|
||||||
|
if !ok {
|
||||||
|
pic = RandomProfileImage(handle)
|
||||||
|
peer.SetAttribute(constants.Picture, pic)
|
||||||
|
}
|
||||||
|
|
||||||
|
tag, _ := peer.GetAttribute(app.AttributeTag)
|
||||||
|
log.Infof("AddProfile %v %v %v %v\n", handle, nick, pic, tag)
|
||||||
|
gcd.AddProfile(handle, nick, pic, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type manager struct {
|
||||||
|
gcd *GrandCentralDispatcher
|
||||||
|
profile string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manager is a middleware helper for entities like peer event listeners wishing to trigger ui changes (via the gcd)
|
||||||
|
// each manager is for one profile/peer
|
||||||
|
// manager takes minimal arguments and builds the full struct of data (usually pulled from a cwtch peer) required to call the GCD to perform the ui action
|
||||||
|
// 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)
|
||||||
|
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)
|
||||||
|
|
||||||
|
ReloadProfiles()
|
||||||
|
|
||||||
|
UpdateContactDisplayName(handle string, name string)
|
||||||
|
UpdateContactStatus(handle string, status int, loading bool)
|
||||||
|
UpdateContactAttribute(handle, key, value string)
|
||||||
|
|
||||||
|
ChangePasswordResponse(error bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewManager returns a new Manager interface for a profile to the gcd
|
||||||
|
func NewManager(profile string, gcd *GrandCentralDispatcher) Manager {
|
||||||
|
return &manager{gcd: gcd, profile: profile}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acknowledge acknowledges the given message id in the UI
|
||||||
|
func (this *manager) Acknowledge(mID string) {
|
||||||
|
this.gcd.DoIfProfile(this.profile, func() {
|
||||||
|
this.gcd.Acknowledged(mID)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLastMessageTime(tl *model.Timeline) int {
|
||||||
|
if len(tl.Messages) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(tl.Messages[len(tl.Messages)-1].Timestamp.Unix())
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddContact adds a new contact to the ui for this manager's profile
|
||||||
|
func (this *manager) AddContact(Handle string) {
|
||||||
|
this.gcd.DoIfProfile(this.profile, func() {
|
||||||
|
|
||||||
|
if isGroup(Handle) {
|
||||||
|
group := the.Peer.GetGroup(Handle)
|
||||||
|
if group != nil {
|
||||||
|
lastRead := initLastReadTime(group.GroupID)
|
||||||
|
unread := countUnread(group.Timeline.GetMessages(), lastRead)
|
||||||
|
picture := initProfilePicture(Handle)
|
||||||
|
nick, exists := group.GetAttribute(constants.Nick)
|
||||||
|
if !exists {
|
||||||
|
nick = Handle
|
||||||
|
}
|
||||||
|
|
||||||
|
this.gcd.AddContact(Handle, nick, picture, group.GroupServer, unread, int(connections.ConnectionStateToType[group.State]), false, false, getLastMessageTime(&group.Timeline))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else if !isPeer(Handle) {
|
||||||
|
log.Errorf("sorry, unable to handle AddContact(%v)", Handle)
|
||||||
|
debug.PrintStack()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
contact := the.Peer.GetContact(Handle)
|
||||||
|
if contact != nil {
|
||||||
|
lastRead := initLastReadTime(contact.Onion)
|
||||||
|
unread := countUnread(contact.Timeline.GetMessages(), lastRead)
|
||||||
|
picture := initProfilePicture(Handle)
|
||||||
|
nick, exists := contact.GetAttribute(constants.Nick)
|
||||||
|
if !exists {
|
||||||
|
nick = Handle
|
||||||
|
}
|
||||||
|
|
||||||
|
this.gcd.AddContact(Handle, nick, picture, "", unread, int(connections.ConnectionStateToType[contact.State]), contact.Blocked, false, getLastMessageTime(&contact.Timeline))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddSendMessageError adds an error not and icon to a message in a conversation in the ui for the message identified by the peer/sig combo
|
||||||
|
func (this *manager) AddSendMessageError(peer string, signature string, err string) {
|
||||||
|
this.gcd.DoIfProfile(this.profile, func() {
|
||||||
|
this.gcd.DoIfConversation(peer, func() {
|
||||||
|
log.Debugf("Received Error Sending Message: %v", err)
|
||||||
|
// FIXME: Sometimes, for the first Peer message we send our error beats our message to the UI
|
||||||
|
time.Sleep(time.Second * 1)
|
||||||
|
this.gcd.GroupSendError(signature, err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 := getOrDefault(handle, constants.Nick, 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.Format(constants.TIME_FORMAT), false, false)
|
||||||
|
} else {
|
||||||
|
if !Acknowledged {
|
||||||
|
this.gcd.AppendMessage(handle, from, nick, message, image, messageID, fromMe, timestamp.Format(constants.TIME_FORMAT), false, false)
|
||||||
|
} else {
|
||||||
|
this.gcd.Acknowledged(messageID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.gcd.IncContactUnreadCount(handle)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *manager) ReloadProfiles() {
|
||||||
|
this.gcd.reloadProfileList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateContactDisplayName updates a contact's display name in the contact list and conversations
|
||||||
|
func (this *manager) UpdateContactDisplayName(handle string, name string) {
|
||||||
|
this.gcd.DoIfProfile(this.profile, func() {
|
||||||
|
this.gcd.UpdateContactDisplayName(handle, name)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateContactStatus updates a contact's status in the ui
|
||||||
|
func (this *manager) UpdateContactStatus(handle string, status int, loading bool) {
|
||||||
|
this.gcd.DoIfProfile(this.profile, func() {
|
||||||
|
this.gcd.UpdateContactStatus(handle, status, loading)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateContactAttribute update's a contacts attribute in the ui
|
||||||
|
func (this *manager) UpdateContactAttribute(handle, key, value string) {
|
||||||
|
this.gcd.DoIfProfile(this.profile, func() {
|
||||||
|
this.gcd.UpdateContactAttribute(handle, key, value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *manager) ChangePasswordResponse(error bool) {
|
||||||
|
this.gcd.ChangePasswordResponse(error)
|
||||||
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
package cwutil
|
package ui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base32"
|
"encoding/base32"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
@ -23,7 +22,7 @@ func RandomGroupImage(handle string) string {
|
||||||
choices := []string{"001-borobudur", "002-opera-house", "003-burj-al-arab", "004-chrysler", "005-acropolis", "006-empire-state-building", "007-temple", "008-indonesia-1", "009-new-zealand", "010-notre-dame", "011-space-needle", "012-seoul", "013-mosque", "014-milan", "015-statue", "016-pyramid", "017-cologne", "018-brandenburg-gate", "019-berlin-cathedral", "020-hungarian-parliament", "021-buckingham", "022-thailand", "023-independence", "024-angkor-wat", "025-vaticano", "026-christ-the-redeemer", "027-colosseum", "028-golden-gate-bridge", "029-sphinx", "030-statue-of-liberty", "031-cradle-of-humankind", "032-istanbul", "033-london-eye", "034-sagrada-familia", "035-tower-bridge", "036-burj-khalifa", "037-washington", "038-big-ben", "039-stonehenge", "040-white-house", "041-ahu-tongariki", "042-capitol", "043-eiffel-tower", "044-church-of-the-savior-on-spilled-blood", "045-arc-de-triomphe", "046-windmill", "047-louvre", "048-torii-gate", "049-petronas", "050-matsumoto-castle", "051-fuji", "052-temple-of-heaven", "053-pagoda", "054-chichen-itza", "055-forbidden-city", "056-merlion", "057-great-wall-of-china", "058-taj-mahal", "059-pisa", "060-indonesia"}
|
choices := []string{"001-borobudur", "002-opera-house", "003-burj-al-arab", "004-chrysler", "005-acropolis", "006-empire-state-building", "007-temple", "008-indonesia-1", "009-new-zealand", "010-notre-dame", "011-space-needle", "012-seoul", "013-mosque", "014-milan", "015-statue", "016-pyramid", "017-cologne", "018-brandenburg-gate", "019-berlin-cathedral", "020-hungarian-parliament", "021-buckingham", "022-thailand", "023-independence", "024-angkor-wat", "025-vaticano", "026-christ-the-redeemer", "027-colosseum", "028-golden-gate-bridge", "029-sphinx", "030-statue-of-liberty", "031-cradle-of-humankind", "032-istanbul", "033-london-eye", "034-sagrada-familia", "035-tower-bridge", "036-burj-khalifa", "037-washington", "038-big-ben", "039-stonehenge", "040-white-house", "041-ahu-tongariki", "042-capitol", "043-eiffel-tower", "044-church-of-the-savior-on-spilled-blood", "045-arc-de-triomphe", "046-windmill", "047-louvre", "048-torii-gate", "049-petronas", "050-matsumoto-castle", "051-fuji", "052-temple-of-heaven", "053-pagoda", "054-chichen-itza", "055-forbidden-city", "056-merlion", "057-great-wall-of-china", "058-taj-mahal", "059-pisa", "060-indonesia"}
|
||||||
barr, err := hex.DecodeString(handle)
|
barr, err := hex.DecodeString(handle)
|
||||||
if err != nil || len(barr) == 0 {
|
if err != nil || len(barr) == 0 {
|
||||||
fmt.Printf("error: %v %v %v\n", handle, err, barr)
|
log.Errorf("error: %v %v %v\n", handle, err, barr)
|
||||||
return "qrc:/qml/images/extra/openprivacy.png"
|
return "qrc:/qml/images/extra/openprivacy.png"
|
||||||
}
|
}
|
||||||
return "servers/" + choices[int(barr[0])%len(choices)] + ".png"
|
return "servers/" + choices[int(barr[0])%len(choices)] + ".png"
|
|
@ -4,239 +4,469 @@
|
||||||
<context>
|
<context>
|
||||||
<name>AddGroupPane</name>
|
<name>AddGroupPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="19"/>
|
||||||
<source>create-group-title</source>
|
<source>create-group-title</source>
|
||||||
<translation type="vanished">Gruppe Anlegen</translation>
|
<translation>Gruppe Anlegen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="42"/>
|
||||||
<source>server-label</source>
|
<source>server-label</source>
|
||||||
<extracomment>Server label</extracomment>
|
<extracomment>Server label</extracomment>
|
||||||
<translation type="vanished">Server</translation>
|
<translation>Server</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="53"/>
|
||||||
<source>group-name-label</source>
|
<source>group-name-label</source>
|
||||||
<extracomment>Group name label</extracomment>
|
<extracomment>Group name label</extracomment>
|
||||||
<translation type="vanished">Gruppenname</translation>
|
<translation>Gruppenname</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="60"/>
|
||||||
<source>default-group-name</source>
|
<source>default-group-name</source>
|
||||||
<extracomment>default suggested group name</extracomment>
|
<extracomment>default suggested group name</extracomment>
|
||||||
<translation type="vanished">Tolle Gruppe</translation>
|
<translation>Tolle Gruppe</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="65"/>
|
||||||
<source>create-group-btn</source>
|
<source>create-group-btn</source>
|
||||||
<extracomment>create group button</extracomment>
|
<extracomment>create group button</extracomment>
|
||||||
<translation type="vanished">Anlegen</translation>
|
<translation>Anlegen</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>BulletinOverlay</name>
|
<name>BulletinOverlay</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/BulletinOverlay.qml" line="203"/>
|
||||||
<source>new-bulletin-label</source>
|
<source>new-bulletin-label</source>
|
||||||
<translation type="vanished">Neue Meldung</translation>
|
<translation>Neue Meldung</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/BulletinOverlay.qml" line="215"/>
|
||||||
<source>post-new-bulletin-label</source>
|
<source>post-new-bulletin-label</source>
|
||||||
<extracomment>Post a new Bulletin Post</extracomment>
|
<extracomment>Post a new Bulletin Post</extracomment>
|
||||||
<translation type="vanished">Neue Meldung veröffentlichen</translation>
|
<translation>Neue Meldung veröffentlichen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/BulletinOverlay.qml" line="221"/>
|
||||||
<source>title-placeholder</source>
|
<source>title-placeholder</source>
|
||||||
<extracomment>title place holder text</extracomment>
|
<extracomment>title place holder text</extracomment>
|
||||||
<translation type="vanished">Titel...</translation>
|
<translation>Titel...</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>GroupSettingsPane</name>
|
<name>GroupSettingsPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="42"/>
|
||||||
<source>server-label</source>
|
<source>server-label</source>
|
||||||
<translation type="vanished">Server</translation>
|
<translation>Server</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="53"/>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="74"/>
|
||||||
<source>copy-btn</source>
|
<source>copy-btn</source>
|
||||||
<translation type="vanished">Kopieren</translation>
|
<translation>Kopieren</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="63"/>
|
||||||
<source>invitation-label</source>
|
<source>invitation-label</source>
|
||||||
<translation type="vanished">Einladung</translation>
|
<translation>Einladung</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="84"/>
|
||||||
<source>group-name-label</source>
|
<source>group-name-label</source>
|
||||||
<translation type="vanished">Gruppenname</translation>
|
<translation>Gruppenname</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="93"/>
|
||||||
<source>save-btn</source>
|
<source>save-btn</source>
|
||||||
<translation type="vanished">Speichern</translation>
|
<translation>Speichern</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="103"/>
|
||||||
<source>invite-to-group-label</source>
|
<source>invite-to-group-label</source>
|
||||||
<extracomment>Invite someone to the group</extracomment>
|
<extracomment>Invite someone to the group</extracomment>
|
||||||
<translation type="vanished">In die Gruppe einladen</translation>
|
<translation>In die Gruppe einladen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="114"/>
|
||||||
<source>invite-btn</source>
|
<source>invite-btn</source>
|
||||||
<translation type="vanished">Einladen</translation>
|
<translation>Einladen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="123"/>
|
||||||
<source>delete-btn</source>
|
<source>delete-btn</source>
|
||||||
<translation type="vanished">Löschen</translation>
|
<translation>Löschen</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>InplaceEditText</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/widgets/InplaceEditText.qml" line="85"/>
|
||||||
|
<source>Update</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ListOverlay</name>
|
<name>ListOverlay</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/ListOverlay.qml" line="184"/>
|
||||||
<source>add-list-item</source>
|
<source>add-list-item</source>
|
||||||
<extracomment>Add a New List Item</extracomment>
|
<extracomment>Add a New List Item</extracomment>
|
||||||
<translation type="vanished">Liste hinzufügen</translation>
|
<translation>Liste hinzufügen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/ListOverlay.qml" line="196"/>
|
||||||
<source>add-new-item</source>
|
<source>add-new-item</source>
|
||||||
<extracomment>Add a new item to the list</extracomment>
|
<extracomment>Add a new item to the list</extracomment>
|
||||||
<translation type="vanished">Neues Listenelement hinzüfgen</translation>
|
<translation>Neues Listenelement hinzüfgen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/ListOverlay.qml" line="202"/>
|
||||||
<source>todo-placeholder</source>
|
<source>todo-placeholder</source>
|
||||||
<extracomment>Todo... placeholder text</extracomment>
|
<extracomment>Todo... placeholder text</extracomment>
|
||||||
<translation type="vanished">noch zu erledigen</translation>
|
<translation>noch zu erledigen</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>MembershipOverlay</name>
|
<name>MembershipOverlay</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/MembershipOverlay.qml" line="21"/>
|
||||||
<source>membership-description</source>
|
<source>membership-description</source>
|
||||||
<extracomment>Below is a list of users who have sent messages to the group. This list may not reflect all users who have access to the group.</extracomment>
|
<extracomment>Below is a list of users who have sent messages to the group. This list may not reflect all users who have access to the group.</extracomment>
|
||||||
<translation type="vanished">Unten steht eine Liste der Benutzer, die Nachrichten an die Gruppe gesendet haben. Möglicherweise enthält diese Benutzerzliste nicht alle, die Zugang zur Gruppe haben.</translation>
|
<translation>Unten steht eine Liste der Benutzer, die Nachrichten an die Gruppe gesendet haben. Möglicherweise enthält diese Benutzerzliste nicht alle, die Zugang zur Gruppe haben.</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>Message</name>
|
<name>Message</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/Message.qml" line="56"/>
|
||||||
<source>dm-tooltip</source>
|
<source>dm-tooltip</source>
|
||||||
<extracomment>Click to DM</extracomment>
|
<extracomment>Click to DM</extracomment>
|
||||||
<translation type="vanished">Klicken, um DM zu senden</translation>
|
<translation>Klicken, um DM zu senden</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>could-not-send-msg-error</source>
|
<source>could-not-send-msg-error</source>
|
||||||
<extracomment>Could not send this message</extracomment>
|
<extracomment>Could not send this message</extracomment>
|
||||||
<translation type="vanished">Nachricht konnte nicht gesendet werden</translation>
|
<translation>Nachricht konnte nicht gesendet werden</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>acknowledged-label</source>
|
<source>acknowledged-label</source>
|
||||||
<translation type="vanished">bestätigt</translation>
|
<translation>bestätigt</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>pending-label</source>
|
<source>pending-label</source>
|
||||||
<translation type="vanished">Bestätigung ausstehend</translation>
|
<translation>Bestätigung ausstehend</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>MyProfile</name>
|
<name>MyProfile</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/MyProfile.qml" line="185"/>
|
||||||
<source>copy-btn</source>
|
<source>copy-btn</source>
|
||||||
<extracomment>Button for copying profile onion address to clipboard</extracomment>
|
<extracomment>Button for copying profile onion address to clipboard</extracomment>
|
||||||
<translation type="vanished">Kopieren</translation>
|
<translation>Kopieren</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/MyProfile.qml" line="189"/>
|
||||||
<source>copied-clipboard-notification</source>
|
<source>copied-clipboard-notification</source>
|
||||||
<extracomment>Copied to clipboard</extracomment>
|
<extracomment>Copied to clipboard</extracomment>
|
||||||
<translation type="vanished">in die Zwischenablage kopiert</translation>
|
<translation>in die Zwischenablage kopiert</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/MyProfile.qml" line="219"/>
|
||||||
<source>new-group-btn</source>
|
<source>new-group-btn</source>
|
||||||
<extracomment>create new group button</extracomment>
|
<extracomment>create new group button</extracomment>
|
||||||
<translation type="vanished">Neue Gruppe anlegen</translation>
|
<translation>Neue Gruppe anlegen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/MyProfile.qml" line="229"/>
|
||||||
<source>paste-address-to-add-contact</source>
|
<source>paste-address-to-add-contact</source>
|
||||||
<extracomment>ex: "... paste an address here to add a contact ..."</extracomment>
|
<extracomment>ex: "... paste an address here to add a contact ..."</extracomment>
|
||||||
<translation type="vanished">Adresse hier hinzufügen, um einen Kontakt aufzunehmen</translation>
|
<translation>Adresse hier hinzufügen, um einen Kontakt aufzunehmen</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>OverlayPane</name>
|
<name>OverlayPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="44"/>
|
||||||
<source>accept-group-invite-label</source>
|
<source>accept-group-invite-label</source>
|
||||||
<extracomment>Do you want to accept the invitation to $GROUP</extracomment>
|
<extracomment>Do you want to accept the invitation to $GROUP</extracomment>
|
||||||
<translation type="vanished">Möchtest Du die Einladung annehmen</translation>
|
<translation>Möchtest Du die Einladung annehmen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="49"/>
|
||||||
<source>accept-group-btn</source>
|
<source>accept-group-btn</source>
|
||||||
<extracomment>Accept group invite button</extracomment>
|
<extracomment>Accept group invite button</extracomment>
|
||||||
<translation type="vanished">Annehmen</translation>
|
<translation>Annehmen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="59"/>
|
||||||
<source>reject-group-btn</source>
|
<source>reject-group-btn</source>
|
||||||
<extracomment>Reject Group invite button</extracomment>
|
<extracomment>Reject Group invite button</extracomment>
|
||||||
<translation type="vanished">Ablehnen</translation>
|
<translation>Ablehnen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="73"/>
|
||||||
<source>chat-btn</source>
|
<source>chat-btn</source>
|
||||||
<translation type="vanished">Chat</translation>
|
<translation>Chat</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="80"/>
|
||||||
<source>lists-btn</source>
|
<source>lists-btn</source>
|
||||||
<translation type="vanished">Listen</translation>
|
<translation>Listen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="87"/>
|
||||||
<source>bulletins-btn</source>
|
<source>bulletins-btn</source>
|
||||||
<translation type="vanished">Meldungen</translation>
|
<translation>Meldungen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="94"/>
|
||||||
<source>puzzle-game-btn</source>
|
<source>puzzle-game-btn</source>
|
||||||
<translation type="vanished">Puzzlespiel</translation>
|
<translation>Puzzlespiel</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PeerSettingsPane</name>
|
<name>PeerSettingsPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="42"/>
|
||||||
<source>address-label</source>
|
<source>address-label</source>
|
||||||
<translation type="vanished">Adresse</translation>
|
<translation>Adresse</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="53"/>
|
||||||
<source>copy-btn</source>
|
<source>copy-btn</source>
|
||||||
<translation type="vanished">Kopieren</translation>
|
<translation>Kopieren</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="57"/>
|
||||||
<source>copied-to-clipboard-notification</source>
|
<source>copied-to-clipboard-notification</source>
|
||||||
<extracomment>notification: copied to clipboard</extracomment>
|
<extracomment>notification: copied to clipboard</extracomment>
|
||||||
<translation type="vanished">in die Zwischenablage kopiert</translation>
|
<translation>in die Zwischenablage kopiert</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="64"/>
|
||||||
<source>display-name-label</source>
|
<source>display-name-label</source>
|
||||||
<translation type="vanished">Angezeigter Name</translation>
|
<translation>Angezeigter Name</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="73"/>
|
||||||
<source>save-btn</source>
|
<source>save-btn</source>
|
||||||
<translation type="vanished">speichern</translation>
|
<translation>speichern</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="85"/>
|
||||||
|
<source>block-btn</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="85"/>
|
||||||
|
<source>unblock-btn</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="99"/>
|
||||||
<source>delete-btn</source>
|
<source>delete-btn</source>
|
||||||
<translation type="vanished">löschen</translation>
|
<translation>löschen</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ProfileAddEditPane</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="24"/>
|
||||||
|
<source>add-profile-title</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="24"/>
|
||||||
|
<source>edit-profile-title</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="92"/>
|
||||||
|
<source>profile-name</source>
|
||||||
|
<extracomment>Display name</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="32"/>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="100"/>
|
||||||
|
<source>default-profile-name</source>
|
||||||
|
<extracomment>default suggested profile name</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="81"/>
|
||||||
|
<source>profile-onion-label</source>
|
||||||
|
<extracomment>Onion</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="112"/>
|
||||||
|
<source>radio-use-password</source>
|
||||||
|
<extracomment>Password</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="122"/>
|
||||||
|
<source>radio-no-password</source>
|
||||||
|
<extracomment>Unencrypted (No password)</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="133"/>
|
||||||
|
<source>no-password-warning</source>
|
||||||
|
<extracomment>Not using a password on this account means that all data stored locally will not be encrypted</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="140"/>
|
||||||
|
<source>current-password-label</source>
|
||||||
|
<extracomment>Current Password</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="154"/>
|
||||||
|
<source>password1-label</source>
|
||||||
|
<extracomment>Password</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="174"/>
|
||||||
|
<source>password2-label</source>
|
||||||
|
<extracomment>Reenter password</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="188"/>
|
||||||
|
<source>create-profile-btn</source>
|
||||||
|
<extracomment>Create Profile || Save Profile</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="188"/>
|
||||||
|
<source>save-profile-btn</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="217"/>
|
||||||
|
<source>password-error-match</source>
|
||||||
|
<extracomment>Passwords do not match</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="225"/>
|
||||||
|
<source>password-change-error</source>
|
||||||
|
<extracomment>Error changing password: Supplied password rejected</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="234"/>
|
||||||
|
<source>delete-profile-btn</source>
|
||||||
|
<extracomment>Delete Profile</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="247"/>
|
||||||
|
<source>delete-confirm-label</source>
|
||||||
|
<extracomment>Type DELETE to confirm</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="263"/>
|
||||||
|
<source>delete-profile-confirm-btn</source>
|
||||||
|
<extracomment>Really Delete Profile</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="269"/>
|
||||||
|
<source>delete-confirm-text</source>
|
||||||
|
<extracomment>DELETE</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ProfileList</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/widgets/ProfileList.qml" line="88"/>
|
||||||
|
<location filename="../qml/widgets/ProfileList.qml" line="101"/>
|
||||||
|
<source>add-new-profile-btn</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ProfileManagerPane</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileManagerPane.qml" line="26"/>
|
||||||
|
<source>enter-profile-password</source>
|
||||||
|
<extracomment>Please enter password:</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileManagerPane.qml" line="42"/>
|
||||||
|
<source>error-0-profiles-loaded-for-password</source>
|
||||||
|
<extracomment>0 profiles loaded with that password</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileManagerPane.qml" line="52"/>
|
||||||
|
<source>unlock</source>
|
||||||
|
<extracomment>Unlock</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>SettingsPane</name>
|
<name>SettingsPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="21"/>
|
||||||
<source>cwtch-settings-title</source>
|
<source>cwtch-settings-title</source>
|
||||||
<extracomment>Cwtch Settings title</extracomment>
|
<extracomment>Cwtch Settings title</extracomment>
|
||||||
<translation type="vanished">Cwtch Einstellungen</translation>
|
<translation>Cwtch Einstellungen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="47"/>
|
||||||
|
<source>version %1 builddate %2</source>
|
||||||
|
<extracomment>Version: %1 Built on: %2</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="54"/>
|
||||||
<source>zoom-label</source>
|
<source>zoom-label</source>
|
||||||
<extracomment>Interface zoom (mostly affects text and button sizes)</extracomment>
|
<extracomment>Interface zoom (mostly affects text and button sizes)</extracomment>
|
||||||
<translation type="vanished">Benutzeroberflächen-Zoom (betriftt hauptsächlich Text- und Knopgrößen)</translation>
|
<translation>Benutzeroberflächen-Zoom (betriftt hauptsächlich Text- und Knopgrößen)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="83"/>
|
||||||
|
<source>block-unknown-label</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="90"/>
|
||||||
<source>large-text-label</source>
|
<source>large-text-label</source>
|
||||||
<translation type="vanished">Groß</translation>
|
<translation>Groß</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="98"/>
|
||||||
<source>default-scaling-text</source>
|
<source>default-scaling-text</source>
|
||||||
<extracomment>"Default size text (scale factor: "</extracomment>
|
<extracomment>"Default size text (scale factor: "</extracomment>
|
||||||
<translation type="vanished">defaultmäßige Textgröße (Skalierungsfaktor:</translation>
|
<translation>defaultmäßige Textgröße (Skalierungsfaktor:</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="102"/>
|
||||||
<source>small-text-label</source>
|
<source>small-text-label</source>
|
||||||
<translation type="vanished">Klein</translation>
|
<translation>Klein</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>StackToolbar</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/widgets/StackToolbar.qml" line="58"/>
|
||||||
|
<source>view-group-membership-tooltip</source>
|
||||||
|
<extracomment>View Group Membership</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
</TS>
|
</TS>
|
||||||
|
|
Binary file not shown.
|
@ -4,264 +4,469 @@
|
||||||
<context>
|
<context>
|
||||||
<name>AddGroupPane</name>
|
<name>AddGroupPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="19"/>
|
||||||
<source>create-group-title</source>
|
<source>create-group-title</source>
|
||||||
<translation type="vanished">Create Group</translation>
|
<translation>Create Group</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="42"/>
|
||||||
<source>server-label</source>
|
<source>server-label</source>
|
||||||
<extracomment>Server label</extracomment>
|
<extracomment>Server label</extracomment>
|
||||||
<translation type="vanished">Server</translation>
|
<translation>Server</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="53"/>
|
||||||
<source>group-name-label</source>
|
<source>group-name-label</source>
|
||||||
<extracomment>Group name label</extracomment>
|
<extracomment>Group name label</extracomment>
|
||||||
<translation type="vanished">Group name</translation>
|
<translation>Group name</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="60"/>
|
||||||
<source>default-group-name</source>
|
<source>default-group-name</source>
|
||||||
<extracomment>default suggested group name</extracomment>
|
<extracomment>default suggested group name</extracomment>
|
||||||
<translation type="vanished">Awesome Group</translation>
|
<translation>Awesome Group</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="65"/>
|
||||||
<source>create-group-btn</source>
|
<source>create-group-btn</source>
|
||||||
<extracomment>create group button</extracomment>
|
<extracomment>create group button</extracomment>
|
||||||
<translation type="vanished">Create</translation>
|
<translation>Create</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>BulletinOverlay</name>
|
<name>BulletinOverlay</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/BulletinOverlay.qml" line="203"/>
|
||||||
<source>new-bulletin-label</source>
|
<source>new-bulletin-label</source>
|
||||||
<translation type="vanished">New Bulletin</translation>
|
<translation>New Bulletin</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/BulletinOverlay.qml" line="215"/>
|
||||||
<source>post-new-bulletin-label</source>
|
<source>post-new-bulletin-label</source>
|
||||||
<extracomment>Post a new Bulletin Post</extracomment>
|
<extracomment>Post a new Bulletin Post</extracomment>
|
||||||
<translation type="vanished">Post new bulletin</translation>
|
<translation>Post new bulletin</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/BulletinOverlay.qml" line="221"/>
|
||||||
<source>title-placeholder</source>
|
<source>title-placeholder</source>
|
||||||
<extracomment>title place holder text</extracomment>
|
<extracomment>title place holder text</extracomment>
|
||||||
<translation type="vanished">title...</translation>
|
<translation>title...</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>GroupSettingsPane</name>
|
<name>GroupSettingsPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="42"/>
|
||||||
<source>server-label</source>
|
<source>server-label</source>
|
||||||
<translation type="vanished">Server</translation>
|
<translation>Server</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="53"/>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="74"/>
|
||||||
<source>copy-btn</source>
|
<source>copy-btn</source>
|
||||||
<translation type="vanished">Copy</translation>
|
<translation>Copy</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="63"/>
|
||||||
<source>invitation-label</source>
|
<source>invitation-label</source>
|
||||||
<translation type="vanished">Invitation</translation>
|
<translation>Invitation</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="84"/>
|
||||||
<source>group-name-label</source>
|
<source>group-name-label</source>
|
||||||
<translation type="vanished">Group Name</translation>
|
<translation>Group Name</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="93"/>
|
||||||
<source>save-btn</source>
|
<source>save-btn</source>
|
||||||
<translation type="vanished">Save</translation>
|
<translation>Save</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="103"/>
|
||||||
<source>invite-to-group-label</source>
|
<source>invite-to-group-label</source>
|
||||||
<extracomment>Invite someone to the group</extracomment>
|
<extracomment>Invite someone to the group</extracomment>
|
||||||
<translation type="vanished">Invite to group</translation>
|
<translation>Invite to group</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="114"/>
|
||||||
<source>invite-btn</source>
|
<source>invite-btn</source>
|
||||||
<translation type="vanished">Invite</translation>
|
<translation>Invite</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="123"/>
|
||||||
<source>delete-btn</source>
|
<source>delete-btn</source>
|
||||||
<translation type="vanished">Delete</translation>
|
<translation>Delete</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>InplaceEditText</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/widgets/InplaceEditText.qml" line="85"/>
|
||||||
|
<source>Update</source>
|
||||||
|
<translation>Update</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ListOverlay</name>
|
<name>ListOverlay</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/ListOverlay.qml" line="184"/>
|
||||||
<source>add-list-item</source>
|
<source>add-list-item</source>
|
||||||
<extracomment>Add a New List Item</extracomment>
|
<extracomment>Add a New List Item</extracomment>
|
||||||
<translation type="vanished">Add a New List Item</translation>
|
<translation>Add a New List Item</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/ListOverlay.qml" line="196"/>
|
||||||
<source>add-new-item</source>
|
<source>add-new-item</source>
|
||||||
<extracomment>Add a new item to the list</extracomment>
|
<extracomment>Add a new item to the list</extracomment>
|
||||||
<translation type="vanished">Add a new item to the list</translation>
|
<translation>Add a new item to the list</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/ListOverlay.qml" line="202"/>
|
||||||
<source>todo-placeholder</source>
|
<source>todo-placeholder</source>
|
||||||
<extracomment>Todo... placeholder text</extracomment>
|
<extracomment>Todo... placeholder text</extracomment>
|
||||||
<translation type="vanished">Todo...</translation>
|
<translation>Todo...</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>MembershipOverlay</name>
|
<name>MembershipOverlay</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/MembershipOverlay.qml" line="21"/>
|
||||||
<source>membership-description</source>
|
<source>membership-description</source>
|
||||||
<extracomment>Below is a list of users who have sent messages to the group. This list may not reflect all users who have access to the group.</extracomment>
|
<extracomment>Below is a list of users who have sent messages to the group. This list may not reflect all users who have access to the group.</extracomment>
|
||||||
<translation type="vanished">Below is a list of users who have sent messages to the group. This list may not reflect all users who have access to the group.</translation>
|
<translation>Below is a list of users who have sent messages to the group. This list may not reflect all users who have access to the group.</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>Message</name>
|
<name>Message</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/Message.qml" line="56"/>
|
||||||
<source>dm-tooltip</source>
|
<source>dm-tooltip</source>
|
||||||
<extracomment>Click to DM</extracomment>
|
<extracomment>Click to DM</extracomment>
|
||||||
<translation type="vanished">Click to DM</translation>
|
<translation>Click to DM</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>could-not-send-msg-error</source>
|
<source>could-not-send-msg-error</source>
|
||||||
<extracomment>Could not send this message</extracomment>
|
<extracomment>Could not send this message</extracomment>
|
||||||
<translation type="vanished">Could not send this message</translation>
|
<translation>Could not send this message</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>acknowledged-label</source>
|
<source>acknowledged-label</source>
|
||||||
<translation type="vanished">Acknowledged</translation>
|
<translation>Acknowledged</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>pending-label</source>
|
<source>pending-label</source>
|
||||||
<translation type="vanished">Pending</translation>
|
<translation>Pending</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>MyProfile</name>
|
<name>MyProfile</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/MyProfile.qml" line="185"/>
|
||||||
<source>copy-btn</source>
|
<source>copy-btn</source>
|
||||||
<extracomment>Button for copying profile onion address to clipboard</extracomment>
|
<extracomment>Button for copying profile onion address to clipboard</extracomment>
|
||||||
<translation type="vanished">Copy</translation>
|
<translation>Copy</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/MyProfile.qml" line="189"/>
|
||||||
<source>copied-clipboard-notification</source>
|
<source>copied-clipboard-notification</source>
|
||||||
<extracomment>Copied to clipboard</extracomment>
|
<extracomment>Copied to clipboard</extracomment>
|
||||||
<translation type="vanished">Copied to clipboard</translation>
|
<translation>Copied to clipboard</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/MyProfile.qml" line="219"/>
|
||||||
<source>new-group-btn</source>
|
<source>new-group-btn</source>
|
||||||
<extracomment>create new group button</extracomment>
|
<extracomment>create new group button</extracomment>
|
||||||
<translation type="vanished">Create new group</translation>
|
<translation>Create new group</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/MyProfile.qml" line="229"/>
|
||||||
<source>paste-address-to-add-contact</source>
|
<source>paste-address-to-add-contact</source>
|
||||||
<extracomment>ex: "... paste an address here to add a contact ..."</extracomment>
|
<extracomment>ex: "... paste an address here to add a contact ..."</extracomment>
|
||||||
<translation type="vanished">... paste an address here to add a contact...</translation>
|
<translation>... paste an address here to add a contact...</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>OverlayPane</name>
|
<name>OverlayPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="44"/>
|
||||||
<source>accept-group-invite-label</source>
|
<source>accept-group-invite-label</source>
|
||||||
<extracomment>Do you want to accept the invitation to $GROUP</extracomment>
|
<extracomment>Do you want to accept the invitation to $GROUP</extracomment>
|
||||||
<translation type="vanished">Do you want to accept the invitation to</translation>
|
<translation>Do you want to accept the invitation to</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="49"/>
|
||||||
<source>accept-group-btn</source>
|
<source>accept-group-btn</source>
|
||||||
<extracomment>Accept group invite button</extracomment>
|
<extracomment>Accept group invite button</extracomment>
|
||||||
<translation type="vanished">Accept</translation>
|
<translation>Accept</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="59"/>
|
||||||
<source>reject-group-btn</source>
|
<source>reject-group-btn</source>
|
||||||
<extracomment>Reject Group invite button</extracomment>
|
<extracomment>Reject Group invite button</extracomment>
|
||||||
<translation type="vanished">Reject</translation>
|
<translation>Reject</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="73"/>
|
||||||
<source>chat-btn</source>
|
<source>chat-btn</source>
|
||||||
<translation type="vanished">Chat</translation>
|
<translation>Chat</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="80"/>
|
||||||
<source>lists-btn</source>
|
<source>lists-btn</source>
|
||||||
<translation type="vanished">Lists</translation>
|
<translation>Lists</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="87"/>
|
||||||
<source>bulletins-btn</source>
|
<source>bulletins-btn</source>
|
||||||
<translation type="vanished">Bulletins</translation>
|
<translation>Bulletins</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="94"/>
|
||||||
<source>puzzle-game-btn</source>
|
<source>puzzle-game-btn</source>
|
||||||
<translation type="vanished">Puzzle Game</translation>
|
<translation>Puzzle Game</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PeerSettingsPane</name>
|
<name>PeerSettingsPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="42"/>
|
||||||
<source>address-label</source>
|
<source>address-label</source>
|
||||||
<translation type="vanished">Address</translation>
|
<translation>Address</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="53"/>
|
||||||
<source>copy-btn</source>
|
<source>copy-btn</source>
|
||||||
<translation type="vanished">Copy</translation>
|
<translation>Copy</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="57"/>
|
||||||
<source>copied-to-clipboard-notification</source>
|
<source>copied-to-clipboard-notification</source>
|
||||||
<extracomment>notification: copied to clipboard</extracomment>
|
<extracomment>notification: copied to clipboard</extracomment>
|
||||||
<translation type="vanished">Copied to Clipboard</translation>
|
<translation>Copied to Clipboard</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="64"/>
|
||||||
<source>display-name-label</source>
|
<source>display-name-label</source>
|
||||||
<translation type="vanished">Display Name</translation>
|
<translation>Display Name</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="73"/>
|
||||||
<source>save-btn</source>
|
<source>save-btn</source>
|
||||||
<translation type="vanished">Save</translation>
|
<translation>Save</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="85"/>
|
||||||
<source>block-btn</source>
|
<source>block-btn</source>
|
||||||
<translation type="vanished">Block Peer</translation>
|
<translation>Block Peer</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="85"/>
|
||||||
<source>unblock-btn</source>
|
<source>unblock-btn</source>
|
||||||
<translation type="vanished">Unblock Peer</translation>
|
<translation>Unblock Peer</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="99"/>
|
||||||
<source>delete-btn</source>
|
<source>delete-btn</source>
|
||||||
<translation type="vanished">Delete</translation>
|
<translation>Delete</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ProfileAddEditPane</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="24"/>
|
||||||
|
<source>add-profile-title</source>
|
||||||
|
<translation>Add new profile</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="24"/>
|
||||||
|
<source>edit-profile-title</source>
|
||||||
|
<translation>Edit Profile</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="92"/>
|
||||||
|
<source>profile-name</source>
|
||||||
|
<extracomment>Display name</extracomment>
|
||||||
|
<translation>Display name</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="32"/>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="100"/>
|
||||||
|
<source>default-profile-name</source>
|
||||||
|
<extracomment>default suggested profile name</extracomment>
|
||||||
|
<translation>Alice</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="81"/>
|
||||||
|
<source>profile-onion-label</source>
|
||||||
|
<extracomment>Onion</extracomment>
|
||||||
|
<translation>Onion</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="112"/>
|
||||||
|
<source>radio-use-password</source>
|
||||||
|
<extracomment>Password</extracomment>
|
||||||
|
<translation>Password</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="122"/>
|
||||||
|
<source>radio-no-password</source>
|
||||||
|
<extracomment>Unencrypted (No password)</extracomment>
|
||||||
|
<translation>Unencrypted (No password)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="133"/>
|
||||||
|
<source>no-password-warning</source>
|
||||||
|
<extracomment>Not using a password on this account means that all data stored locally will not be encrypted</extracomment>
|
||||||
|
<translation>Not using a password on this account means that all data stored locally will not be encrypted</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="140"/>
|
||||||
|
<source>current-password-label</source>
|
||||||
|
<extracomment>Current Password</extracomment>
|
||||||
|
<translation>Current Password</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="154"/>
|
||||||
|
<source>password1-label</source>
|
||||||
|
<extracomment>Password</extracomment>
|
||||||
|
<translation>Password</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="174"/>
|
||||||
|
<source>password2-label</source>
|
||||||
|
<extracomment>Reenter password</extracomment>
|
||||||
|
<translation>Reenter password</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="188"/>
|
||||||
|
<source>create-profile-btn</source>
|
||||||
|
<extracomment>Create Profile || Save Profile</extracomment>
|
||||||
|
<translation>Create Profile</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="188"/>
|
||||||
|
<source>save-profile-btn</source>
|
||||||
|
<translation>Save Profile</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="217"/>
|
||||||
|
<source>password-error-match</source>
|
||||||
|
<extracomment>Passwords do not match</extracomment>
|
||||||
|
<translation>Passwords do not match</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="225"/>
|
||||||
|
<source>password-change-error</source>
|
||||||
|
<extracomment>Error changing password: Supplied password rejected</extracomment>
|
||||||
|
<translation>Error changing password: Supplied password rejected</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="234"/>
|
||||||
|
<source>delete-profile-btn</source>
|
||||||
|
<extracomment>Delete Profile</extracomment>
|
||||||
|
<translation>Delete Profile</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="247"/>
|
||||||
|
<source>delete-confirm-label</source>
|
||||||
|
<extracomment>Type DELETE to confirm</extracomment>
|
||||||
|
<translation>Type DELETE to confirm</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="263"/>
|
||||||
|
<source>delete-profile-confirm-btn</source>
|
||||||
|
<extracomment>Really Delete Profile</extracomment>
|
||||||
|
<translation>Really Delete Profile</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="269"/>
|
||||||
|
<source>delete-confirm-text</source>
|
||||||
|
<extracomment>DELETE</extracomment>
|
||||||
|
<translation>DELETE</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ProfileList</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/widgets/ProfileList.qml" line="88"/>
|
||||||
|
<location filename="../qml/widgets/ProfileList.qml" line="101"/>
|
||||||
|
<source>add-new-profile-btn</source>
|
||||||
|
<translation>Add new profile</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ProfileManagerPane</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileManagerPane.qml" line="26"/>
|
||||||
|
<source>enter-profile-password</source>
|
||||||
|
<extracomment>Please enter password:</extracomment>
|
||||||
|
<translation>Please enter password</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileManagerPane.qml" line="42"/>
|
||||||
|
<source>error-0-profiles-loaded-for-password</source>
|
||||||
|
<extracomment>0 profiles loaded with that password</extracomment>
|
||||||
|
<translation>0 profiles loaded with that password</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileManagerPane.qml" line="52"/>
|
||||||
|
<source>unlock</source>
|
||||||
|
<extracomment>Unlock</extracomment>
|
||||||
|
<translation>Unlock</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>SettingsPane</name>
|
<name>SettingsPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="21"/>
|
||||||
<source>cwtch-settings-title</source>
|
<source>cwtch-settings-title</source>
|
||||||
<extracomment>Cwtch Settings title</extracomment>
|
<extracomment>Cwtch Settings title</extracomment>
|
||||||
<translation type="vanished">Cwtch Settings</translation>
|
<translation>Cwtch Settings</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="47"/>
|
||||||
<source>version %1 builddate %2</source>
|
<source>version %1 builddate %2</source>
|
||||||
<extracomment>Version: %1 Built on: %2</extracomment>
|
<extracomment>Version: %1 Built on: %2</extracomment>
|
||||||
<translation type="vanished">Version: %1 Built on: %2</translation>
|
<translation>Version: %1 Built on: %2</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="54"/>
|
||||||
<source>zoom-label</source>
|
<source>zoom-label</source>
|
||||||
<extracomment>Interface zoom (mostly affects text and button sizes)</extracomment>
|
<extracomment>Interface zoom (mostly affects text and button sizes)</extracomment>
|
||||||
<translation type="vanished">Interface zoom (mostly affects text and button sizes)</translation>
|
<translation>Interface zoom (mostly affects text and button sizes)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="83"/>
|
||||||
<source>block-unknown-label</source>
|
<source>block-unknown-label</source>
|
||||||
<translation type="vanished">Block Unknown Peers</translation>
|
<translation>Block Unknown Peers</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="90"/>
|
||||||
<source>large-text-label</source>
|
<source>large-text-label</source>
|
||||||
<translation type="vanished">Large</translation>
|
<translation>Large</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="98"/>
|
||||||
<source>default-scaling-text</source>
|
<source>default-scaling-text</source>
|
||||||
<extracomment>"Default size text (scale factor: "</extracomment>
|
<extracomment>"Default size text (scale factor: "</extracomment>
|
||||||
<translation type="vanished">Default size text (scale factor:</translation>
|
<translation>Default size text (scale factor:</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="102"/>
|
||||||
<source>small-text-label</source>
|
<source>small-text-label</source>
|
||||||
<translation type="vanished">Small</translation>
|
<translation>Small</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>StackToolbar</name>
|
<name>StackToolbar</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/StackToolbar.qml" line="58"/>
|
||||||
<source>view-group-membership-tooltip</source>
|
<source>view-group-membership-tooltip</source>
|
||||||
<extracomment>View Group Membership</extracomment>
|
<extracomment>View Group Membership</extracomment>
|
||||||
<translation type="vanished">View Group Membership</translation>
|
<translation>View Group Membership</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
</TS>
|
</TS>
|
||||||
|
|
|
@ -4,239 +4,469 @@
|
||||||
<context>
|
<context>
|
||||||
<name>AddGroupPane</name>
|
<name>AddGroupPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="19"/>
|
||||||
<source>create-group-title</source>
|
<source>create-group-title</source>
|
||||||
<translation type="vanished">Créer un groupe</translation>
|
<translation>Créer un groupe</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="42"/>
|
||||||
<source>server-label</source>
|
<source>server-label</source>
|
||||||
<extracomment>Server label</extracomment>
|
<extracomment>Server label</extracomment>
|
||||||
<translation type="vanished">Serveur</translation>
|
<translation>Serveur</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="53"/>
|
||||||
<source>group-name-label</source>
|
<source>group-name-label</source>
|
||||||
<extracomment>Group name label</extracomment>
|
<extracomment>Group name label</extracomment>
|
||||||
<translation type="vanished">Groupe</translation>
|
<translation>Groupe</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="60"/>
|
||||||
<source>default-group-name</source>
|
<source>default-group-name</source>
|
||||||
<extracomment>default suggested group name</extracomment>
|
<extracomment>default suggested group name</extracomment>
|
||||||
<translation type="vanished">Un super groupe</translation>
|
<translation>Un super groupe</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="65"/>
|
||||||
<source>create-group-btn</source>
|
<source>create-group-btn</source>
|
||||||
<extracomment>create group button</extracomment>
|
<extracomment>create group button</extracomment>
|
||||||
<translation type="vanished">Créer</translation>
|
<translation>Créer</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>BulletinOverlay</name>
|
<name>BulletinOverlay</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/BulletinOverlay.qml" line="203"/>
|
||||||
<source>new-bulletin-label</source>
|
<source>new-bulletin-label</source>
|
||||||
<translation type="vanished">Nouveau bulletin</translation>
|
<translation>Nouveau bulletin</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/BulletinOverlay.qml" line="215"/>
|
||||||
<source>post-new-bulletin-label</source>
|
<source>post-new-bulletin-label</source>
|
||||||
<extracomment>Post a new Bulletin Post</extracomment>
|
<extracomment>Post a new Bulletin Post</extracomment>
|
||||||
<translation type="vanished">Envoyer un nouveau bulletin</translation>
|
<translation>Envoyer un nouveau bulletin</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/BulletinOverlay.qml" line="221"/>
|
||||||
<source>title-placeholder</source>
|
<source>title-placeholder</source>
|
||||||
<extracomment>title place holder text</extracomment>
|
<extracomment>title place holder text</extracomment>
|
||||||
<translation type="vanished">titre...</translation>
|
<translation>titre...</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>GroupSettingsPane</name>
|
<name>GroupSettingsPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="42"/>
|
||||||
<source>server-label</source>
|
<source>server-label</source>
|
||||||
<translation type="vanished">Serveur</translation>
|
<translation>Serveur</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="53"/>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="74"/>
|
||||||
<source>copy-btn</source>
|
<source>copy-btn</source>
|
||||||
<translation type="vanished">Copier</translation>
|
<translation>Copier</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="63"/>
|
||||||
<source>invitation-label</source>
|
<source>invitation-label</source>
|
||||||
<translation type="vanished">Invitation</translation>
|
<translation>Invitation</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="84"/>
|
||||||
<source>group-name-label</source>
|
<source>group-name-label</source>
|
||||||
<translation type="vanished">Nom du groupe</translation>
|
<translation>Nom du groupe</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="93"/>
|
||||||
<source>save-btn</source>
|
<source>save-btn</source>
|
||||||
<translation type="vanished">Sauvegarder</translation>
|
<translation>Sauvegarder</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="103"/>
|
||||||
<source>invite-to-group-label</source>
|
<source>invite-to-group-label</source>
|
||||||
<extracomment>Invite someone to the group</extracomment>
|
<extracomment>Invite someone to the group</extracomment>
|
||||||
<translation type="vanished">Inviter quelqu'un</translation>
|
<translation>Inviter quelqu'un</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="114"/>
|
||||||
<source>invite-btn</source>
|
<source>invite-btn</source>
|
||||||
<translation type="vanished">Invitation</translation>
|
<translation>Invitation</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="123"/>
|
||||||
<source>delete-btn</source>
|
<source>delete-btn</source>
|
||||||
<translation type="vanished">Effacer</translation>
|
<translation>Effacer</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>InplaceEditText</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/widgets/InplaceEditText.qml" line="85"/>
|
||||||
|
<source>Update</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ListOverlay</name>
|
<name>ListOverlay</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/ListOverlay.qml" line="184"/>
|
||||||
<source>add-list-item</source>
|
<source>add-list-item</source>
|
||||||
<extracomment>Add a New List Item</extracomment>
|
<extracomment>Add a New List Item</extracomment>
|
||||||
<translation type="vanished">Ajouter un nouvel élément</translation>
|
<translation>Ajouter un nouvel élément</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/ListOverlay.qml" line="196"/>
|
||||||
<source>add-new-item</source>
|
<source>add-new-item</source>
|
||||||
<extracomment>Add a new item to the list</extracomment>
|
<extracomment>Add a new item to the list</extracomment>
|
||||||
<translation type="vanished">Ajouter un nouvel élément à la liste</translation>
|
<translation>Ajouter un nouvel élément à la liste</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/ListOverlay.qml" line="202"/>
|
||||||
<source>todo-placeholder</source>
|
<source>todo-placeholder</source>
|
||||||
<extracomment>Todo... placeholder text</extracomment>
|
<extracomment>Todo... placeholder text</extracomment>
|
||||||
<translation type="vanished">A faire...</translation>
|
<translation>A faire...</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>MembershipOverlay</name>
|
<name>MembershipOverlay</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/MembershipOverlay.qml" line="21"/>
|
||||||
<source>membership-description</source>
|
<source>membership-description</source>
|
||||||
<extracomment>Below is a list of users who have sent messages to the group. This list may not reflect all users who have access to the group.</extracomment>
|
<extracomment>Below is a list of users who have sent messages to the group. This list may not reflect all users who have access to the group.</extracomment>
|
||||||
<translation type="vanished">Liste des utilisateurs ayant envoyés un ou plusieurs messages au groupe. Cette liste peut ne pas être representatives de l'ensemble des membres du groupe.</translation>
|
<translation>Liste des utilisateurs ayant envoyés un ou plusieurs messages au groupe. Cette liste peut ne pas être representatives de l'ensemble des membres du groupe.</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>Message</name>
|
<name>Message</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/Message.qml" line="56"/>
|
||||||
<source>dm-tooltip</source>
|
<source>dm-tooltip</source>
|
||||||
<extracomment>Click to DM</extracomment>
|
<extracomment>Click to DM</extracomment>
|
||||||
<translation type="vanished">Envoyer un message privé</translation>
|
<translation>Envoyer un message privé</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>could-not-send-msg-error</source>
|
<source>could-not-send-msg-error</source>
|
||||||
<extracomment>Could not send this message</extracomment>
|
<extracomment>Could not send this message</extracomment>
|
||||||
<translation type="vanished">Impossible d'envoyer ce message</translation>
|
<translation>Impossible d'envoyer ce message</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>acknowledged-label</source>
|
<source>acknowledged-label</source>
|
||||||
<translation type="vanished">Confirmé</translation>
|
<translation>Confirmé</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>pending-label</source>
|
<source>pending-label</source>
|
||||||
<translation type="vanished">En attente</translation>
|
<translation>En attente</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>MyProfile</name>
|
<name>MyProfile</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/MyProfile.qml" line="185"/>
|
||||||
<source>copy-btn</source>
|
<source>copy-btn</source>
|
||||||
<extracomment>Button for copying profile onion address to clipboard</extracomment>
|
<extracomment>Button for copying profile onion address to clipboard</extracomment>
|
||||||
<translation type="vanished">Copier</translation>
|
<translation>Copier</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/MyProfile.qml" line="189"/>
|
||||||
<source>copied-clipboard-notification</source>
|
<source>copied-clipboard-notification</source>
|
||||||
<extracomment>Copied to clipboard</extracomment>
|
<extracomment>Copied to clipboard</extracomment>
|
||||||
<translation type="vanished">Copié dans le presse-papier</translation>
|
<translation>Copié dans le presse-papier</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/MyProfile.qml" line="219"/>
|
||||||
<source>new-group-btn</source>
|
<source>new-group-btn</source>
|
||||||
<extracomment>create new group button</extracomment>
|
<extracomment>create new group button</extracomment>
|
||||||
<translation type="vanished">Créer un nouveau groupe</translation>
|
<translation>Créer un nouveau groupe</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/MyProfile.qml" line="229"/>
|
||||||
<source>paste-address-to-add-contact</source>
|
<source>paste-address-to-add-contact</source>
|
||||||
<extracomment>ex: "... paste an address here to add a contact ..."</extracomment>
|
<extracomment>ex: "... paste an address here to add a contact ..."</extracomment>
|
||||||
<translation type="vanished">... coller une adresse ici pour ajouter un contact...</translation>
|
<translation>... coller une adresse ici pour ajouter un contact...</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>OverlayPane</name>
|
<name>OverlayPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="44"/>
|
||||||
<source>accept-group-invite-label</source>
|
<source>accept-group-invite-label</source>
|
||||||
<extracomment>Do you want to accept the invitation to $GROUP</extracomment>
|
<extracomment>Do you want to accept the invitation to $GROUP</extracomment>
|
||||||
<translation type="vanished">Voulez-vous accepter l'invitation au groupe</translation>
|
<translation>Voulez-vous accepter l'invitation au groupe</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="49"/>
|
||||||
<source>accept-group-btn</source>
|
<source>accept-group-btn</source>
|
||||||
<extracomment>Accept group invite button</extracomment>
|
<extracomment>Accept group invite button</extracomment>
|
||||||
<translation type="vanished">Accepter</translation>
|
<translation>Accepter</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="59"/>
|
||||||
<source>reject-group-btn</source>
|
<source>reject-group-btn</source>
|
||||||
<extracomment>Reject Group invite button</extracomment>
|
<extracomment>Reject Group invite button</extracomment>
|
||||||
<translation type="vanished">Refuser</translation>
|
<translation>Refuser</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="73"/>
|
||||||
<source>chat-btn</source>
|
<source>chat-btn</source>
|
||||||
<translation type="vanished">Discuter</translation>
|
<translation>Discuter</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="80"/>
|
||||||
<source>lists-btn</source>
|
<source>lists-btn</source>
|
||||||
<translation type="vanished">Listes</translation>
|
<translation>Listes</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="87"/>
|
||||||
<source>bulletins-btn</source>
|
<source>bulletins-btn</source>
|
||||||
<translation type="vanished">Bulletins</translation>
|
<translation>Bulletins</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="94"/>
|
||||||
<source>puzzle-game-btn</source>
|
<source>puzzle-game-btn</source>
|
||||||
<translation type="vanished">Puzzle</translation>
|
<translation>Puzzle</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PeerSettingsPane</name>
|
<name>PeerSettingsPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="42"/>
|
||||||
<source>address-label</source>
|
<source>address-label</source>
|
||||||
<translation type="vanished">Adresse</translation>
|
<translation>Adresse</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="53"/>
|
||||||
<source>copy-btn</source>
|
<source>copy-btn</source>
|
||||||
<translation type="vanished">Copier</translation>
|
<translation>Copier</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="57"/>
|
||||||
<source>copied-to-clipboard-notification</source>
|
<source>copied-to-clipboard-notification</source>
|
||||||
<extracomment>notification: copied to clipboard</extracomment>
|
<extracomment>notification: copied to clipboard</extracomment>
|
||||||
<translation type="vanished">Copié dans le presse-papier</translation>
|
<translation>Copié dans le presse-papier</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="64"/>
|
||||||
<source>display-name-label</source>
|
<source>display-name-label</source>
|
||||||
<translation type="vanished">Pseudo</translation>
|
<translation>Pseudo</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="73"/>
|
||||||
<source>save-btn</source>
|
<source>save-btn</source>
|
||||||
<translation type="vanished">Sauvegarder</translation>
|
<translation>Sauvegarder</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="85"/>
|
||||||
|
<source>block-btn</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="85"/>
|
||||||
|
<source>unblock-btn</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="99"/>
|
||||||
<source>delete-btn</source>
|
<source>delete-btn</source>
|
||||||
<translation type="vanished">Effacer</translation>
|
<translation>Effacer</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ProfileAddEditPane</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="24"/>
|
||||||
|
<source>add-profile-title</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="24"/>
|
||||||
|
<source>edit-profile-title</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="92"/>
|
||||||
|
<source>profile-name</source>
|
||||||
|
<extracomment>Display name</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="32"/>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="100"/>
|
||||||
|
<source>default-profile-name</source>
|
||||||
|
<extracomment>default suggested profile name</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="81"/>
|
||||||
|
<source>profile-onion-label</source>
|
||||||
|
<extracomment>Onion</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="112"/>
|
||||||
|
<source>radio-use-password</source>
|
||||||
|
<extracomment>Password</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="122"/>
|
||||||
|
<source>radio-no-password</source>
|
||||||
|
<extracomment>Unencrypted (No password)</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="133"/>
|
||||||
|
<source>no-password-warning</source>
|
||||||
|
<extracomment>Not using a password on this account means that all data stored locally will not be encrypted</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="140"/>
|
||||||
|
<source>current-password-label</source>
|
||||||
|
<extracomment>Current Password</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="154"/>
|
||||||
|
<source>password1-label</source>
|
||||||
|
<extracomment>Password</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="174"/>
|
||||||
|
<source>password2-label</source>
|
||||||
|
<extracomment>Reenter password</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="188"/>
|
||||||
|
<source>create-profile-btn</source>
|
||||||
|
<extracomment>Create Profile || Save Profile</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="188"/>
|
||||||
|
<source>save-profile-btn</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="217"/>
|
||||||
|
<source>password-error-match</source>
|
||||||
|
<extracomment>Passwords do not match</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="225"/>
|
||||||
|
<source>password-change-error</source>
|
||||||
|
<extracomment>Error changing password: Supplied password rejected</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="234"/>
|
||||||
|
<source>delete-profile-btn</source>
|
||||||
|
<extracomment>Delete Profile</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="247"/>
|
||||||
|
<source>delete-confirm-label</source>
|
||||||
|
<extracomment>Type DELETE to confirm</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="263"/>
|
||||||
|
<source>delete-profile-confirm-btn</source>
|
||||||
|
<extracomment>Really Delete Profile</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="269"/>
|
||||||
|
<source>delete-confirm-text</source>
|
||||||
|
<extracomment>DELETE</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ProfileList</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/widgets/ProfileList.qml" line="88"/>
|
||||||
|
<location filename="../qml/widgets/ProfileList.qml" line="101"/>
|
||||||
|
<source>add-new-profile-btn</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ProfileManagerPane</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileManagerPane.qml" line="26"/>
|
||||||
|
<source>enter-profile-password</source>
|
||||||
|
<extracomment>Please enter password:</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileManagerPane.qml" line="42"/>
|
||||||
|
<source>error-0-profiles-loaded-for-password</source>
|
||||||
|
<extracomment>0 profiles loaded with that password</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileManagerPane.qml" line="52"/>
|
||||||
|
<source>unlock</source>
|
||||||
|
<extracomment>Unlock</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>SettingsPane</name>
|
<name>SettingsPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="21"/>
|
||||||
<source>cwtch-settings-title</source>
|
<source>cwtch-settings-title</source>
|
||||||
<extracomment>Cwtch Settings title</extracomment>
|
<extracomment>Cwtch Settings title</extracomment>
|
||||||
<translation type="vanished">Préférences Cwtch</translation>
|
<translation>Préférences Cwtch</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="47"/>
|
||||||
|
<source>version %1 builddate %2</source>
|
||||||
|
<extracomment>Version: %1 Built on: %2</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="54"/>
|
||||||
<source>zoom-label</source>
|
<source>zoom-label</source>
|
||||||
<extracomment>Interface zoom (mostly affects text and button sizes)</extracomment>
|
<extracomment>Interface zoom (mostly affects text and button sizes)</extracomment>
|
||||||
<translation type="vanished">Interface zoom (essentiellement la taille du texte et des composants de l'interface)</translation>
|
<translation>Interface zoom (essentiellement la taille du texte et des composants de l'interface)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="83"/>
|
||||||
|
<source>block-unknown-label</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="90"/>
|
||||||
<source>large-text-label</source>
|
<source>large-text-label</source>
|
||||||
<translation type="obsolete">Large</translation>
|
<translation type="unfinished">Large</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="98"/>
|
||||||
<source>default-scaling-text</source>
|
<source>default-scaling-text</source>
|
||||||
<extracomment>"Default size text (scale factor: "</extracomment>
|
<extracomment>"Default size text (scale factor: "</extracomment>
|
||||||
<translation type="vanished">Taille par défaut du texte (échelle:</translation>
|
<translation>Taille par défaut du texte (échelle:</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="102"/>
|
||||||
<source>small-text-label</source>
|
<source>small-text-label</source>
|
||||||
<translation type="vanished">Petit</translation>
|
<translation>Petit</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>StackToolbar</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/widgets/StackToolbar.qml" line="58"/>
|
||||||
|
<source>view-group-membership-tooltip</source>
|
||||||
|
<extracomment>View Group Membership</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
</TS>
|
</TS>
|
||||||
|
|
|
@ -4,239 +4,469 @@
|
||||||
<context>
|
<context>
|
||||||
<name>AddGroupPane</name>
|
<name>AddGroupPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="19"/>
|
||||||
<source>create-group-title</source>
|
<source>create-group-title</source>
|
||||||
<translation type="vanished">Criar Grupo</translation>
|
<translation>Criar Grupo</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="42"/>
|
||||||
<source>server-label</source>
|
<source>server-label</source>
|
||||||
<extracomment>Server label</extracomment>
|
<extracomment>Server label</extracomment>
|
||||||
<translation type="vanished">Servidor</translation>
|
<translation>Servidor</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="53"/>
|
||||||
<source>group-name-label</source>
|
<source>group-name-label</source>
|
||||||
<extracomment>Group name label</extracomment>
|
<extracomment>Group name label</extracomment>
|
||||||
<translation type="vanished">Nome do grupo</translation>
|
<translation>Nome do grupo</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="60"/>
|
||||||
<source>default-group-name</source>
|
<source>default-group-name</source>
|
||||||
<extracomment>default suggested group name</extracomment>
|
<extracomment>default suggested group name</extracomment>
|
||||||
<translation type="vanished">Grupo incrível</translation>
|
<translation>Grupo incrível</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/AddGroupPane.qml" line="65"/>
|
||||||
<source>create-group-btn</source>
|
<source>create-group-btn</source>
|
||||||
<extracomment>create group button</extracomment>
|
<extracomment>create group button</extracomment>
|
||||||
<translation type="vanished">Criar</translation>
|
<translation>Criar</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>BulletinOverlay</name>
|
<name>BulletinOverlay</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/BulletinOverlay.qml" line="203"/>
|
||||||
<source>new-bulletin-label</source>
|
<source>new-bulletin-label</source>
|
||||||
<translation type="vanished">Novo Boletim</translation>
|
<translation>Novo Boletim</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/BulletinOverlay.qml" line="215"/>
|
||||||
<source>post-new-bulletin-label</source>
|
<source>post-new-bulletin-label</source>
|
||||||
<extracomment>Post a new Bulletin Post</extracomment>
|
<extracomment>Post a new Bulletin Post</extracomment>
|
||||||
<translation type="vanished">Postar novo boletim</translation>
|
<translation>Postar novo boletim</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/BulletinOverlay.qml" line="221"/>
|
||||||
<source>title-placeholder</source>
|
<source>title-placeholder</source>
|
||||||
<extracomment>title place holder text</extracomment>
|
<extracomment>title place holder text</extracomment>
|
||||||
<translation type="vanished">título…</translation>
|
<translation>título…</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>GroupSettingsPane</name>
|
<name>GroupSettingsPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="42"/>
|
||||||
<source>server-label</source>
|
<source>server-label</source>
|
||||||
<translation type="vanished">Servidor</translation>
|
<translation>Servidor</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="53"/>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="74"/>
|
||||||
<source>copy-btn</source>
|
<source>copy-btn</source>
|
||||||
<translation type="vanished">Copiar</translation>
|
<translation>Copiar</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="63"/>
|
||||||
<source>invitation-label</source>
|
<source>invitation-label</source>
|
||||||
<translation type="vanished">Convite</translation>
|
<translation>Convite</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="84"/>
|
||||||
<source>group-name-label</source>
|
<source>group-name-label</source>
|
||||||
<translation type="vanished">Nome do Grupo</translation>
|
<translation>Nome do Grupo</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="93"/>
|
||||||
<source>save-btn</source>
|
<source>save-btn</source>
|
||||||
<translation type="vanished">Salvar</translation>
|
<translation>Salvar</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="103"/>
|
||||||
<source>invite-to-group-label</source>
|
<source>invite-to-group-label</source>
|
||||||
<extracomment>Invite someone to the group</extracomment>
|
<extracomment>Invite someone to the group</extracomment>
|
||||||
<translation type="vanished">Convidar ao grupo</translation>
|
<translation>Convidar ao grupo</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="114"/>
|
||||||
<source>invite-btn</source>
|
<source>invite-btn</source>
|
||||||
<translation type="vanished">Convidar</translation>
|
<translation>Convidar</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/GroupSettingsPane.qml" line="123"/>
|
||||||
<source>delete-btn</source>
|
<source>delete-btn</source>
|
||||||
<translation type="vanished">Deletar</translation>
|
<translation>Deletar</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>InplaceEditText</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/widgets/InplaceEditText.qml" line="85"/>
|
||||||
|
<source>Update</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ListOverlay</name>
|
<name>ListOverlay</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/ListOverlay.qml" line="184"/>
|
||||||
<source>add-list-item</source>
|
<source>add-list-item</source>
|
||||||
<extracomment>Add a New List Item</extracomment>
|
<extracomment>Add a New List Item</extracomment>
|
||||||
<translation type="vanished">Adicionar Item à Lista</translation>
|
<translation>Adicionar Item à Lista</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/ListOverlay.qml" line="196"/>
|
||||||
<source>add-new-item</source>
|
<source>add-new-item</source>
|
||||||
<extracomment>Add a new item to the list</extracomment>
|
<extracomment>Add a new item to the list</extracomment>
|
||||||
<translation type="vanished">Adicionar novo item à lista</translation>
|
<translation>Adicionar novo item à lista</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/ListOverlay.qml" line="202"/>
|
||||||
<source>todo-placeholder</source>
|
<source>todo-placeholder</source>
|
||||||
<extracomment>Todo... placeholder text</extracomment>
|
<extracomment>Todo... placeholder text</extracomment>
|
||||||
<translation type="vanished">Afazer…</translation>
|
<translation>Afazer…</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>MembershipOverlay</name>
|
<name>MembershipOverlay</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/overlays/MembershipOverlay.qml" line="21"/>
|
||||||
<source>membership-description</source>
|
<source>membership-description</source>
|
||||||
<extracomment>Below is a list of users who have sent messages to the group. This list may not reflect all users who have access to the group.</extracomment>
|
<extracomment>Below is a list of users who have sent messages to the group. This list may not reflect all users who have access to the group.</extracomment>
|
||||||
<translation type="vanished">A lista abaixo é de usuários que enviaram mensagens ao grupo. Essa lista pode não refletir todos os usuários que têm acesso ao grupo.</translation>
|
<translation>A lista abaixo é de usuários que enviaram mensagens ao grupo. Essa lista pode não refletir todos os usuários que têm acesso ao grupo.</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>Message</name>
|
<name>Message</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/Message.qml" line="56"/>
|
||||||
<source>dm-tooltip</source>
|
<source>dm-tooltip</source>
|
||||||
<extracomment>Click to DM</extracomment>
|
<extracomment>Click to DM</extracomment>
|
||||||
<translation type="vanished">Clique para DM</translation>
|
<translation>Clique para DM</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>could-not-send-msg-error</source>
|
<source>could-not-send-msg-error</source>
|
||||||
<extracomment>Could not send this message</extracomment>
|
<extracomment>Could not send this message</extracomment>
|
||||||
<translation type="vanished">Não deu para enviar esta mensagem</translation>
|
<translation>Não deu para enviar esta mensagem</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>acknowledged-label</source>
|
<source>acknowledged-label</source>
|
||||||
<translation type="vanished">Confirmada</translation>
|
<translation>Confirmada</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>pending-label</source>
|
<source>pending-label</source>
|
||||||
<translation type="vanished">Pendente</translation>
|
<translation>Pendente</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>MyProfile</name>
|
<name>MyProfile</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/MyProfile.qml" line="185"/>
|
||||||
<source>copy-btn</source>
|
<source>copy-btn</source>
|
||||||
<extracomment>Button for copying profile onion address to clipboard</extracomment>
|
<extracomment>Button for copying profile onion address to clipboard</extracomment>
|
||||||
<translation type="vanished">Copiar</translation>
|
<translation>Copiar</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/MyProfile.qml" line="189"/>
|
||||||
<source>copied-clipboard-notification</source>
|
<source>copied-clipboard-notification</source>
|
||||||
<extracomment>Copied to clipboard</extracomment>
|
<extracomment>Copied to clipboard</extracomment>
|
||||||
<translation type="vanished">Copiado</translation>
|
<translation>Copiado</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/MyProfile.qml" line="219"/>
|
||||||
<source>new-group-btn</source>
|
<source>new-group-btn</source>
|
||||||
<extracomment>create new group button</extracomment>
|
<extracomment>create new group button</extracomment>
|
||||||
<translation type="vanished">Criar novo grupo</translation>
|
<translation>Criar novo grupo</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/widgets/MyProfile.qml" line="229"/>
|
||||||
<source>paste-address-to-add-contact</source>
|
<source>paste-address-to-add-contact</source>
|
||||||
<extracomment>ex: "... paste an address here to add a contact ..."</extracomment>
|
<extracomment>ex: "... paste an address here to add a contact ..."</extracomment>
|
||||||
<translation type="vanished">… cole um endereço aqui para adicionar um contato…</translation>
|
<translation>… cole um endereço aqui para adicionar um contato…</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>OverlayPane</name>
|
<name>OverlayPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="44"/>
|
||||||
<source>accept-group-invite-label</source>
|
<source>accept-group-invite-label</source>
|
||||||
<extracomment>Do you want to accept the invitation to $GROUP</extracomment>
|
<extracomment>Do you want to accept the invitation to $GROUP</extracomment>
|
||||||
<translation type="vanished">Você quer aceitar o convite para</translation>
|
<translation>Você quer aceitar o convite para</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="49"/>
|
||||||
<source>accept-group-btn</source>
|
<source>accept-group-btn</source>
|
||||||
<extracomment>Accept group invite button</extracomment>
|
<extracomment>Accept group invite button</extracomment>
|
||||||
<translation type="vanished">Aceitar</translation>
|
<translation>Aceitar</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="59"/>
|
||||||
<source>reject-group-btn</source>
|
<source>reject-group-btn</source>
|
||||||
<extracomment>Reject Group invite button</extracomment>
|
<extracomment>Reject Group invite button</extracomment>
|
||||||
<translation type="vanished">Recusar</translation>
|
<translation>Recusar</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="73"/>
|
||||||
<source>chat-btn</source>
|
<source>chat-btn</source>
|
||||||
<translation type="vanished">Chat</translation>
|
<translation>Chat</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="80"/>
|
||||||
<source>lists-btn</source>
|
<source>lists-btn</source>
|
||||||
<translation type="vanished">Listas</translation>
|
<translation>Listas</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="87"/>
|
||||||
<source>bulletins-btn</source>
|
<source>bulletins-btn</source>
|
||||||
<translation type="vanished">Boletins</translation>
|
<translation>Boletins</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/OverlayPane.qml" line="94"/>
|
||||||
<source>puzzle-game-btn</source>
|
<source>puzzle-game-btn</source>
|
||||||
<translation type="vanished">Jogo de Adivinhação</translation>
|
<translation>Jogo de Adivinhação</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PeerSettingsPane</name>
|
<name>PeerSettingsPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="42"/>
|
||||||
<source>address-label</source>
|
<source>address-label</source>
|
||||||
<translation type="vanished">Endereço</translation>
|
<translation>Endereço</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="53"/>
|
||||||
<source>copy-btn</source>
|
<source>copy-btn</source>
|
||||||
<translation type="vanished">Copiar</translation>
|
<translation>Copiar</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="57"/>
|
||||||
<source>copied-to-clipboard-notification</source>
|
<source>copied-to-clipboard-notification</source>
|
||||||
<extracomment>notification: copied to clipboard</extracomment>
|
<extracomment>notification: copied to clipboard</extracomment>
|
||||||
<translation type="vanished">Copiado</translation>
|
<translation>Copiado</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="64"/>
|
||||||
<source>display-name-label</source>
|
<source>display-name-label</source>
|
||||||
<translation type="vanished">Nome de Exibição</translation>
|
<translation>Nome de Exibição</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="73"/>
|
||||||
<source>save-btn</source>
|
<source>save-btn</source>
|
||||||
<translation type="vanished">Salvar</translation>
|
<translation>Salvar</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="85"/>
|
||||||
|
<source>block-btn</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="85"/>
|
||||||
|
<source>unblock-btn</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/PeerSettingsPane.qml" line="99"/>
|
||||||
<source>delete-btn</source>
|
<source>delete-btn</source>
|
||||||
<translation type="vanished">Deletar</translation>
|
<translation>Deletar</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ProfileAddEditPane</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="24"/>
|
||||||
|
<source>add-profile-title</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="24"/>
|
||||||
|
<source>edit-profile-title</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="92"/>
|
||||||
|
<source>profile-name</source>
|
||||||
|
<extracomment>Display name</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="32"/>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="100"/>
|
||||||
|
<source>default-profile-name</source>
|
||||||
|
<extracomment>default suggested profile name</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="81"/>
|
||||||
|
<source>profile-onion-label</source>
|
||||||
|
<extracomment>Onion</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="112"/>
|
||||||
|
<source>radio-use-password</source>
|
||||||
|
<extracomment>Password</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="122"/>
|
||||||
|
<source>radio-no-password</source>
|
||||||
|
<extracomment>Unencrypted (No password)</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="133"/>
|
||||||
|
<source>no-password-warning</source>
|
||||||
|
<extracomment>Not using a password on this account means that all data stored locally will not be encrypted</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="140"/>
|
||||||
|
<source>current-password-label</source>
|
||||||
|
<extracomment>Current Password</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="154"/>
|
||||||
|
<source>password1-label</source>
|
||||||
|
<extracomment>Password</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="174"/>
|
||||||
|
<source>password2-label</source>
|
||||||
|
<extracomment>Reenter password</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="188"/>
|
||||||
|
<source>create-profile-btn</source>
|
||||||
|
<extracomment>Create Profile || Save Profile</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="188"/>
|
||||||
|
<source>save-profile-btn</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="217"/>
|
||||||
|
<source>password-error-match</source>
|
||||||
|
<extracomment>Passwords do not match</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="225"/>
|
||||||
|
<source>password-change-error</source>
|
||||||
|
<extracomment>Error changing password: Supplied password rejected</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="234"/>
|
||||||
|
<source>delete-profile-btn</source>
|
||||||
|
<extracomment>Delete Profile</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="247"/>
|
||||||
|
<source>delete-confirm-label</source>
|
||||||
|
<extracomment>Type DELETE to confirm</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="263"/>
|
||||||
|
<source>delete-profile-confirm-btn</source>
|
||||||
|
<extracomment>Really Delete Profile</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileAddEditPane.qml" line="269"/>
|
||||||
|
<source>delete-confirm-text</source>
|
||||||
|
<extracomment>DELETE</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ProfileList</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/widgets/ProfileList.qml" line="88"/>
|
||||||
|
<location filename="../qml/widgets/ProfileList.qml" line="101"/>
|
||||||
|
<source>add-new-profile-btn</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>ProfileManagerPane</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileManagerPane.qml" line="26"/>
|
||||||
|
<source>enter-profile-password</source>
|
||||||
|
<extracomment>Please enter password:</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileManagerPane.qml" line="42"/>
|
||||||
|
<source>error-0-profiles-loaded-for-password</source>
|
||||||
|
<extracomment>0 profiles loaded with that password</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/ProfileManagerPane.qml" line="52"/>
|
||||||
|
<source>unlock</source>
|
||||||
|
<extracomment>Unlock</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>SettingsPane</name>
|
<name>SettingsPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="21"/>
|
||||||
<source>cwtch-settings-title</source>
|
<source>cwtch-settings-title</source>
|
||||||
<extracomment>Cwtch Settings title</extracomment>
|
<extracomment>Cwtch Settings title</extracomment>
|
||||||
<translation type="vanished">Configurações do Cwtch</translation>
|
<translation>Configurações do Cwtch</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="47"/>
|
||||||
|
<source>version %1 builddate %2</source>
|
||||||
|
<extracomment>Version: %1 Built on: %2</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="54"/>
|
||||||
<source>zoom-label</source>
|
<source>zoom-label</source>
|
||||||
<extracomment>Interface zoom (mostly affects text and button sizes)</extracomment>
|
<extracomment>Interface zoom (mostly affects text and button sizes)</extracomment>
|
||||||
<translation type="vanished">Zoom da interface (afeta principalmente tamanho de texto e botões)</translation>
|
<translation>Zoom da interface (afeta principalmente tamanho de texto e botões)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="83"/>
|
||||||
|
<source>block-unknown-label</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="90"/>
|
||||||
<source>large-text-label</source>
|
<source>large-text-label</source>
|
||||||
<translation type="vanished">Grande</translation>
|
<translation>Grande</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="98"/>
|
||||||
<source>default-scaling-text</source>
|
<source>default-scaling-text</source>
|
||||||
<extracomment>"Default size text (scale factor: "</extracomment>
|
<extracomment>"Default size text (scale factor: "</extracomment>
|
||||||
<translation type="vanished">Texto tamanho padrão (fator de escala: </translation>
|
<translation>Texto tamanho padrão (fator de escala: </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
|
<location filename="../qml/panes/SettingsPane.qml" line="102"/>
|
||||||
<source>small-text-label</source>
|
<source>small-text-label</source>
|
||||||
<translation type="vanished">Pequeno</translation>
|
<translation>Pequeno</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>StackToolbar</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../qml/widgets/StackToolbar.qml" line="58"/>
|
||||||
|
<source>view-group-membership-tooltip</source>
|
||||||
|
<extracomment>View Group Membership</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
</TS>
|
</TS>
|
||||||
|
|
28
main.go
28
main.go
|
@ -3,11 +3,10 @@ package main
|
||||||
import (
|
import (
|
||||||
libapp "cwtch.im/cwtch/app"
|
libapp "cwtch.im/cwtch/app"
|
||||||
"cwtch.im/cwtch/event/bridge"
|
"cwtch.im/cwtch/event/bridge"
|
||||||
"cwtch.im/ui/go/characters"
|
"cwtch.im/ui/go/handlers"
|
||||||
"cwtch.im/ui/go/gobjects"
|
|
||||||
"cwtch.im/ui/go/gothings"
|
|
||||||
"cwtch.im/ui/go/gothings/android"
|
|
||||||
"cwtch.im/ui/go/the"
|
"cwtch.im/ui/go/the"
|
||||||
|
"cwtch.im/ui/go/ui"
|
||||||
|
"cwtch.im/ui/go/ui/android"
|
||||||
"flag"
|
"flag"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
||||||
|
@ -34,7 +33,7 @@ var (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// make go-defined types available in qml
|
// make go-defined types available in qml
|
||||||
gothings.GrandCentralDispatcher_QmlRegisterType2("CustomQmlTypes", 1, 0, "GrandCentralDispatcher")
|
ui.GrandCentralDispatcher_QmlRegisterType2("CustomQmlTypes", 1, 0, "GrandCentralDispatcher")
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -58,7 +57,9 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TESTING
|
// TESTING
|
||||||
//log.SetLevel(log.LevelDebug)
|
if buildVer == "" {
|
||||||
|
log.SetLevel(log.LevelDebug)
|
||||||
|
}
|
||||||
//log.ExcludeFromPattern("connection/connection")
|
//log.ExcludeFromPattern("connection/connection")
|
||||||
//log.ExcludeFromPattern("outbound/3dhauthchannel")
|
//log.ExcludeFromPattern("outbound/3dhauthchannel")
|
||||||
//log.AddNothingExceptFilter("event/eventmanager")
|
//log.AddNothingExceptFilter("event/eventmanager")
|
||||||
|
@ -75,6 +76,12 @@ func main() {
|
||||||
}
|
}
|
||||||
the.CwtchDir = path.Join(usr.HomeDir, ".cwtch")
|
the.CwtchDir = path.Join(usr.HomeDir, ".cwtch")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if buildVer == "" && os.Getenv("CWTCH_FOLDER") == "" {
|
||||||
|
log.Infoln("Development build: using dev directory for dev profiles")
|
||||||
|
the.CwtchDir = path.Join(the.CwtchDir, "dev")
|
||||||
|
}
|
||||||
|
|
||||||
the.ACN = nil
|
the.ACN = nil
|
||||||
the.Peer = nil
|
the.Peer = nil
|
||||||
the.IPCBridge = nil
|
the.IPCBridge = nil
|
||||||
|
@ -111,6 +118,7 @@ func mainService() {
|
||||||
log.Infoln("Making QGuiApplication...")
|
log.Infoln("Making QGuiApplication...")
|
||||||
app = gui.NewQGuiApplication(len(os.Args), os.Args)
|
app = gui.NewQGuiApplication(len(os.Args), os.Args)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infoln("Cwtch Service starting app.Exec")
|
log.Infoln("Cwtch Service starting app.Exec")
|
||||||
app.Exec()
|
app.Exec()
|
||||||
}
|
}
|
||||||
|
@ -121,7 +129,7 @@ func mainUi(flagLocal bool, flagClientUI bool) {
|
||||||
//app := gui.NewQGuiApplication(len(os.Args), os.Args)
|
//app := gui.NewQGuiApplication(len(os.Args), os.Args)
|
||||||
app := widgets.NewQApplication(len(os.Args), os.Args)
|
app := widgets.NewQApplication(len(os.Args), os.Args)
|
||||||
// our globals
|
// our globals
|
||||||
gcd := gothings.NewGrandCentralDispatcher(nil)
|
gcd := ui.NewGrandCentralDispatcher(nil)
|
||||||
gcd.SetOs(runtime.GOOS)
|
gcd.SetOs(runtime.GOOS)
|
||||||
ex, err := os.Executable()
|
ex, err := os.Executable()
|
||||||
if err != nil { log.Infof("error getting path: %v", err) }
|
if err != nil { log.Infof("error getting path: %v", err) }
|
||||||
|
@ -139,8 +147,6 @@ func mainUi(flagLocal bool, flagClientUI bool) {
|
||||||
gcd.SetVersion("development")
|
gcd.SetVersion("development")
|
||||||
gcd.SetBuildDate("now")
|
gcd.SetBuildDate("now")
|
||||||
}
|
}
|
||||||
gcd.UIState = gothings.NewUIState(gcd)
|
|
||||||
gcd.OutgoingMessages = make(chan gobjects.Letter, 1000)
|
|
||||||
|
|
||||||
//TODO: put theme stuff somewhere better
|
//TODO: put theme stuff somewhere better
|
||||||
gcd.SetThemeScale(1.0)
|
gcd.SetThemeScale(1.0)
|
||||||
|
@ -232,7 +238,7 @@ func loadACN() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadNetworkingAndFiles(gcd *gothings.GrandCentralDispatcher, service bool, clientUI bool) {
|
func loadNetworkingAndFiles(gcd *ui.GrandCentralDispatcher, service bool, clientUI bool) {
|
||||||
if service || clientUI || runtime.GOOS == "android" {
|
if service || clientUI || runtime.GOOS == "android" {
|
||||||
clientIn := path.Join(the.CwtchDir, "clientIn")
|
clientIn := path.Join(the.CwtchDir, "clientIn")
|
||||||
serviceIn := path.Join(the.CwtchDir, "serviceIn")
|
serviceIn := path.Join(the.CwtchDir, "serviceIn")
|
||||||
|
@ -255,7 +261,7 @@ func loadNetworkingAndFiles(gcd *gothings.GrandCentralDispatcher, service bool,
|
||||||
if !service {
|
if !service {
|
||||||
the.AppBus = the.CwtchApp.GetPrimaryBus()
|
the.AppBus = the.CwtchApp.GetPrimaryBus()
|
||||||
subscribed := make(chan bool)
|
subscribed := make(chan bool)
|
||||||
go characters.AppEventListener(gcd, subscribed)
|
go handlers.App(gcd, subscribed, clientUI)
|
||||||
<-subscribed
|
<-subscribed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
45
qml/main.qml
45
qml/main.qml
|
@ -127,6 +127,13 @@ ApplicationWindow {
|
||||||
currentIndex: 1
|
currentIndex: 1
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
currentIndex: 0
|
||||||
|
readonly property int splashPane: 0
|
||||||
|
readonly property int managementPane: 1
|
||||||
|
readonly property int addEditProfilePane: 2
|
||||||
|
readonly property int profilePane: 3
|
||||||
|
property alias pane: parentStack.currentIndex
|
||||||
|
|
||||||
Rectangle { // Splash pane
|
Rectangle { // Splash pane
|
||||||
color: "#FFFFFF"
|
color: "#FFFFFF"
|
||||||
//Layout.fillHeight: true
|
//Layout.fillHeight: true
|
||||||
|
@ -143,6 +150,28 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle { // Profile login/management pane
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: false
|
||||||
|
color: "#D2C0DD"
|
||||||
|
|
||||||
|
ProfileManagerPane {
|
||||||
|
id: profilesPane
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle { // Profile login/management pane
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "#EEEEFF"
|
||||||
|
|
||||||
|
|
||||||
|
ProfileAddEditPane{
|
||||||
|
id: profileAddEditPane
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
RowLayout { // CONTAINS EVERYTHING EXCEPT THE TOOLBAR
|
RowLayout { // CONTAINS EVERYTHING EXCEPT THE TOOLBAR
|
||||||
/* anchors.left: ratio >= 0.92 ? parent.left : toolbar.right
|
/* anchors.left: ratio >= 0.92 ? parent.left : toolbar.right
|
||||||
|
@ -260,7 +289,23 @@ ApplicationWindow {
|
||||||
onSetToolbarTitle: function(str) {
|
onSetToolbarTitle: function(str) {
|
||||||
theStack.title = str
|
theStack.title = str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onLoaded: function() {
|
||||||
|
parentStack.pane = parentStack.managementPane
|
||||||
|
splashPane.running = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: Mutant.standard.imagePath = gcd.assetPath;
|
Component.onCompleted: Mutant.standard.imagePath = gcd.assetPath;
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: Qt.application
|
||||||
|
onStateChanged: function() {
|
||||||
|
// https://doc.qt.io/qt-5/qt.html#ApplicationState-enum
|
||||||
|
if (Qt.application.state == 4) {
|
||||||
|
// Active
|
||||||
|
gcd.onActivate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,7 @@ import QtQuick.Controls 1.4
|
||||||
import QtQuick.Layouts 1.3
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
|
||||||
import "../widgets"
|
import "../widgets" as Widgets
|
||||||
import "../widgets/controls" as Awesome
|
|
||||||
import "../fonts/Twemoji.js" as T
|
import "../fonts/Twemoji.js" as T
|
||||||
import "../utils.js" as Utils
|
import "../utils.js" as Utils
|
||||||
import "../styles"
|
import "../styles"
|
||||||
|
@ -87,13 +86,13 @@ ColumnLayout {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sv.contentY + sv.height >= sv.contentHeight - colMessages.height && sv.contentHeight > sv.height) {
|
/*if (sv.contentY + sv.height >= sv.contentHeight - colMessages.height && sv.contentHeight > sv.height) {
|
||||||
sv.contentY = sv.contentHeight - sv.height
|
sv.contentY = sv.contentHeight - sv.height
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpdateContact: function(_handle, _displayName, _image, _server, _badge, _status, _trusted, _blocked, _loading) {
|
onUpdateContactStatus: function(_handle, _status, _loading) {
|
||||||
if (gcd.currentOpenConversation == _handle) {
|
if (gcd.selectedConversation == _handle) {
|
||||||
if (_loading == true) {
|
if (_loading == true) {
|
||||||
newposttitle.enabled = false
|
newposttitle.enabled = false
|
||||||
newpostbody.enabled = false
|
newpostbody.enabled = false
|
||||||
|
@ -176,7 +175,7 @@ ColumnLayout {
|
||||||
width: parent.width - 50
|
width: parent.width - 50
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleButton {
|
Widgets.SimpleButton {
|
||||||
id: replybtn
|
id: replybtn
|
||||||
visible: selected
|
visible: selected
|
||||||
text: "reply"
|
text: "reply"
|
||||||
|
@ -231,7 +230,7 @@ ColumnLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SimpleButton { // SEND MESSAGE BUTTON
|
Widgets.SimpleButton { // SEND MESSAGE BUTTON
|
||||||
id: btnSend
|
id: btnSend
|
||||||
icon: "regular/paper-plane"
|
icon: "regular/paper-plane"
|
||||||
text: "post"
|
text: "post"
|
||||||
|
|
|
@ -112,10 +112,10 @@ Item {
|
||||||
messagesListView.positionViewAtEnd()
|
messagesListView.positionViewAtEnd()
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpdateContact: function(_handle, _displayName, _image, _server, _badge, _status, _trusted, _blocked, _loading) {
|
onUpdateContactStatus: function(_handle, _status, _loading) {
|
||||||
if (gcd.currentOpenConversation == _handle) {
|
if (gcd.selectedConversation == _handle) {
|
||||||
// Group is Synced OR p2p is Authenticated
|
// Group is Synced OR p2p is Authenticated
|
||||||
if ( (_handle.length == 32 && _status == 4) || _status == 3) {
|
if ( (_handle.length == 32 && _status == 4) || (_handle.length == 56 && _status == 3) ) {
|
||||||
txtMessage.enabled = true
|
txtMessage.enabled = true
|
||||||
btnSend.enabled = true
|
btnSend.enabled = true
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import QtQuick.Controls.Material 2.0
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 1.4
|
||||||
import QtQuick.Layouts 1.3
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
import "../widgets"
|
import "../widgets" as Widgets
|
||||||
import "../widgets/controls" as Awesome
|
import "../widgets/controls" as Awesome
|
||||||
import "../fonts/Twemoji.js" as T
|
import "../fonts/Twemoji.js" as T
|
||||||
import "../utils.js" as Utils
|
import "../utils.js" as Utils
|
||||||
|
@ -87,17 +87,17 @@ ColumnLayout {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if(msg.c != undefined) {
|
/*if(msg.c != undefined) {
|
||||||
jsonModel4.get(msg.c).complete = true
|
jsonModel4.get(msg.c).complete = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sv.contentY + sv.height >= sv.contentHeight - colMessages.height && sv.contentHeight > sv.height) {
|
if (sv.contentY + sv.height >= sv.contentHeight - colMessages.height && sv.contentHeight > sv.height) {
|
||||||
sv.contentY = sv.contentHeight - sv.height
|
sv.contentY = sv.contentHeight - sv.height
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpdateContact: function(_handle, _displayName, _image, _server, _badge, _status, _trusted, _blocked, _loading) {
|
onUpdateContactStatus: function(_handle, _status, _loading) {
|
||||||
if (gcd.currentOpenConversation == _handle) {
|
if (gcd.selectedConversation == _handle) {
|
||||||
if (_loading == true) {
|
if (_loading == true) {
|
||||||
newposttitle.enabled = false
|
newposttitle.enabled = false
|
||||||
btnSend.enabled = false
|
btnSend.enabled = false
|
||||||
|
@ -204,7 +204,7 @@ ColumnLayout {
|
||||||
style: CwtchTextFieldStyle{}
|
style: CwtchTextFieldStyle{}
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleButton { // SEND MESSAGE BUTTON
|
Widgets.SimpleButton { // SEND MESSAGE BUTTON
|
||||||
id: btnSend
|
id: btnSend
|
||||||
icon: "regular/paper-plane"
|
icon: "regular/paper-plane"
|
||||||
text: "add"
|
text: "add"
|
||||||
|
|
|
@ -105,7 +105,6 @@ ColumnLayout {
|
||||||
handle: _handle
|
handle: _handle
|
||||||
displayName: _displayName
|
displayName: _displayName
|
||||||
image: _image
|
image: _image
|
||||||
trusted: true
|
|
||||||
blocked: false
|
blocked: false
|
||||||
background: false
|
background: false
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import QtQuick.Layouts 1.3
|
||||||
import QtQuick.Window 2.11
|
import QtQuick.Window 2.11
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 1.4
|
||||||
|
|
||||||
import "../widgets"
|
import "../widgets" as Widgets
|
||||||
import "../styles"
|
import "../styles"
|
||||||
|
|
||||||
ColumnLayout { // settingsPane
|
ColumnLayout { // settingsPane
|
||||||
|
@ -14,7 +14,7 @@ ColumnLayout { // settingsPane
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
|
||||||
StackToolbar {
|
Widgets.StackToolbar {
|
||||||
id: stb
|
id: stb
|
||||||
text: qsTr("create-group-title")
|
text: qsTr("create-group-title")
|
||||||
aux.visible: false
|
aux.visible: false
|
||||||
|
@ -37,7 +37,7 @@ ColumnLayout { // settingsPane
|
||||||
spacing: 5
|
spacing: 5
|
||||||
width: root.width
|
width: root.width
|
||||||
|
|
||||||
ScalingLabel {
|
Widgets.ScalingLabel {
|
||||||
//: Server label
|
//: Server label
|
||||||
text: qsTr("server-label") + ":"
|
text: qsTr("server-label") + ":"
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ ColumnLayout { // settingsPane
|
||||||
text: "2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd"
|
text: "2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd"
|
||||||
}
|
}
|
||||||
|
|
||||||
ScalingLabel{
|
Widgets.ScalingLabel{
|
||||||
//: Group name label
|
//: Group name label
|
||||||
text: qsTr("group-name-label") + ":"
|
text: qsTr("group-name-label") + ":"
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ ColumnLayout { // settingsPane
|
||||||
text: qsTr("default-group-name")
|
text: qsTr("default-group-name")
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleButton {
|
Widgets.SimpleButton {
|
||||||
//: create group button
|
//: create group button
|
||||||
text: qsTr("create-group-btn")
|
text: qsTr("create-group-btn")
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import QtQuick.Layouts 1.3
|
||||||
import QtQuick.Window 2.11
|
import QtQuick.Window 2.11
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 1.4
|
||||||
|
|
||||||
import "../widgets"
|
import "../widgets" as Widgets
|
||||||
import "../styles"
|
import "../styles"
|
||||||
import "../utils.js" as Utils
|
import "../utils.js" as Utils
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ ColumnLayout { // groupSettingsPane
|
||||||
property string groupID
|
property string groupID
|
||||||
property variant addrbook
|
property variant addrbook
|
||||||
|
|
||||||
StackToolbar {
|
Widgets.StackToolbar {
|
||||||
id: toolbar
|
id: toolbar
|
||||||
aux.visible: false
|
aux.visible: false
|
||||||
back.onClicked: theStack.pane = theStack.messagePane
|
back.onClicked: theStack.pane = theStack.messagePane
|
||||||
|
@ -38,7 +38,7 @@ ColumnLayout { // groupSettingsPane
|
||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
spacing: 5
|
spacing: 5
|
||||||
|
|
||||||
ScalingLabel {
|
Widgets.ScalingLabel {
|
||||||
text: qsTr("server-label") + ":"
|
text: qsTr("server-label") + ":"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ ColumnLayout { // groupSettingsPane
|
||||||
readOnly: true
|
readOnly: true
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleButton {
|
Widgets.SimpleButton {
|
||||||
icon: "regular/clipboard"
|
icon: "regular/clipboard"
|
||||||
text: qsTr("copy-btn")
|
text: qsTr("copy-btn")
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ ColumnLayout { // groupSettingsPane
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ScalingLabel {
|
Widgets.ScalingLabel {
|
||||||
text: qsTr("invitation-label") + ":"
|
text: qsTr("invitation-label") + ":"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ ColumnLayout { // groupSettingsPane
|
||||||
readOnly: true
|
readOnly: true
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleButton {
|
Widgets.SimpleButton {
|
||||||
icon: "regular/clipboard"
|
icon: "regular/clipboard"
|
||||||
text: qsTr("copy-btn")
|
text: qsTr("copy-btn")
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ ColumnLayout { // groupSettingsPane
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ScalingLabel{
|
Widgets.ScalingLabel{
|
||||||
text: qsTr("group-name-label") + ":"
|
text: qsTr("group-name-label") + ":"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ ColumnLayout { // groupSettingsPane
|
||||||
style: CwtchTextFieldStyle{ width: tehcol.width * 0.8 }
|
style: CwtchTextFieldStyle{ width: tehcol.width * 0.8 }
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleButton {
|
Widgets.SimpleButton {
|
||||||
text: qsTr("save-btn")
|
text: qsTr("save-btn")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
@ -100,7 +100,7 @@ ColumnLayout { // groupSettingsPane
|
||||||
}
|
}
|
||||||
|
|
||||||
//: Invite someone to the group
|
//: Invite someone to the group
|
||||||
ScalingLabel { text: qsTr("invite-to-group-label") }
|
Widgets.ScalingLabel { text: qsTr("invite-to-group-label") }
|
||||||
|
|
||||||
ComboBox {
|
ComboBox {
|
||||||
id: cbInvite
|
id: cbInvite
|
||||||
|
@ -110,7 +110,7 @@ ColumnLayout { // groupSettingsPane
|
||||||
style: CwtchComboBoxStyle{}
|
style: CwtchComboBoxStyle{}
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleButton {
|
Widgets.SimpleButton {
|
||||||
text: qsTr("invite-btn")
|
text: qsTr("invite-btn")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
@ -118,7 +118,7 @@ ColumnLayout { // groupSettingsPane
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleButton {
|
Widgets.SimpleButton {
|
||||||
icon: "regular/trash-alt"
|
icon: "regular/trash-alt"
|
||||||
text: qsTr("delete-btn")
|
text: qsTr("delete-btn")
|
||||||
|
|
||||||
|
|
|
@ -19,14 +19,14 @@ ColumnLayout {
|
||||||
StackToolbar {
|
StackToolbar {
|
||||||
id: toolbar
|
id: toolbar
|
||||||
|
|
||||||
membership.visible: gcd.currentOpenConversation.length == 32
|
membership.visible: gcd.selectedConversation.length == 32
|
||||||
|
|
||||||
membership.onClicked: overlayStack.overlay = overlayStack.membershipOverlay
|
membership.onClicked: overlayStack.overlay = overlayStack.membershipOverlay
|
||||||
|
|
||||||
aux.onClicked: {
|
aux.onClicked: {
|
||||||
if (gcd.currentOpenConversation.length == 32) {
|
if (gcd.selectedConversation.length == 32) {
|
||||||
theStack.pane = theStack.groupProfilePane
|
theStack.pane = theStack.groupProfilePane
|
||||||
gcd.requestGroupSettings(gcd.currentOpenConversation)
|
gcd.requestGroupSettings(gcd.selectedConversation)
|
||||||
} else {
|
} else {
|
||||||
theStack.pane = theStack.userProfilePane
|
theStack.pane = theStack.userProfilePane
|
||||||
gcd.requestPeerSettings()
|
gcd.requestPeerSettings()
|
||||||
|
@ -36,7 +36,7 @@ ColumnLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
visible:!overlay.accepted && (gcd.currentOpenConversation.length == 32)
|
visible:!overlay.accepted && (gcd.selectedConversation.length == 32)
|
||||||
|
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
@ -49,8 +49,8 @@ ColumnLayout {
|
||||||
text: qsTr("accept-group-btn")
|
text: qsTr("accept-group-btn")
|
||||||
icon: "regular/heart"
|
icon: "regular/heart"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
gcd.acceptGroup(gcd.currentOpenConversation)
|
gcd.acceptGroup(gcd.selectedConversation)
|
||||||
gcd.requestGroupSettings(gcd.currentOpenConversation)
|
gcd.requestGroupSettings(gcd.selectedConversation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ ColumnLayout {
|
||||||
text: qsTr("reject-group-btn")
|
text: qsTr("reject-group-btn")
|
||||||
icon: "regular/trash-alt"
|
icon: "regular/trash-alt"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
gcd.leaveGroup(gcd.currentOpenConversation)
|
gcd.leaveGroup(gcd.selectedConversation)
|
||||||
theStack.pane = theStack.emptyPane
|
theStack.pane = theStack.emptyPane
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import QtQuick.Layouts 1.3
|
||||||
import QtQuick.Window 2.11
|
import QtQuick.Window 2.11
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 1.4
|
||||||
|
|
||||||
import "../widgets"
|
import "../widgets" as Widgets
|
||||||
import "../styles"
|
import "../styles"
|
||||||
|
|
||||||
ColumnLayout { // peerSettingsPane
|
ColumnLayout { // peerSettingsPane
|
||||||
|
@ -14,7 +14,7 @@ ColumnLayout { // peerSettingsPane
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
property bool blocked
|
property bool blocked
|
||||||
|
|
||||||
StackToolbar {
|
Widgets.StackToolbar {
|
||||||
id: toolbar
|
id: toolbar
|
||||||
aux.visible: false
|
aux.visible: false
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ ColumnLayout { // peerSettingsPane
|
||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
spacing: 5
|
spacing: 5
|
||||||
|
|
||||||
ScalingLabel {
|
Widgets.ScalingLabel {
|
||||||
text: qsTr("address-label")
|
text: qsTr("address-label")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ ColumnLayout { // peerSettingsPane
|
||||||
readOnly: true
|
readOnly: true
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleButton {
|
Widgets.SimpleButton {
|
||||||
icon: "regular/clipboard"
|
icon: "regular/clipboard"
|
||||||
text: qsTr("copy-btn")
|
text: qsTr("copy-btn")
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ ColumnLayout { // peerSettingsPane
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ScalingLabel{
|
Widgets.ScalingLabel{
|
||||||
text: qsTr("display-name-label")
|
text: qsTr("display-name-label")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ ColumnLayout { // peerSettingsPane
|
||||||
style: CwtchTextFieldStyle{ width: tehcol.width * 0.8 }
|
style: CwtchTextFieldStyle{ width: tehcol.width * 0.8 }
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleButton {
|
Widgets.SimpleButton {
|
||||||
text: qsTr("save-btn")
|
text: qsTr("save-btn")
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
@ -80,7 +80,7 @@ ColumnLayout { // peerSettingsPane
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SimpleButton {
|
Widgets.SimpleButton {
|
||||||
icon: "solid/hand-paper"
|
icon: "solid/hand-paper"
|
||||||
text: root.blocked ? qsTr("unblock-btn") : qsTr("block-btn")
|
text: root.blocked ? qsTr("unblock-btn") : qsTr("block-btn")
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ ColumnLayout { // peerSettingsPane
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SimpleButton {
|
Widgets.SimpleButton {
|
||||||
icon: "regular/trash-alt"
|
icon: "regular/trash-alt"
|
||||||
text: qsTr("delete-btn")
|
text: qsTr("delete-btn")
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,303 @@
|
||||||
|
import QtGraphicalEffects 1.0
|
||||||
|
import QtQuick 2.7
|
||||||
|
import QtQuick.Controls 2.13
|
||||||
|
import QtQuick.Controls.Material 2.0
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
import QtQuick.Window 2.11
|
||||||
|
|
||||||
|
|
||||||
|
import "../widgets" as Widgets
|
||||||
|
// import "../styles"
|
||||||
|
|
||||||
|
ColumnLayout { // Add Profile Pane
|
||||||
|
id: profileAddEditPane
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
property string mode // edit or add
|
||||||
|
property string onion
|
||||||
|
property string tag
|
||||||
|
property bool deleting
|
||||||
|
property bool changingPassword
|
||||||
|
|
||||||
|
Widgets.StackToolbar {
|
||||||
|
id: stb
|
||||||
|
text: mode == "add" ? qsTr("add-profile-title") : qsTr("edit-profile-title")
|
||||||
|
aux.visible: false
|
||||||
|
membership.visible: false
|
||||||
|
stack: "management"
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
mode = "add"
|
||||||
|
txtProfileName.text = qsTr("default-profile-name")
|
||||||
|
changingPassword = false
|
||||||
|
txtPassword1.text = ""
|
||||||
|
txtPassword2.text = ""
|
||||||
|
deleting = false
|
||||||
|
deleteConfirmLabel.color = "black"
|
||||||
|
passwordErrorLabel.visible = false
|
||||||
|
txtCurrentPassword.text = ""
|
||||||
|
|
||||||
|
tag = ""
|
||||||
|
confirmDeleteTxt.text = ""
|
||||||
|
radioUsePassword.checked = true
|
||||||
|
passwordChangeErrorLabel.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function load(userOnion, name, userTag) {
|
||||||
|
reset()
|
||||||
|
|
||||||
|
mode = "edit"
|
||||||
|
tag = userTag
|
||||||
|
onion = userOnion
|
||||||
|
txtPassword1.text = ""
|
||||||
|
txtPassword2.text = ""
|
||||||
|
onionLabel.text = onion
|
||||||
|
txtProfileName.text = name
|
||||||
|
|
||||||
|
if (tag == "v1-defaultPassword" || tag == "v1-default-password") {
|
||||||
|
radioNoPassword.checked = true
|
||||||
|
} else {
|
||||||
|
radioUsePassword.checked = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Flickable {
|
||||||
|
anchors.top: stb.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
clip:true
|
||||||
|
contentWidth: tehcol.width
|
||||||
|
contentHeight: tehcol.height
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: tehcol
|
||||||
|
leftPadding: 10
|
||||||
|
spacing: 5
|
||||||
|
width: profileAddEditPane.width
|
||||||
|
|
||||||
|
Widgets.ScalingLabel {
|
||||||
|
//: Onion
|
||||||
|
text: qsTr("profile-onion-label") + ":"
|
||||||
|
visible: mode == "edit"
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets.ScalingLabel {
|
||||||
|
id: onionLabel
|
||||||
|
visible: mode == "edit"
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets.ScalingLabel {
|
||||||
|
//: Display name
|
||||||
|
text: qsTr("profile-name") + ":"
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets.TextField {
|
||||||
|
id: txtProfileName
|
||||||
|
Layout.fillWidth: true
|
||||||
|
//style: CwtchTextFieldStyle{ width: tehcol.width * 0.8 }
|
||||||
|
//: default suggested profile name
|
||||||
|
text: qsTr("default-profile-name")
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
//id: radioButtons
|
||||||
|
|
||||||
|
Widgets.RadioButton {
|
||||||
|
id: radioUsePassword
|
||||||
|
checked: true
|
||||||
|
//: Password
|
||||||
|
text: qsTr("radio-use-password")
|
||||||
|
visible: mode == "add" || tag == "v1-defaultPassword"
|
||||||
|
onClicked: {
|
||||||
|
changingPassword = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets.RadioButton {
|
||||||
|
id: radioNoPassword
|
||||||
|
//: Unencrypted (No password)
|
||||||
|
text: qsTr("radio-no-password")
|
||||||
|
visible: mode == "add" || tag == "v1-defaultPassword"
|
||||||
|
onClicked: {
|
||||||
|
changingPassword = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets.ScalingLabel {
|
||||||
|
id: noPasswordLabel
|
||||||
|
//: Not using a password on this account means that all data stored locally will not be encrypted
|
||||||
|
text: qsTr("no-password-warning")
|
||||||
|
visible: radioNoPassword.checked
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets.ScalingLabel {
|
||||||
|
id: currentPasswordLabel
|
||||||
|
//: Current Password
|
||||||
|
text: qsTr("current-password-label") + ":"
|
||||||
|
visible: radioUsePassword.checked && mode == "edit" && tag != "v1-defaultPassword"
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets.TextField {
|
||||||
|
id: txtCurrentPassword
|
||||||
|
Layout.fillWidth: true
|
||||||
|
echoMode: TextInput.Password
|
||||||
|
visible: radioUsePassword.checked && mode == "edit" && tag != "v1-defaultPassword"
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets.ScalingLabel {
|
||||||
|
id: passwordLabel
|
||||||
|
//: Password
|
||||||
|
text: qsTr("password1-label") + ":"
|
||||||
|
visible: radioUsePassword.checked
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets.TextField {
|
||||||
|
id: txtPassword1
|
||||||
|
Layout.fillWidth: true
|
||||||
|
//style: CwtchTextFieldStyle{ width: tehcol.width * 0.8 }
|
||||||
|
echoMode: TextInput.Password
|
||||||
|
visible: radioUsePassword.checked
|
||||||
|
|
||||||
|
onTextEdited: {
|
||||||
|
changingPassword = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Widgets.ScalingLabel {
|
||||||
|
id: passwordReLabel
|
||||||
|
//: Reenter password
|
||||||
|
text: qsTr("password2-label") + ":"
|
||||||
|
visible: radioUsePassword.checked
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets.TextField {
|
||||||
|
id: txtPassword2
|
||||||
|
Layout.fillWidth: true
|
||||||
|
//style: CwtchTextFieldStyle{ width: tehcol.width * 0.8 }
|
||||||
|
echoMode: TextInput.Password
|
||||||
|
visible: radioUsePassword.checked
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets.SimpleButton { // ADD or SAVE button
|
||||||
|
//: Create Profile || Save Profile
|
||||||
|
text: mode == "add" ? qsTr("create-profile-btn") : qsTr("save-profile-btn")
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (mode == "add") {
|
||||||
|
if (txtPassword1.text != txtPassword2.text) {
|
||||||
|
passwordErrorLabel.visible = true
|
||||||
|
} else {
|
||||||
|
gcd.createProfile(txtProfileName.text, radioNoPassword.checked, txtPassword1.text)
|
||||||
|
gcd.reloadProfileList()
|
||||||
|
parentStack.pane = parentStack.managementPane
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gcd.updateNick(onion, txtProfileName.text)
|
||||||
|
|
||||||
|
if (changingPassword) {
|
||||||
|
if (txtPassword1.text != txtPassword2.text) {
|
||||||
|
passwordErrorLabel.visible = true
|
||||||
|
} else {
|
||||||
|
gcd.changePassword(onion, txtCurrentPassword.text, txtPassword1.text, radioNoPassword.checked)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gcd.reloadProfileList()
|
||||||
|
parentStack.pane = parentStack.managementPane
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets.ScalingLabel {
|
||||||
|
id: passwordErrorLabel
|
||||||
|
//: Passwords do not match
|
||||||
|
text: qsTr("password-error-match")
|
||||||
|
visible: false
|
||||||
|
color: "red"
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets.ScalingLabel {
|
||||||
|
id: passwordChangeErrorLabel
|
||||||
|
//: Error changing password: Supplied password rejected
|
||||||
|
text: qsTr("password-change-error")
|
||||||
|
visible: false
|
||||||
|
color: "red"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ***** Delete button and confirm flow *****
|
||||||
|
|
||||||
|
Widgets.SimpleButton {
|
||||||
|
//: Delete Profile
|
||||||
|
text: qsTr("delete-profile-btn")
|
||||||
|
icon: "regular/trash-alt"
|
||||||
|
visible: mode == "edit"
|
||||||
|
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
deleting = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets.ScalingLabel {
|
||||||
|
id: deleteConfirmLabel
|
||||||
|
//: Type DELETE to confirm
|
||||||
|
text: qsTr("delete-confirm-label")+ ":"
|
||||||
|
visible: deleting
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets.TextField {
|
||||||
|
id: confirmDeleteTxt
|
||||||
|
Layout.fillWidth: true
|
||||||
|
//style: CwtchTextFieldStyle{ width: tehcol.width * 0.8 }
|
||||||
|
visible: deleting
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets.SimpleButton {
|
||||||
|
id: confirmDeleteBtn
|
||||||
|
icon: "regular/trash-alt"
|
||||||
|
|
||||||
|
//: Really Delete Profile
|
||||||
|
text: qsTr("delete-profile-confirm-btn")
|
||||||
|
color: "red"
|
||||||
|
visible: deleting
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
//: DELETE
|
||||||
|
if (confirmDeleteTxt.text == qsTr("delete-confirm-text")) {
|
||||||
|
deleteConfirmLabel.color = "black"
|
||||||
|
gcd.deleteProfile(onion)
|
||||||
|
gcd.reloadProfileList()
|
||||||
|
parentStack.pane = parentStack.managementPane
|
||||||
|
} else {
|
||||||
|
deleteConfirmLabel.color = "red"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}//end of column with padding
|
||||||
|
}//end of flickable
|
||||||
|
|
||||||
|
Connections { // UPDATE UNREAD MESSAGES COUNTER
|
||||||
|
target: gcd
|
||||||
|
|
||||||
|
onChangePasswordResponse: function(error) {
|
||||||
|
if (!error) {
|
||||||
|
gcd.reloadProfileList()
|
||||||
|
parentStack.pane = parentStack.managementPane
|
||||||
|
} else {
|
||||||
|
passwordChangeErrorLabel.visible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
import QtQuick 2.0
|
||||||
|
import QtGraphicalEffects 1.0
|
||||||
|
import QtQuick 2.7
|
||||||
|
import QtQuick.Controls 2.4
|
||||||
|
import QtQuick.Controls.Material 2.0
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
import QtQuick.Window 2.11
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
import QtQuick.Controls.Styles 1.4
|
||||||
|
|
||||||
|
import "../widgets" as Widgets
|
||||||
|
import "../widgets/controls"
|
||||||
|
import "../styles"
|
||||||
|
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: thecol
|
||||||
|
anchors.fill: parent
|
||||||
|
//leftPadding: 10
|
||||||
|
//spacing: 5
|
||||||
|
|
||||||
|
Widgets.ScalingLabel {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
wrapMode: TextEdit.Wrap
|
||||||
|
//: Please enter password:
|
||||||
|
text: qsTr("enter-profile-password")+":"
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
id: txtPassword
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
style: CwtchTextFieldStyle{ width: thecol.width * 0.8 }
|
||||||
|
echoMode: TextInput.Password
|
||||||
|
onAccepted: button.clicked()
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets.ScalingLabel {
|
||||||
|
id: error
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
color: "red"
|
||||||
|
//: 0 profiles loaded with that password
|
||||||
|
text: qsTr("error-0-profiles-loaded-for-password")
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
|
||||||
|
Widgets.SimpleButton {
|
||||||
|
id: "button"
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
icon: "solid/unlock-alt"
|
||||||
|
//: Unlock
|
||||||
|
text: qsTr("unlock")
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
gcd.unlockProfiles(txtPassword.text)
|
||||||
|
txtPassword.text = ""
|
||||||
|
error.visible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections { // ADD/REMOVE CONTACT ENTRIES
|
||||||
|
target: gcd
|
||||||
|
|
||||||
|
onErrorLoaded0: function() {
|
||||||
|
error.visible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Rectangle { // THE LEFT PANE WITH TOOLS AND CONTACTS
|
||||||
|
color: "#D2C0DD"
|
||||||
|
width: thecol.width
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.minimumWidth: Layout.maximumWidth
|
||||||
|
//Layout.maximumWidth: theStack.pane == theStack.emptyPane ? parent.width : 450
|
||||||
|
|
||||||
|
Widgets.ProfileList {
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -47,19 +47,36 @@ ColumnLayout {
|
||||||
Connections { // ADD/REMOVE CONTACT ENTRIES
|
Connections { // ADD/REMOVE CONTACT ENTRIES
|
||||||
target: gcd
|
target: gcd
|
||||||
|
|
||||||
onAddContact: function(handle, displayName, image, server, badge, status, trusted, blocked, loading) {
|
onAddContact: function(handle, displayName, image, server, badge, status, blocked, loading, lastMsgTs) {
|
||||||
contactsModel.append({
|
|
||||||
"_handle": handle,
|
for (var i = 0; i < contactsModel.count; i++) {
|
||||||
"_displayName": displayName + (blocked ? " (blocked)" : "" ),
|
if (contactsModel.get(i)["_handle"] == handle) {
|
||||||
"_image": image,
|
return
|
||||||
"_server": server,
|
}
|
||||||
"_badge": badge,
|
}
|
||||||
"_status": status,
|
|
||||||
"_trusted": trusted,
|
var index = contactsModel.count
|
||||||
"_blocked": blocked,
|
for (var i = 0; i < contactsModel.count; i++) {
|
||||||
"_loading": loading,
|
if (contactsModel.get(i)["_lastMsgTs"] < lastMsgTs) {
|
||||||
"_loading": loading
|
index = i
|
||||||
})
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var newContact = {
|
||||||
|
"_handle": handle,
|
||||||
|
"_displayName": displayName + (blocked ? " (blocked)" : "" ),
|
||||||
|
"_image": image,
|
||||||
|
"_server": server,
|
||||||
|
"_badge": badge,
|
||||||
|
"_status": status,
|
||||||
|
"_blocked": blocked,
|
||||||
|
"_loading": loading,
|
||||||
|
"_loading": loading,
|
||||||
|
"_lastMsgTs": lastMsgTs
|
||||||
|
}
|
||||||
|
|
||||||
|
contactsModel.insert(index, newContact)
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemoveContact: function(handle) {
|
onRemoveContact: function(handle) {
|
||||||
|
@ -71,6 +88,22 @@ ColumnLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onIncContactUnreadCount: function(handle) {
|
||||||
|
var ts = Math.round((new Date()).getTime() / 1000);
|
||||||
|
for(var i = 0; i < contactsModel.count; i++){
|
||||||
|
if(contactsModel.get(i)["_handle"] == handle) {
|
||||||
|
var contact = contactsModel.get(i)
|
||||||
|
contact["_lastMsgTs"] = ts
|
||||||
|
console.log("Found at " + i + " contact: " + contact)
|
||||||
|
contactsModel.move(i, 0, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onResetProfile: function() {
|
||||||
|
contactsModel.clear()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListModel { // CONTACT OBJECTS ARE STORED HERE ...
|
ListModel { // CONTACT OBJECTS ARE STORED HERE ...
|
||||||
|
@ -86,11 +119,18 @@ ColumnLayout {
|
||||||
server: _server
|
server: _server
|
||||||
badge: _badge
|
badge: _badge
|
||||||
status: _status
|
status: _status
|
||||||
trusted: _trusted
|
|
||||||
blocked: _blocked
|
blocked: _blocked
|
||||||
loading: _loading
|
loading: _loading
|
||||||
|
type: "contact"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ Item {
|
||||||
property bool isGroup
|
property bool isGroup
|
||||||
property bool showStatus
|
property bool showStatus
|
||||||
property bool highlight
|
property bool highlight
|
||||||
|
property bool button
|
||||||
property real logscale: 4 * Math.log10(gcd.themeScale + 1)
|
property real logscale: 4 * Math.log10(gcd.themeScale + 1)
|
||||||
property int baseWidth: 48 * logscale
|
property int baseWidth: 48 * logscale
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ Item {
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: highlight ? baseWidth - 4 : baseWidth
|
width: highlight ? baseWidth - 4 : baseWidth
|
||||||
height: highlight ? baseWidth - 4 : baseWidth
|
height: highlight ? baseWidth - 4 : baseWidth
|
||||||
color: "#FFFFFF"
|
color: button ? windowItem.cwtch_dark_color: "#FFFFFF"
|
||||||
radius: width / 2
|
radius: width / 2
|
||||||
anchors.centerIn:parent
|
anchors.centerIn:parent
|
||||||
|
|
||||||
|
@ -69,7 +70,7 @@ Item {
|
||||||
anchors.margins: 4 * logscale
|
anchors.margins: 4 * logscale
|
||||||
|
|
||||||
|
|
||||||
Rectangle { //-2:WtfCodeError,-1:Untrusted,0:Disconnected,1:Connecting,2:Connected,3:Authenticated,4:Synced,5:Failed,6:Killed
|
Rectangle { //-2:WtfCodeError,-1:Error,0:Disconnected,1:Connecting,2:Connected,3:Authenticated,4:Synced,5:Failed,6:Killed
|
||||||
color: status == 4 ? "green" : status == 3 ? "green" : status == -1 ? "blue" : status == 1 ? "orange" : status == 2 ? "orange" : "red"
|
color: status == 4 ? "green" : status == 3 ? "green" : status == -1 ? "blue" : status == 1 ? "orange" : status == 2 ? "orange" : "red"
|
||||||
width: 5 * logscale
|
width: 5 * logscale
|
||||||
height: 5 * logscale
|
height: 5 * logscale
|
||||||
|
|
|
@ -10,6 +10,7 @@ import QtQuick.Controls.Styles 1.4
|
||||||
|
|
||||||
|
|
||||||
Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
|
Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
|
||||||
|
id: crItem
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
height: 48 * logscale + 3
|
height: 48 * logscale + 3
|
||||||
|
@ -22,12 +23,18 @@ Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
|
||||||
property int badge
|
property int badge
|
||||||
property bool isActive
|
property bool isActive
|
||||||
property bool isHover
|
property bool isHover
|
||||||
property bool trusted
|
property bool background: true
|
||||||
|
property string type // profile or contact or button
|
||||||
|
property string tag // profile version/type
|
||||||
|
|
||||||
|
// Profile
|
||||||
|
property bool defaultPassword
|
||||||
|
|
||||||
|
// Contact
|
||||||
property bool blocked
|
property bool blocked
|
||||||
property bool loading
|
property bool loading
|
||||||
property alias status: imgProfile.status
|
property alias status: imgProfile.status
|
||||||
property string server
|
property string server
|
||||||
property bool background: true
|
|
||||||
|
|
||||||
|
|
||||||
Rectangle { // CONTACT ENTRY BACKGROUND COLOR
|
Rectangle { // CONTACT ENTRY BACKGROUND COLOR
|
||||||
|
@ -40,24 +47,43 @@ Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
|
||||||
|
|
||||||
ContactPicture {
|
ContactPicture {
|
||||||
id: imgProfile
|
id: imgProfile
|
||||||
showStatus: true
|
showStatus: type == "contact"
|
||||||
|
button: type == "button"
|
||||||
}
|
}
|
||||||
|
|
||||||
Label { // CONTACT NAME
|
ColumnLayout {
|
||||||
id: cn
|
|
||||||
leftPadding: 10
|
|
||||||
rightPadding: 10
|
|
||||||
//wrapMode: Text.WordWrap
|
|
||||||
anchors.left: imgProfile.right
|
anchors.left: imgProfile.right
|
||||||
anchors.right: loading ? loadingProgress.left : rectUnread.left
|
anchors.right: loading ? loadingProgress.left : rectUnread.left
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
font.pixelSize: 16 * gcd.themeScale
|
|
||||||
font.italic: !trusted
|
|
||||||
font.strikeout: blocked
|
Label { // CONTACT NAME
|
||||||
textFormat: Text.PlainText
|
id: cn
|
||||||
//fontSizeMode: Text.HorizontalFit
|
leftPadding: 10
|
||||||
elide: Text.ElideRight
|
rightPadding: 10
|
||||||
color: "#000000"
|
//wrapMode: Text.WordWrap
|
||||||
|
font.pixelSize: 16 * gcd.themeScale
|
||||||
|
font.strikeout: blocked
|
||||||
|
textFormat: Text.PlainText
|
||||||
|
//fontSizeMode: Text.HorizontalFit
|
||||||
|
elide: Text.ElideRight
|
||||||
|
color: "#000000"
|
||||||
|
}
|
||||||
|
|
||||||
|
Label { // Onion
|
||||||
|
id: onion
|
||||||
|
text: handle
|
||||||
|
leftPadding: 10
|
||||||
|
rightPadding: 10
|
||||||
|
font.pixelSize: 10 * gcd.themeScale
|
||||||
|
font.strikeout: blocked
|
||||||
|
textFormat: Text.PlainText
|
||||||
|
//fontSizeMode: Text.HorizontalFit
|
||||||
|
elide: Text.ElideRight
|
||||||
|
color: "#000000"
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle { // UNREAD MESSAGES?
|
Rectangle { // UNREAD MESSAGES?
|
||||||
|
@ -87,6 +113,27 @@ Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Profile
|
||||||
|
|
||||||
|
Image {// Profle Type
|
||||||
|
id: profiletype
|
||||||
|
|
||||||
|
source: tag == "v1-userPassword" ? "qrc:/qml/images/fontawesome/solid/lock.svg" : "qrc:/qml/images/fontawesome/solid/lock-open.svg"
|
||||||
|
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.leftMargin: 1 * gcd.themeScale
|
||||||
|
anchors.rightMargin: (20 * gcd.themeScale) + parent.height
|
||||||
|
height: parent.height * 0.5
|
||||||
|
width: height
|
||||||
|
|
||||||
|
visible: type == "profile"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Contact
|
||||||
ProgressBar { // LOADING ?
|
ProgressBar { // LOADING ?
|
||||||
id: loadingProgress
|
id: loadingProgress
|
||||||
property bool running
|
property bool running
|
||||||
|
@ -118,14 +165,26 @@ Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (displayName != "me") {
|
if (type == "contact") {
|
||||||
gcd.broadcast("ResetMessagePane")
|
if (displayName != "me") {
|
||||||
isActive = true
|
gcd.broadcast("ResetMessagePane")
|
||||||
theStack.pane = theStack.messagePane
|
isActive = true
|
||||||
gcd.loadMessagesPane(handle)
|
theStack.pane = theStack.messagePane
|
||||||
if (handle.length == 32) {
|
gcd.loadMessagesPane(handle)
|
||||||
gcd.requestGroupSettings(handle)
|
badge = 0
|
||||||
}
|
if (handle.length == 32) {
|
||||||
|
gcd.requestGroupSettings(handle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (type == "profile") {
|
||||||
|
gcd.broadcast("ResetMessagePane")
|
||||||
|
gcd.broadcast("ResetProfile")
|
||||||
|
gcd.selectedProfile = handle
|
||||||
|
gcd.loadProfile(handle)
|
||||||
|
parentStack.pane = parentStack.profilePane
|
||||||
|
} else if (type == "button") { // Add profile button
|
||||||
|
profileAddEditPane.reset()
|
||||||
|
parentStack.pane = parentStack.addEditProfilePane
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,6 +197,27 @@ Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SimpleButton {// Edit BUTTON
|
||||||
|
id: btnEdit
|
||||||
|
icon: "solid/user-edit"
|
||||||
|
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
//rectUnread.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.leftMargin: 1 * gcd.themeScale
|
||||||
|
anchors.rightMargin: 20 * gcd.themeScale
|
||||||
|
height: parent.height * 0.75
|
||||||
|
|
||||||
|
visible: type == "profile"
|
||||||
|
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
profileAddEditPane.load(handle, displayName, tag)
|
||||||
|
parentStack.pane = parentStack.addEditProfilePane
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Connections { // UPDATE UNREAD MESSAGES COUNTER
|
Connections { // UPDATE UNREAD MESSAGES COUNTER
|
||||||
target: gcd
|
target: gcd
|
||||||
|
|
||||||
|
@ -145,17 +225,29 @@ Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
|
||||||
isActive = false
|
isActive = false
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpdateContact: function(_handle, _displayName, _image, _server, _badge, _status, _trusted, _blocked, _loading) {
|
onUpdateContactStatus: function(_handle, _status, _loading) {
|
||||||
if (handle == _handle) {
|
if (handle == _handle) {
|
||||||
displayName = _displayName + (_blocked == true ? " (blocked)" : "")
|
status = _status
|
||||||
image = _image
|
|
||||||
server = _server
|
|
||||||
badge = _badge
|
|
||||||
status = _status
|
|
||||||
trusted = _trusted
|
|
||||||
blocked = _blocked
|
|
||||||
loadingProgress.visible = loadingProgress.running = loading = _loading
|
loadingProgress.visible = loadingProgress.running = loading = _loading
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onUpdateContactBlocked: function(_handle, _blocked) {
|
||||||
|
if (handle == _handle) {
|
||||||
|
blocked = _blocked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onUpdateContactDisplayName: function(_handle, _displayName) {
|
||||||
|
if (handle == _handle) {
|
||||||
|
displayName = _displayName + (_blocked == true ? " (blocked)" : "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onIncContactUnreadCount: function(handle) {
|
||||||
|
if (handle == _handle && gcd.selectedConversation != handle) {
|
||||||
|
badge++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ Item {
|
||||||
|
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
gcd.createContact(from)
|
||||||
gcd.broadcast("ResetMessagePane")
|
gcd.broadcast("ResetMessagePane")
|
||||||
theStack.pane = theStack.messagePane
|
theStack.pane = theStack.messagePane
|
||||||
gcd.loadMessagesPane(from)
|
gcd.loadMessagesPane(from)
|
||||||
|
|
|
@ -19,6 +19,22 @@ ColumnLayout {
|
||||||
property string onion
|
property string onion
|
||||||
|
|
||||||
|
|
||||||
|
SimpleButton {// BACK BUTTON
|
||||||
|
id: btnBack
|
||||||
|
icon: "solid/arrow-circle-left"
|
||||||
|
anchors.left: parent.left
|
||||||
|
//anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.leftMargin: 2
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: 2
|
||||||
|
onClicked: function() {
|
||||||
|
gcd.selectedProfile = "none"
|
||||||
|
gcd.reloadProfileList()
|
||||||
|
parentStack.pane = parentStack.managementPane
|
||||||
|
theStack.pane = theStack.emptyPane
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Item{ height: 6 }
|
Item{ height: 6 }
|
||||||
|
|
||||||
Item { // PROFILE IMAGE
|
Item { // PROFILE IMAGE
|
||||||
|
@ -106,7 +122,7 @@ ColumnLayout {
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
onUpdated: {
|
onUpdated: {
|
||||||
gcd.updateNick(lblNick.text)
|
gcd.updateNick(onion, lblNick.text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,8 +246,6 @@ ColumnLayout {
|
||||||
lblNick.text = _nick
|
lblNick.text = _nick
|
||||||
onion = _onion
|
onion = _onion
|
||||||
image = _image
|
image = _image
|
||||||
parentStack.currentIndex = 1
|
|
||||||
splashPane.running = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onTorStatus: function(code, str) {
|
onTorStatus: function(code, str) {
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
import QtGraphicalEffects 1.0
|
||||||
|
import QtQuick 2.7
|
||||||
|
import QtQuick.Controls 2.4
|
||||||
|
import QtQuick.Controls.Material 2.0
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Flickable { // Profile List
|
||||||
|
id: sv
|
||||||
|
clip: true
|
||||||
|
Layout.minimumHeight: 100
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.minimumWidth: parent.width
|
||||||
|
Layout.maximumWidth: parent.width
|
||||||
|
contentWidth: colContacts.width
|
||||||
|
contentHeight: colContacts.height
|
||||||
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
maximumFlickVelocity: 400
|
||||||
|
|
||||||
|
|
||||||
|
ScrollBar.vertical: ScrollBar {
|
||||||
|
policy: ScrollBar.AlwaysOn
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: colContacts
|
||||||
|
width: root.width
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Connections { // ADD/REMOVE CONTACT ENTRIES
|
||||||
|
target: gcd
|
||||||
|
|
||||||
|
onAddProfile: function(handle, displayName, image, tag) {
|
||||||
|
|
||||||
|
// don't add duplicates
|
||||||
|
console.log("ProfileList onAddProfile for: " + handle)
|
||||||
|
for (var i = 0; i < profilesModel.count; i++) {
|
||||||
|
if (profilesModel.get(i)["_handle"] == handle) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// find index for insert (sort by onion)
|
||||||
|
var index = profilesModel.count-1
|
||||||
|
for (var i = 0; i < profilesModel.count-1; i++) {
|
||||||
|
if (profilesModel.get(i)["_handle"] > handle) {
|
||||||
|
index = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
profilesModel.insert(index,
|
||||||
|
{
|
||||||
|
"_handle": handle,
|
||||||
|
"_displayName": displayName,
|
||||||
|
"_image": image,
|
||||||
|
"_type": "profile",
|
||||||
|
"_tag": tag
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
onRemoveProfile: function(handle) {
|
||||||
|
for(var i = 0; i < profilesModel.count; i++){
|
||||||
|
if(profilesModel.get(i)["_handle"] == handle) {
|
||||||
|
console.log("deleting contact " + profilesModel.get(i)["_handle"])
|
||||||
|
profilesModel.remove(i)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
onResetProfileList: function() {
|
||||||
|
profilesModel.clear()
|
||||||
|
profilesModel.append({
|
||||||
|
_handle: "",
|
||||||
|
_displayName: qsTr("add-new-profile-btn"),
|
||||||
|
_image: "qrc:/qml/images/fontawesome/solid/user-plus.svg",
|
||||||
|
_type: "button",
|
||||||
|
_tag: ","
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListModel { // Profile OBJECTS ARE STORED HERE ...
|
||||||
|
id: profilesModel
|
||||||
|
|
||||||
|
ListElement {
|
||||||
|
_handle: ""
|
||||||
|
_displayName: qsTr("add-new-profile-btn")
|
||||||
|
_image: "qrc:/qml/images/fontawesome/solid/user-plus.svg"
|
||||||
|
_type: "button"
|
||||||
|
_tag: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: profilesModel // ... AND DISPLAYED HERE
|
||||||
|
delegate: ContactRow {
|
||||||
|
handle: _handle
|
||||||
|
displayName: _displayName
|
||||||
|
image: _image
|
||||||
|
server: ""
|
||||||
|
badge: 0
|
||||||
|
status: 0
|
||||||
|
blocked: false
|
||||||
|
loading: false
|
||||||
|
type: _type
|
||||||
|
tag: _tag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
import QtQuick 2.7
|
||||||
|
|
||||||
|
import QtQuick.Controls 2.13
|
||||||
|
|
||||||
|
|
||||||
|
RadioButton {
|
||||||
|
id: control
|
||||||
|
|
||||||
|
property real size: 12
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
indicator: Rectangle {
|
||||||
|
width: 16 * gcd.themeScale
|
||||||
|
height: 16 * gcd.themeScale
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
radius: 9
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: control.checked
|
||||||
|
color: "black"
|
||||||
|
radius: 9
|
||||||
|
anchors.margins: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,6 @@ import QtQuick.Controls 2.4
|
||||||
import QtQuick.Controls.Material 2.0
|
import QtQuick.Controls.Material 2.0
|
||||||
import QtQuick.Layouts 1.3
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
import "controls" as Awesome
|
|
||||||
import "../fonts/Twemoji.js" as T
|
import "../fonts/Twemoji.js" as T
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import QtQuick.Controls 2.4
|
||||||
import QtQuick.Controls.Material 2.0
|
import QtQuick.Controls.Material 2.0
|
||||||
import QtQuick.Layouts 1.3
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
import "controls" as Awesome
|
|
||||||
import "../fonts/Twemoji.js" as T
|
import "../fonts/Twemoji.js" as T
|
||||||
|
|
||||||
Rectangle { // OVERHEAD BAR ON STACK PANE
|
Rectangle { // OVERHEAD BAR ON STACK PANE
|
||||||
|
@ -21,6 +20,7 @@ Rectangle { // OVERHEAD BAR ON STACK PANE
|
||||||
property alias aux: btnAux
|
property alias aux: btnAux
|
||||||
property alias back: btnBack
|
property alias back: btnBack
|
||||||
property alias membership: btnMembership
|
property alias membership: btnMembership
|
||||||
|
property string stack: "profile" // profile(theStack) or management(parentStack)
|
||||||
|
|
||||||
|
|
||||||
SimpleButton {// BACK BUTTON
|
SimpleButton {// BACK BUTTON
|
||||||
|
@ -29,7 +29,13 @@ Rectangle { // OVERHEAD BAR ON STACK PANE
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.leftMargin: 6
|
anchors.leftMargin: 6
|
||||||
onClicked: theStack.pane = theStack.emptyPane
|
onClicked: {
|
||||||
|
if (stack == "profile") {
|
||||||
|
theStack.pane = theStack.emptyPane
|
||||||
|
} else {
|
||||||
|
parentStack.pane = parentStack.managementPane
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ScalingLabel { // TEXT
|
ScalingLabel { // TEXT
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
import QtQuick 2.7
|
||||||
|
|
||||||
|
import QtQuick.Controls 2.13
|
||||||
|
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
color: "black"
|
||||||
|
font.pointSize: 10 * gcd.themeScale
|
||||||
|
width: 100
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
radius: 2
|
||||||
|
color: windowItem.cwtch_background_color
|
||||||
|
border.color: windowItem.cwtch_color
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,81 +0,0 @@
|
||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
**
|
|
||||||
** Copyright (c) 2014 Ricardo do Valle Flores de Oliveira
|
|
||||||
**
|
|
||||||
** $BEGIN_LICENSE:MIT$
|
|
||||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
** of this software and associated documentation files (the "Software"), to deal
|
|
||||||
** in the Software without restriction, including without limitation the rights
|
|
||||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
** copies of the Software, and to permit persons to whom the Software is
|
|
||||||
** furnished to do so, subject to the following conditions:
|
|
||||||
**
|
|
||||||
** The above copyright notice and this permission notice shall be included in
|
|
||||||
** all copies or substantial portions of the Software.
|
|
||||||
**
|
|
||||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
** SOFTWARE.
|
|
||||||
**
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
import QtQuick 2.0
|
|
||||||
import QtQuick.Controls 1.0
|
|
||||||
import QtQuick.Controls.Styles 1.0
|
|
||||||
import QtQuick.Layouts 1.0
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: button
|
|
||||||
property string icon
|
|
||||||
property color color: "black"
|
|
||||||
property font font
|
|
||||||
|
|
||||||
style: ButtonStyle {
|
|
||||||
id: buttonstyle
|
|
||||||
property font font: button.font
|
|
||||||
property color foregroundColor: button.color
|
|
||||||
|
|
||||||
background: Item {
|
|
||||||
Rectangle {
|
|
||||||
id: baserect
|
|
||||||
anchors.fill: parent
|
|
||||||
color: "transparent"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
label: Item {
|
|
||||||
implicitWidth: row.implicitWidth
|
|
||||||
implicitHeight: row.implicitHeight
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: row
|
|
||||||
anchors.centerIn: parent
|
|
||||||
spacing: 15
|
|
||||||
|
|
||||||
Text {
|
|
||||||
color: buttonstyle.foregroundColor
|
|
||||||
font.pointSize: buttonstyle.font.pointSize * 2
|
|
||||||
font.family: awesome.family
|
|
||||||
renderType: Text.NativeRendering
|
|
||||||
text: awesome.loaded ? icon : ""
|
|
||||||
visible: !(icon === "")
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
color: buttonstyle.foregroundColor
|
|
||||||
font: buttonstyle.font
|
|
||||||
renderType: Text.NativeRendering
|
|
||||||
text: control.text
|
|
||||||
visible: !(control.text === "")
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignBottom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** The MIT License (MIT)
|
|
||||||
**
|
|
||||||
** Copyright (c) 2014 Ricardo do Valle Flores de Oliveira
|
|
||||||
**
|
|
||||||
** $BEGIN_LICENSE:MIT$
|
|
||||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
** of this software and associated documentation files (the "Software"), to deal
|
|
||||||
** in the Software without restriction, including without limitation the rights
|
|
||||||
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
** copies of the Software, and to permit persons to whom the Software is
|
|
||||||
** furnished to do so, subject to the following conditions:
|
|
||||||
**
|
|
||||||
** The above copyright notice and this permission notice shall be included in
|
|
||||||
** all copies or substantial portions of the Software.
|
|
||||||
**
|
|
||||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
** SOFTWARE.
|
|
||||||
**
|
|
||||||
** $END_LICENSE$
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
import QtQuick 2.0
|
|
||||||
import QtQuick.Controls 1.0
|
|
||||||
import QtQuick.Layouts 1.0
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property alias spacing: row.spacing
|
|
||||||
property alias text: content.text
|
|
||||||
property color color: "black"
|
|
||||||
property font font
|
|
||||||
property string icon
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: row
|
|
||||||
|
|
||||||
Text {
|
|
||||||
color: root.color
|
|
||||||
font.pointSize: root.font.pointSize
|
|
||||||
font.family: awesome.family
|
|
||||||
renderType: Text.NativeRendering
|
|
||||||
text: awesome.loaded ? icon : ""
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: content
|
|
||||||
color: root.color
|
|
||||||
font.pointSize: root.font.pointSize
|
|
||||||
renderType: Text.NativeRendering
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue