Compare commits

...

19 Commits

Author SHA1 Message Date
erinn a43d148da8 Merge branch 'translate-en' of dan/ui into master 2019-03-13 10:55:53 -07:00
Dan Ballard e4db07bee8 Add english translations. change translatable strings to ids 2019-03-11 14:39:47 -07:00
erinn c36d74639e Merge branch 'translate' of dan/ui into master 2019-03-07 13:11:30 -08:00
Dan Ballard 901109409b adding i18n support 2019-03-06 14:56:07 -08:00
erinn 7a9022bac1 Merge branch 'alpha-updates' of cwtch.im/ui into master 2019-03-06 13:22:32 -08:00
Sarah Jamie Lewis bcd81c813d Add User Feedback when hovering over a contact in groups 2019-03-06 13:18:25 -08:00
erinn ac6fb8d2e8 Merge branch 'alpha-updates' of cwtch.im/ui into master 2019-03-06 12:25:30 -08:00
Sarah Jamie Lewis c483bded55 Only use recieved messages to update the group membership 2019-03-06 12:22:43 -08:00
erinn 713c3ed72d Merge branch 'alpha-updates' of cwtch.im/ui into master 2019-03-06 12:02:03 -08:00
Sarah Jamie Lewis 153651478a Adding Basic Group Membership Pane 2019-03-06 12:00:55 -08:00
Sarah Jamie Lewis eaa700ba57 Merge branch 'ebf201903051402' of cwtch.im/ui into master 2019-03-05 14:04:14 -08:00
erinn c4b0eeccfb Merge branch 'alpha-updates' of cwtch.im/ui into master 2019-03-05 14:03:52 -08:00
erinn 202153bab2 fix implicitwidth issue 2019-03-05 14:02:29 -08:00
Sarah Jamie Lewis d4abc25ed0 Remove Info Log 2019-03-05 13:40:16 -08:00
erinn ebdaf54ff9 Merge branch 'alpha-updates' of cwtch.im/ui into master 2019-03-05 12:23:36 -08:00
Dan Ballard 2e7f49bde4 drone branch restrict master 2019-03-05 12:22:11 -08:00
Sarah Jamie Lewis a9b1f7904a Fixing Error Handling for Peer Connections, Ack's now don't ack'd error'd messages.
Also fixed 1 concurrent map access issue by moving to sync.Map
2019-03-05 12:18:53 -08:00
Dan Ballard d6fc4766a0 Merge branch 'master' of git.openprivacy.ca:cwtch.im/ui 2019-03-04 15:07:58 -08:00
Dan Ballard 3cc713ed9a drone restict when builds by repo 2019-03-04 14:15:07 -08:00
32 changed files with 1027 additions and 134 deletions

View File

@ -7,9 +7,9 @@ pipeline:
mem_limit: 3G
image: therecipe/qt:linux
when:
branch: master
repo: cwtch.im/ui
branch: master
event: [ push, pull_request ]
status: [ success ]
environment:
- QT_DIR=/opt/Qt
- QT_DOCKER='true'
@ -30,9 +30,9 @@ pipeline:
mem_limit: 3G
image: therecipe/qt:android
when:
branch: master
repo: cwtch.im/ui
branch: master
event: push
status: [ success ]
environment:
- QT_DIR=/opt/Qt
- QT_DOCKER='true'
@ -55,9 +55,9 @@ pipeline:
mem_limit: 3G
image: therecipe/qt:windows_64_shared
when:
branch: master
repo: cwtch.im/ui
branch: master
event: push
status: [ success ]
environment:
- QT_DIR=/opt/Qt
- QT_DOCKER='true'
@ -83,7 +83,8 @@ pipeline:
image: pivotaldata/concourse-ssh
secrets: [buildfiles_key]
when:
branch: master
repo: cwtch.im/ui
branch: master
event: push
status: [ success ]
commands:
@ -103,10 +104,14 @@ pipeline:
skip_verify: true
from: drone@openprivacy.ca
when:
repo: cwtch.im/ui
branch: master
status: [ failure ]
notify-gogs:
image: openpriv/drone-gogs
when:
repo: cwtch.im/ui
branch: master
event: pull_request
status: [ success, changed, failure ]
secrets: [gogs_account_token]

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ rcc*
*.qmlc
*.jsc
vendor/
.directory

View File

@ -41,3 +41,9 @@ 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 and run `qtdeploy` in the root of it.
Currently you will need to manually run tor first before running cwtch.im/ui. Use the included tor and torrc file: `tor -f torrc`
# Development
## Translations
Translations can be update by runing QT Linguist in the project directory (`linguist`) and loading and editing any of the `i18n/translate_*.ts` files. To add a new translation, please register the file in qml.qrc. To update translations, run `lupdate ui.pro` to update the editable .ts files and when you are done run `lrelease ui.pro` to generate the .qm files that are used at runtime.

View File

@ -11,7 +11,7 @@ import (
"time"
)
func IncomingListener(callback func(*gobjects.Message), groupErrorCallback func(string,string)) {
func IncomingListener(callback func(*gobjects.Message), groupErrorCallback func(string, string,string)) {
q := event.NewEventQueue(1000)
the.CwtchApp.EventBus().Subscribe(event.NewMessageFromPeer, q.EventChannel)
the.CwtchApp.EventBus().Subscribe(event.NewMessageFromGroup, q.EventChannel)
@ -68,9 +68,9 @@ func IncomingListener(callback func(*gobjects.Message), groupErrorCallback func(
case event.NewGroupInvite:
log.Debugf("got a group invite!")
case event.SendMessageToGroupError:
groupErrorCallback(e.Data[event.Signature], e.Data[event.Error])
groupErrorCallback(e.Data[event.GroupServer], e.Data[event.Signature], e.Data[event.Error])
case event.SendMessageToPeerError:
groupErrorCallback(e.Data[event.Signature], e.Data[event.Error])
groupErrorCallback(e.Data[event.RemotePeer], e.Data[event.Signature], e.Data[event.Error])
}
}
}

View File

@ -14,7 +14,6 @@ func RandomProfileImage(onion string) string {
barr, err := base32.StdEncoding.DecodeString(strings.ToUpper(onion))
if err != nil || len(barr) != 35 {
log.Errorf("error: %v %v %v\n", onion, err, barr)
panic("lol")
return "qrc:/qml/images/extra/openprivacy.png"
}
return "qrc:/qml/images/profiles/" + choices[int(barr[33])%len(choices)] + ".png"

View File

@ -12,4 +12,5 @@ type Message struct {
MessageID string
Timestamp time.Time
Acknowledged bool
Error bool
}

View File

@ -29,7 +29,7 @@ type GrandCentralDispatcher struct {
_ func(handle, key, value string) `signal:"UpdateContactAttribute"`
// messages pane stuff
_ func(handle, from, displayName, message, image string, mID string, fromMe bool, ts string, ackd bool) `signal:"AppendMessage"`
_ func(handle, from, displayName, message, image string, mID string, fromMe bool, ts string, ackd bool, error bool) `signal:"AppendMessage"`
_ func() `signal:"ClearMessages"`
_ func() `signal:"ResetMessagePane"`
_ func(mID string) `signal:"Acknowledged"`
@ -99,6 +99,7 @@ func (this *GrandCentralDispatcher) sendMessage(message string, mID string) {
mID,
time.Now(),
false,
false,
})
if err != nil {
@ -118,7 +119,7 @@ func (this *GrandCentralDispatcher) sendMessage(message string, mID string) {
mID = the.Peer.SendMessageToPeer(to, message)
this.UIState.AddMessage(&gobjects.Message{
this.CurrentOpenConversation(),
to,
"me",
"",
message,
@ -127,6 +128,7 @@ func (this *GrandCentralDispatcher) sendMessage(message string, mID string) {
mID,
time.Now(),
false,
false,
})
ackID := new(the.AckId)
@ -201,7 +203,8 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
tl[i].PeerID == the.Peer.GetProfile().Onion,
tl[i].Timestamp.Format(constants.TIME_FORMAT),
tl[i].Received.Equal(time.Unix(0,0)) == false, // If the received timestamp is epoch, we have not yet received this message through an active server
)
false,
)
}
return
} // ELSE LOAD CONTACT
@ -222,6 +225,7 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
if messages[i].FromMe {
from = "me"
}
this.AppendMessage(
messages[i].Handle,
from,
@ -231,10 +235,11 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
messages[i].MessageID,
messages[i].FromMe,
messages[i].Timestamp.Format(constants.TIME_FORMAT),
true,
false,
messages[i].Error,
)
for _,id := range the.AcknowledgementIDs[messages[i].Handle] {
if id.ID == messages[i].MessageID && id.Ack{
if id.ID == messages[i].MessageID && id.Ack && !id.Error {
this.Acknowledged(id.ID)
}
}

View File

@ -9,16 +9,18 @@ import (
"git.openprivacy.ca/openprivacy/libricochet-go/log"
"runtime/debug"
"strings"
"sync"
"time"
)
type InterfaceState struct {
parentGcd *GrandCentralDispatcher
contacts map[string]*gobjects.Contact
messages map[string][]*gobjects.Message
messages sync.Map
}
func NewUIState(gcd *GrandCentralDispatcher) (uis InterfaceState) {
uis = InterfaceState{gcd, make(map[string]*gobjects.Contact), make(map[string][]*gobjects.Message)}
uis = InterfaceState{gcd, make(map[string]*gobjects.Contact), sync.Map{}}
return
}
@ -86,16 +88,33 @@ func (this *InterfaceState) GetContact(handle string) *gobjects.Contact {
return this.contacts[handle]
}
func (this *InterfaceState) AddGroupError(signature string, err string) {
func (this *InterfaceState) AddSendMessageError(peer string, signature string, err string) {
acklist := the.AcknowledgementIDs[peer]
for _,ack := range acklist {
if ack.ID == signature {
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 %v", signature, 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[m.Handle]
_,found := this.messages.Load(m.Handle)
if !found {
this.messages[m.Handle] = make([]*gobjects.Message, 0)
this.messages.Store(m.Handle, make([]*gobjects.Message, 0))
}
// Ack message sent to group
@ -107,17 +126,22 @@ func (this *InterfaceState) AddMessage(m *gobjects.Message) {
// If an ack, swallow the message and ack from the list.
acklist := the.AcknowledgementIDs[m.From]
for _,ack := range acklist {
ack.Ack = true
this.parentGcd.Acknowledged(ack.ID)
if ack.Error == false {
ack.Ack = true
this.parentGcd.Acknowledged(ack.ID)
}
}
} else {
this.messages[m.Handle] = append(this.messages[m.Handle], m)
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)
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)
}
@ -133,11 +157,13 @@ func (this *InterfaceState) AddMessage(m *gobjects.Message) {
}
func (this *InterfaceState) GetMessages(handle string) []*gobjects.Message {
_, found := this.messages[handle]
_,found := this.messages.Load(handle)
if !found {
this.messages[handle] = make([]*gobjects.Message, 0)
this.messages.Store(handle, make([]*gobjects.Message, 0))
}
return this.messages[handle]
messages,found := this.messages.Load(handle)
messageList,_ := messages.([]*gobjects.Message)
return messageList
}
func (this *InterfaceState) UpdateContact(handle string) {

View File

@ -12,6 +12,7 @@ var CwtchDir string
type AckId struct {
ID string
Ack bool
Error bool
}
var AcknowledgementIDs map[string][]*AckId

BIN
i18n/translation_de.qm Normal file

Binary file not shown.

289
i18n/translation_de.ts Normal file
View File

@ -0,0 +1,289 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="de_DE">
<context>
<name>AddGroupPane</name>
<message>
<location filename="../qml/panes/AddGroupPane.qml" line="17"/>
<source>create-group-title</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/AddGroupPane.qml" line="27"/>
<source>server-label</source>
<extracomment>Server label</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/AddGroupPane.qml" line="38"/>
<source>group-name-label</source>
<extracomment>Group name label</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/AddGroupPane.qml" line="45"/>
<source>default-group-name</source>
<extracomment>default suggested group name</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/AddGroupPane.qml" line="50"/>
<source>create-group-btn</source>
<extracomment>create group button</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>BulletinOverlay</name>
<message>
<location filename="../qml/overlays/BulletinOverlay.qml" line="181"/>
<source>new-bulletin-label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/overlays/BulletinOverlay.qml" line="193"/>
<source>post-new-bulletin-label</source>
<extracomment>Post a new Bulletin Post</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/overlays/BulletinOverlay.qml" line="199"/>
<source>title-placeholder</source>
<extracomment>title place holder text</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>GroupSettingsPane</name>
<message>
<location filename="../qml/panes/GroupSettingsPane.qml" line="30"/>
<source>server-label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/GroupSettingsPane.qml" line="41"/>
<location filename="../qml/panes/GroupSettingsPane.qml" line="62"/>
<source>copy-btn</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/GroupSettingsPane.qml" line="51"/>
<source>invitation-label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/GroupSettingsPane.qml" line="72"/>
<source>group-name-label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/GroupSettingsPane.qml" line="81"/>
<source>save-btn</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/GroupSettingsPane.qml" line="91"/>
<source>invite-to-group-label</source>
<extracomment>Invite someone to the group</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/GroupSettingsPane.qml" line="102"/>
<source>invite-btn</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/GroupSettingsPane.qml" line="111"/>
<source>delete-btn</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ListOverlay</name>
<message>
<location filename="../qml/overlays/ListOverlay.qml" line="162"/>
<source>add-list-item</source>
<extracomment>Add a New List Item</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/overlays/ListOverlay.qml" line="174"/>
<source>add-new-item</source>
<extracomment>Add a new item to the list</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/overlays/ListOverlay.qml" line="180"/>
<source>todo-placeholder</source>
<extracomment>Todo... placeholder text</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MembershipOverlay</name>
<message>
<location filename="../qml/overlays/MembershipOverlay.qml" line="21"/>
<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>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Message</name>
<message>
<location filename="../qml/widgets/Message.qml" line="55"/>
<source>dm-tooltip</source>
<extracomment>Click to DM</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/widgets/Message.qml" line="154"/>
<source>could-not-send-msg-error</source>
<extracomment>Could not send this message</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/widgets/Message.qml" line="154"/>
<source>acknowledged-label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/widgets/Message.qml" line="154"/>
<source>pending-label</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MyProfile</name>
<message>
<location filename="../qml/widgets/MyProfile.qml" line="169"/>
<source>copy-btn</source>
<extracomment>Button for copying profile onion address to clipboard</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/widgets/MyProfile.qml" line="173"/>
<source>copied-clipboard-notification</source>
<extracomment>Copied to clipboard</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/widgets/MyProfile.qml" line="203"/>
<source>new-group-btn</source>
<extracomment>create new group button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/widgets/MyProfile.qml" line="213"/>
<source>paste-address-to-add-contact</source>
<extracomment>ex: &quot;... paste an address here to add a contact ...&quot;</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>OverlayPane</name>
<message>
<location filename="../qml/panes/OverlayPane.qml" line="44"/>
<source>accept-group-invite-label</source>
<extracomment>Do you want to accept the invitation to $GROUP</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/OverlayPane.qml" line="49"/>
<source>accept-group-btn</source>
<extracomment>Accept group invite button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/OverlayPane.qml" line="59"/>
<source>reject-group-btn</source>
<extracomment>Reject Group invite button</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/OverlayPane.qml" line="73"/>
<source>chat-btn</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/OverlayPane.qml" line="80"/>
<source>lists-btn</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/OverlayPane.qml" line="87"/>
<source>bulletins-btn</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/OverlayPane.qml" line="94"/>
<source>puzzle-game-btn</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PeerSettingsPane</name>
<message>
<location filename="../qml/panes/PeerSettingsPane.qml" line="29"/>
<source>address-label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/PeerSettingsPane.qml" line="40"/>
<source>copy-btn</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/PeerSettingsPane.qml" line="44"/>
<source>copied-to-clipboard-notification</source>
<extracomment>notification: copied to clipboard</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/PeerSettingsPane.qml" line="51"/>
<source>display-name-label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/PeerSettingsPane.qml" line="60"/>
<source>save-btn</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/PeerSettingsPane.qml" line="71"/>
<source>delete-btn</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SettingsPane</name>
<message>
<location filename="../qml/panes/SettingsPane.qml" line="17"/>
<source>cwtch-settings-title</source>
<extracomment>Cwtch Settings title</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/SettingsPane.qml" line="28"/>
<source>zoom-label</source>
<extracomment>Interface zoom (mostly affects text and button sizes)</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/SettingsPane.qml" line="44"/>
<source>large-text-label</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/SettingsPane.qml" line="50"/>
<source>default-scaling-text</source>
<extracomment>&quot;Default size text (scale factor: &quot;</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/panes/SettingsPane.qml" line="54"/>
<source>small-text-label</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

BIN
i18n/translation_en.qm Normal file

Binary file not shown.

289
i18n/translation_en.ts Normal file
View File

@ -0,0 +1,289 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="en_US">
<context>
<name>AddGroupPane</name>
<message>
<location filename="../qml/panes/AddGroupPane.qml" line="17"/>
<source>create-group-title</source>
<translation>Create Group</translation>
</message>
<message>
<location filename="../qml/panes/AddGroupPane.qml" line="27"/>
<source>server-label</source>
<extracomment>Server label</extracomment>
<translation>Server</translation>
</message>
<message>
<location filename="../qml/panes/AddGroupPane.qml" line="38"/>
<source>group-name-label</source>
<extracomment>Group name label</extracomment>
<translation>Group name</translation>
</message>
<message>
<location filename="../qml/panes/AddGroupPane.qml" line="45"/>
<source>default-group-name</source>
<extracomment>default suggested group name</extracomment>
<translation>Awesome Group</translation>
</message>
<message>
<location filename="../qml/panes/AddGroupPane.qml" line="50"/>
<source>create-group-btn</source>
<extracomment>create group button</extracomment>
<translation>Create</translation>
</message>
</context>
<context>
<name>BulletinOverlay</name>
<message>
<location filename="../qml/overlays/BulletinOverlay.qml" line="181"/>
<source>new-bulletin-label</source>
<translation>New Bulletin</translation>
</message>
<message>
<location filename="../qml/overlays/BulletinOverlay.qml" line="193"/>
<source>post-new-bulletin-label</source>
<extracomment>Post a new Bulletin Post</extracomment>
<translation>Post new bulletin</translation>
</message>
<message>
<location filename="../qml/overlays/BulletinOverlay.qml" line="199"/>
<source>title-placeholder</source>
<extracomment>title place holder text</extracomment>
<translation>title...</translation>
</message>
</context>
<context>
<name>GroupSettingsPane</name>
<message>
<location filename="../qml/panes/GroupSettingsPane.qml" line="30"/>
<source>server-label</source>
<translation>Server</translation>
</message>
<message>
<location filename="../qml/panes/GroupSettingsPane.qml" line="41"/>
<location filename="../qml/panes/GroupSettingsPane.qml" line="62"/>
<source>copy-btn</source>
<translation>Copy</translation>
</message>
<message>
<location filename="../qml/panes/GroupSettingsPane.qml" line="51"/>
<source>invitation-label</source>
<translation>Invitation</translation>
</message>
<message>
<location filename="../qml/panes/GroupSettingsPane.qml" line="72"/>
<source>group-name-label</source>
<translation>Group Name</translation>
</message>
<message>
<location filename="../qml/panes/GroupSettingsPane.qml" line="81"/>
<source>save-btn</source>
<translation>Save</translation>
</message>
<message>
<location filename="../qml/panes/GroupSettingsPane.qml" line="91"/>
<source>invite-to-group-label</source>
<extracomment>Invite someone to the group</extracomment>
<translation>Invite to group</translation>
</message>
<message>
<location filename="../qml/panes/GroupSettingsPane.qml" line="102"/>
<source>invite-btn</source>
<translation>Invite</translation>
</message>
<message>
<location filename="../qml/panes/GroupSettingsPane.qml" line="111"/>
<source>delete-btn</source>
<translation>Delete</translation>
</message>
</context>
<context>
<name>ListOverlay</name>
<message>
<location filename="../qml/overlays/ListOverlay.qml" line="162"/>
<source>add-list-item</source>
<extracomment>Add a New List Item</extracomment>
<translation>Add a New List Item</translation>
</message>
<message>
<location filename="../qml/overlays/ListOverlay.qml" line="174"/>
<source>add-new-item</source>
<extracomment>Add a new item to the list</extracomment>
<translation>Add a new item to the list</translation>
</message>
<message>
<location filename="../qml/overlays/ListOverlay.qml" line="180"/>
<source>todo-placeholder</source>
<extracomment>Todo... placeholder text</extracomment>
<translation>Todo...</translation>
</message>
</context>
<context>
<name>MembershipOverlay</name>
<message>
<location filename="../qml/overlays/MembershipOverlay.qml" line="21"/>
<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>
<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>
</context>
<context>
<name>Message</name>
<message>
<location filename="../qml/widgets/Message.qml" line="55"/>
<source>dm-tooltip</source>
<extracomment>Click to DM</extracomment>
<translation>Click to DM</translation>
</message>
<message>
<location filename="../qml/widgets/Message.qml" line="154"/>
<source>could-not-send-msg-error</source>
<extracomment>Could not send this message</extracomment>
<translation>Could not send this message</translation>
</message>
<message>
<location filename="../qml/widgets/Message.qml" line="154"/>
<source>acknowledged-label</source>
<translation>Acknowledged</translation>
</message>
<message>
<location filename="../qml/widgets/Message.qml" line="154"/>
<source>pending-label</source>
<translation>Pending</translation>
</message>
</context>
<context>
<name>MyProfile</name>
<message>
<location filename="../qml/widgets/MyProfile.qml" line="169"/>
<source>copy-btn</source>
<extracomment>Button for copying profile onion address to clipboard</extracomment>
<translation>Copy</translation>
</message>
<message>
<location filename="../qml/widgets/MyProfile.qml" line="173"/>
<source>copied-clipboard-notification</source>
<extracomment>Copied to clipboard</extracomment>
<translation>Copied to clipboard</translation>
</message>
<message>
<location filename="../qml/widgets/MyProfile.qml" line="203"/>
<source>new-group-btn</source>
<extracomment>create new group button</extracomment>
<translation>Create new group</translation>
</message>
<message>
<location filename="../qml/widgets/MyProfile.qml" line="213"/>
<source>paste-address-to-add-contact</source>
<extracomment>ex: &quot;... paste an address here to add a contact ...&quot;</extracomment>
<translation>... paste an address here to add a contact...</translation>
</message>
</context>
<context>
<name>OverlayPane</name>
<message>
<location filename="../qml/panes/OverlayPane.qml" line="44"/>
<source>accept-group-invite-label</source>
<extracomment>Do you want to accept the invitation to $GROUP</extracomment>
<translation>Do you want to accept the invitation to</translation>
</message>
<message>
<location filename="../qml/panes/OverlayPane.qml" line="49"/>
<source>accept-group-btn</source>
<extracomment>Accept group invite button</extracomment>
<translation>Accept</translation>
</message>
<message>
<location filename="../qml/panes/OverlayPane.qml" line="59"/>
<source>reject-group-btn</source>
<extracomment>Reject Group invite button</extracomment>
<translation>Reject</translation>
</message>
<message>
<location filename="../qml/panes/OverlayPane.qml" line="73"/>
<source>chat-btn</source>
<translation>Chat</translation>
</message>
<message>
<location filename="../qml/panes/OverlayPane.qml" line="80"/>
<source>lists-btn</source>
<translation>Lists</translation>
</message>
<message>
<location filename="../qml/panes/OverlayPane.qml" line="87"/>
<source>bulletins-btn</source>
<translation>Bulletins</translation>
</message>
<message>
<location filename="../qml/panes/OverlayPane.qml" line="94"/>
<source>puzzle-game-btn</source>
<translation>Puzzle Game</translation>
</message>
</context>
<context>
<name>PeerSettingsPane</name>
<message>
<location filename="../qml/panes/PeerSettingsPane.qml" line="29"/>
<source>address-label</source>
<translation>Address</translation>
</message>
<message>
<location filename="../qml/panes/PeerSettingsPane.qml" line="40"/>
<source>copy-btn</source>
<translation>Copy</translation>
</message>
<message>
<location filename="../qml/panes/PeerSettingsPane.qml" line="44"/>
<source>copied-to-clipboard-notification</source>
<extracomment>notification: copied to clipboard</extracomment>
<translation>Copied to Clipboard</translation>
</message>
<message>
<location filename="../qml/panes/PeerSettingsPane.qml" line="51"/>
<source>display-name-label</source>
<translation>Display Name</translation>
</message>
<message>
<location filename="../qml/panes/PeerSettingsPane.qml" line="60"/>
<source>save-btn</source>
<translation>Save</translation>
</message>
<message>
<location filename="../qml/panes/PeerSettingsPane.qml" line="71"/>
<source>delete-btn</source>
<translation>Delete</translation>
</message>
</context>
<context>
<name>SettingsPane</name>
<message>
<location filename="../qml/panes/SettingsPane.qml" line="17"/>
<source>cwtch-settings-title</source>
<extracomment>Cwtch Settings title</extracomment>
<translation>Cwtch Settings</translation>
</message>
<message>
<location filename="../qml/panes/SettingsPane.qml" line="28"/>
<source>zoom-label</source>
<extracomment>Interface zoom (mostly affects text and button sizes)</extracomment>
<translation>Interface zoon (mostly affects text and button sizes)</translation>
</message>
<message>
<location filename="../qml/panes/SettingsPane.qml" line="44"/>
<source>large-text-label</source>
<translation type="unfinished">Large</translation>
</message>
<message>
<location filename="../qml/panes/SettingsPane.qml" line="50"/>
<source>default-scaling-text</source>
<extracomment>&quot;Default size text (scale factor: &quot;</extracomment>
<translation>Default size text (scale factor:</translation>
</message>
<message>
<location filename="../qml/panes/SettingsPane.qml" line="54"/>
<source>small-text-label</source>
<translation>Small</translation>
</message>
</context>
</TS>

View File

@ -57,6 +57,10 @@ func main() {
app := gui.NewQGuiApplication(len(os.Args), os.Args)
app.SetWindowIcon(gui.NewQIcon5(":/qml/images/cwtch-icon.png"))
var translator = core.NewQTranslator(nil)
translator.Load("translation_"+core.QLocale_System().Name(), ":/i18n/", "", "")
core.QCoreApplication_InstallTranslator(translator)
core.QCoreApplication_SetAttribute(core.Qt__AA_EnableHighDpiScaling, true)
quickcontrols2.QQuickStyle_SetStyle("Universe")
engine := qml.NewQQmlApplicationEngine(nil)
@ -111,7 +115,7 @@ func main() {
// these are long-lived pollers/listeners for incoming messages and status changes
loadCwtchData(gcd, acn)
go characters.IncomingListener(gcd.UIState.AddMessage, gcd.UIState.AddGroupError)
go characters.IncomingListener(gcd.UIState.AddMessage, gcd.UIState.AddSendMessageError)
go characters.TorStatusPoller(gcd.TorStatus, acn)
go characters.PresencePoller(gcd.UIState.GetContact, gcd.UIState.AddContact, gcd.UIState.UpdateContact)
go characters.GroupPoller(gcd.UIState.GetContact, gcd.UIState.UpdateContact)

36
qml.qrc Normal file
View File

@ -0,0 +1,36 @@
<RCC>
<qresource prefix="/">
<file>qml/overlays/BulletinOverlay.qml</file>
<file>qml/overlays/ChatOverlay.qml</file>
<file>qml/overlays/Game1Overlay.qml</file>
<file>qml/overlays/Game2Overlay.qml</file>
<file>qml/overlays/ListOverlay.qml</file>
<file>qml/overlays/MembershipOverlay.qml</file>
<file>qml/main.qml</file>
<file>qml/panes/AddGroupPane.qml</file>
<file>qml/panes/GroupSettingsPane.qml</file>
<file>qml/panes/OverlayPane.qml</file>
<file>qml/panes/PeerSettingsPane.qml</file>
<file>qml/panes/SettingsPane.qml</file>
<file>qml/styles/CwtchComboBoxStyle.qml</file>
<file>qml/styles/CwtchExpandingButton.qml</file>
<file>qml/styles/CwtchTextAreaStyle.qml</file>
<file>qml/styles/CwtchTextFieldStyle.qml</file>
<file>qml/widgets/ContactList.qml</file>
<file>qml/widgets/ContactPicture.qml</file>
<file>qml/widgets/ContactRow.qml</file>
<file>qml/widgets/FontAwesome.qml</file>
<file>qml/widgets/InplaceEditText.qml</file>
<file>qml/widgets/Message.qml</file>
<file>qml/widgets/MyProfile.qml</file>
<file>qml/widgets/ScalingLabel.qml</file>
<file>qml/widgets/SimpleButton.qml</file>
<file>qml/widgets/StackToolbar.qml</file>
<file>qml/widgets/controls/Button.qml</file>
<file>qml/widgets/controls/Loader.qml</file>
<file>qml/widgets/controls/Text.qml</file>
<file>qml/widgets/controls/Variables.qml</file>
<file>i18n/translation_en.qm</file>
<file>i18n/translation_de.qm</file>
</qresource>
</RCC>

View File

@ -120,7 +120,7 @@ ApplicationWindow {
Layout.fillHeight: true
Layout.minimumWidth: Layout.maximumWidth
Layout.maximumWidth: theStack.pane == theStack.emptyPane ? parent.width : 450
visible: (ratio <= 1.08 && windowItem.width >= 500) || theStack.pane == theStack.emptyPane
visible: (ratio <= 1.08 && windowItem.width >= 700) || theStack.pane == theStack.emptyPane
ContactList{

View File

@ -59,7 +59,7 @@ ColumnLayout {
jsonModel4.clear()
}
onAppendMessage: function(handle, from, displayName, message, image, mid, fromMe, ts) {
onAppendMessage: function(handle, from, displayName, message, image, mid, fromMe, ts, ack, error) {
var msg
try {
msg = JSON.parse(message)
@ -178,7 +178,7 @@ ColumnLayout {
}
GroupBox {
title: qsTr("New Bulletin")
title: qsTr("new-bulletin-label")
Layout.fillWidth: true
RowLayout {
@ -189,12 +189,14 @@ ColumnLayout {
Text {
text: "Post a new Bulletin Post"
//: Post a new Bulletin Post
text: qsTr("post-new-bulletin-label")
}
TextField {
id: newposttitle
placeholderText: "Title.."
//: title place holder text
placeholderText: qsTr("title-placeholder")
Layout.fillWidth: true
style: CwtchTextFieldStyle{}
}

View File

@ -32,7 +32,7 @@ ColumnLayout {
txtMessage.text = ""
}
onAppendMessage: function(handle, from, displayName, message, image, mid, fromMe, ts, ackd) {
onAppendMessage: function(handle, from, displayName, message, image, mid, fromMe, ts, ackd, error) {
var msg
try {
msg = JSON.parse(message)
@ -52,6 +52,7 @@ ColumnLayout {
"_fromMe": fromMe,
"_ts": ts,
"_ackd": ackd,
"_error": error == true ? "this message failed to send" : "",
})
@ -93,6 +94,7 @@ ColumnLayout {
fromMe: _fromMe
timestamp: _ts
ackd: _ackd
error: _error
}
}
}

View File

@ -58,7 +58,7 @@ ColumnLayout {
jsonModel4.clear()
}
onAppendMessage: function(handle, from, displayName, message, image, mid, fromMe, ts) {
onAppendMessage: function(handle, from, displayName, message, image, mid, fromMe, ts, ack, error) {
var msg
try {
msg = JSON.parse(message)
@ -158,7 +158,8 @@ ColumnLayout {
}
GroupBox {
title: qsTr("Add a New List Item")
//: Add a New List Item
title: qsTr("add-list-item")
Layout.fillWidth: true
RowLayout {
@ -169,12 +170,14 @@ ColumnLayout {
Text {
text: "Add a new item to the list"
//: Add a new item to the list
text: qsTr("add-new-item")
}
TextField {
id: newposttitle
placeholderText: "Todo.."
//: Todo... placeholder text
placeholderText: qsTr("todo-placeholder")
Layout.fillWidth: true
style: CwtchTextFieldStyle{}
}

View File

@ -0,0 +1,105 @@
import QtGraphicalEffects 1.0
import QtQuick 2.7
import QtQuick.Controls 2.4
import QtQuick.Controls.Material 2.0
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.3
import "../widgets"
import "../widgets/controls" as Awesome
import "../fonts/Twemoji.js" as T
import "../utils.js" as Utils
import "../styles"
ColumnLayout {
Text {
wrapMode: Text.Wrap
Layout.maximumWidth: parent.width
horizontalAlignment: Text.AlignHCenter
padding: 1
//: 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.
text: qsTr("membership-description")
}
Flickable { // THE ACTUAL CONTACT LIST
id: sv
//Layout.alignment: Qt.AlignLeft | Qt.AlignTop
clip: true
Layout.minimumHeight: 100
//Layout.maximumHeight: parent.height - 30
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: sv.width
spacing: 0
Connections { // ADD/REMOVE CONTACT ENTRIES
target: gcd
onClearMessages: function() {
contactsModel.clear()
}
onAppendMessage: function(handle, from, displayName, message, image, mid, fromMe, ts, ack, error) {
var msg
try {
msg = JSON.parse(message)
} catch (e) {
return
}
if (from == "me") {
return
}
for(var i = 0; i<contactsModel.count;i++){
if(contactsModel.get(i)["_handle"] == handle) {
return
}
}
if (fromMe) {
contactsModel.append({
"_handle": handle,
"_displayName": "me",
"_image": image,
})
} else {
contactsModel.append({
"_handle": handle,
"_displayName": displayName == "" ? handle : displayName,
"_image": image,
})
}
}
}
ListModel { // CONTACT OBJECTS ARE STORED HERE ...
id: contactsModel
}
Repeater {
model: contactsModel // ... AND DISPLAYED HERE
delegate: ContactRow {
handle: _handle
displayName: _displayName
image: _image
trusted: true
background: false
}
}
}
}
}

View File

@ -14,7 +14,7 @@ ColumnLayout { // settingsPane
StackToolbar {
text: "Create a new group"
text: qsTr("create-group-title")
aux.visible: false
}
@ -23,7 +23,8 @@ ColumnLayout { // settingsPane
spacing: 5
ScalingLabel {
text: "Server:"
//: Server label
text: qsTr("server-label") + ":"
}
TextField {
@ -33,17 +34,20 @@ ColumnLayout { // settingsPane
}
ScalingLabel{
text: "Group name:"
//: Group name label
text: qsTr("group-name-label") + ":"
}
TextField {
id: txtGroupName
style: CwtchTextFieldStyle{ width: 400 }
text: "my awesome group"
//: default suggested group name
text: qsTr("default-group-name")
}
SimpleButton {
text: "create"
//: create group button
text: qsTr("create-group-btn")
onClicked: {
gcd.createGroup(txtServer.text, txtGroupName.text)

View File

@ -27,7 +27,7 @@ ColumnLayout { // groupSettingsPane
spacing: 5
ScalingLabel {
text: "Server:"
text: qsTr("server-label") + ":"
}
TextField {
@ -38,17 +38,17 @@ ColumnLayout { // groupSettingsPane
SimpleButton {
icon: "regular/clipboard"
text: "copy"
text: qsTr("copy-btn")
onClicked: {
gcd.popup("copied to clipboard!")
gcd.popup("copied-clipboard-notification")
txtServer.selectAll()
txtServer.copy()
}
}
ScalingLabel {
text: "Invitation:"
text: qsTr("invitation-label") + ":"
}
TextField {
@ -59,17 +59,17 @@ ColumnLayout { // groupSettingsPane
SimpleButton {
icon: "regular/clipboard"
text: "copy"
text: qsTr("copy-btn")
onClicked: {
gcd.popup("copied to clipboard!")
gcd.popup("copied-clipboard-notification")
txtInvitation.selectAll()
txtInvitation.copy()
}
}
ScalingLabel{
text: "Group name:"
text: qsTr("group-name-label") + ":"
}
TextField {
@ -78,7 +78,7 @@ ColumnLayout { // groupSettingsPane
}
SimpleButton {
text: "Save"
text: qsTr("save-btn")
onClicked: {
gcd.saveGroupSettings(groupID, txtGroupName.text)
@ -87,7 +87,8 @@ ColumnLayout { // groupSettingsPane
}
}
ScalingLabel { text: "Invite someone to the group:" }
//: Invite someone to the group
ScalingLabel { text: qsTr("invite-to-group-label") }
ComboBox {
id: cbInvite
@ -98,7 +99,7 @@ ColumnLayout { // groupSettingsPane
}
SimpleButton {
text: "Invite"
text: qsTr("invite-btn")
onClicked: {
gcd.inviteToGroup(addrbook[cbInvite.currentIndex], groupID)
@ -107,7 +108,7 @@ ColumnLayout { // groupSettingsPane
SimpleButton {
icon: "regular/trash-alt"
text: "delete"
text: qsTr("delete-btn")
onClicked: {
gcd.leaveGroup(groupID)

View File

@ -13,10 +13,15 @@ ColumnLayout {
id: overlay
property string name
property bool accepted
property bool inGroup
StackToolbar {
id: toolbar
//text: "open privacy exec"
membership.visible: gcd.currentOpenConversation.length == 32
membership.onClicked: overlayStack.overlay = overlayStack.membershipOverlay
aux.onClicked: {
if (gcd.currentOpenConversation.length == 32) {
@ -32,19 +37,26 @@ ColumnLayout {
RowLayout {
visible:!overlay.accepted && (gcd.currentOpenConversation.length == 32)
Text {
text: "Do you want to accept the invitation to " + overlay.name + "?"
//: Do you want to accept the invitation to $GROUP
text: qsTr("accept-group-invite-label") + " " + overlay.name + "?"
}
SimpleButton {
text: "Accept"
//: Accept group invite button
text: qsTr("accept-group-btn")
icon: "regular/heart"
onClicked: {
gcd.acceptGroup(gcd.currentOpenConversation)
gcd.requestGroupSettings(gcd.currentOpenConversation)
}
}
SimpleButton {
text: "Reject"
//: Reject Group invite button
text: qsTr("reject-group-btn")
icon: "regular/trash-alt"
onClicked: {
gcd.leaveGroup(gcd.currentOpenConversation)
@ -58,28 +70,28 @@ ColumnLayout {
SimpleButton {
text: "Chat"
text: qsTr("chat-btn")
onClicked: overlayStack.overlay = overlayStack.chatOverlay
}
SimpleButton {
text: "Lists"
text: qsTr("lists-btn")
onClicked: overlayStack.overlay = overlayStack.listOverlay
}
SimpleButton {
text: "Bulletins"
text: qsTr("bulletins-btn")
onClicked: overlayStack.overlay = overlayStack.bulletinOverlay
}
SimpleButton {
text: "Puzzle Game"
text: qsTr("puzzle-game-btn")
onClicked: overlayStack.overlay = overlayStack.game1Overlay
@ -93,6 +105,7 @@ ColumnLayout {
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.top: switcher.bottom
implicitHeight: height
currentIndex: 0
property alias overlay: overlayStack.currentIndex
@ -100,24 +113,48 @@ ColumnLayout {
readonly property int listOverlay: 1
readonly property int bulletinOverlay: 2
readonly property int game1Overlay: 3
readonly property int membershipOverlay: 4
ChatOverlay {} //0
ChatOverlay { //0
Layout.maximumHeight: overlayStack.height
Layout.maximumWidth: overlayStack.width
}
ListOverlay{} //1
ListOverlay{ //1
Layout.maximumHeight: overlayStack.height
Layout.maximumWidth: overlayStack.width
}
BulletinOverlay{} //2
BulletinOverlay{ //2
Layout.maximumHeight: overlayStack.height
Layout.maximumWidth: overlayStack.width
}
Game1Overlay{} //3
Game1Overlay{ //3
Layout.maximumHeight: overlayStack.height
Layout.maximumWidth: overlayStack.width
}
MembershipOverlay { //4
Layout.maximumHeight: overlayStack.height
Layout.maximumWidth: overlayStack.width
}
}
Connections {
target: gcd
Connections {
target: gcd
onSupplyGroupSettings: function(gid, name, server, invite, accepted, addrbooknames, addrbookaddrs) {
console.log("Supplied " + gid + " " + name + "Accepted " + accepted)
overlay.name = name
overlay.accepted = accepted
}
}
onResetMessagePane: function() {
overlayStack.overlay = overlayStack.chatOverlay
overlay.inGroup = false
}
onSupplyGroupSettings: function(gid, name, server, invite, accepted, addrbooknames, addrbookaddrs) {
console.log("Supplied " + gid + " " + name + "Accepted " + accepted)
overlay.name = name
overlay.accepted = accepted
overlay.inGroup = true
}
}
}

View File

@ -26,7 +26,7 @@ ColumnLayout { // peerSettingsPane
spacing: 5
ScalingLabel {
text: "Address:"
text: qsTr("address-label")
}
TextField {
@ -37,17 +37,18 @@ ColumnLayout { // peerSettingsPane
SimpleButton {
icon: "regular/clipboard"
text: "copy"
text: qsTr("copy-btn")
onClicked: {
gcd.popup("copied to clipboard!")
//: notification: copied to clipboard
gcd.popup(qsTr("copied-to-clipboard-notification"))
txtOnion.selectAll()
txtOnion.copy()
}
}
ScalingLabel{
text: "Display name:"
text: qsTr("display-name-label")
}
TextField {
@ -56,7 +57,7 @@ ColumnLayout { // peerSettingsPane
}
SimpleButton {
text: "Save"
text: qsTr("save-btn")
onClicked: {
gcd.savePeerSettings(txtOnion.text, txtDisplayName.text)
@ -67,7 +68,7 @@ ColumnLayout { // peerSettingsPane
SimpleButton {
icon: "regular/trash-alt"
text: "delete"
text: qsTr("delete-btn")
onClicked: {
gcd.setAttribute(txtOnion.text, "deleted", "deleted")

View File

@ -13,7 +13,8 @@ ColumnLayout { // settingsPane
StackToolbar {
text: "Cwtch Settings"
//: Cwtch Settings title
text: qsTr("cwtch-settings-title")
aux.visible: false
}
@ -23,7 +24,8 @@ ColumnLayout { // settingsPane
ScalingLabel {
Layout.maximumWidth: parent.width
text: "Interface zoom (mostly affects text and button sizes):"
//: Interface zoom (mostly affects text and button sizes)
text: qsTr("zoom-label") + ":"
}
Slider {
@ -39,16 +41,17 @@ ColumnLayout { // settingsPane
}
ScalingLabel {
text: "Large text"
text: qsTr("large-text-label")
size: 20
}
ScalingLabel{
text: "Default size text (scale factor: " + zoomSlider.value + ")"
//: "Default size text (scale factor: "
text: qsTr("default-scaling-text") + zoomSlider.value + ")"
}
ScalingLabel {
text: "Small text"
text: qsTr("small-text-label")
size: 8
}

View File

@ -16,55 +16,66 @@ Item {
property int status
property bool isGroup
property bool showStatus
property bool highlight
Rectangle {
id: mainImage
width: 48
height: 48
color: "#FFFFFF"
color: highlight ? windowItem.cwtch_dark_color: "#FFFFFF"
radius: width / 2
Rectangle {
width: highlight ? 44 : 48
height: highlight ? 44 : 48
color: "#FFFFFF"
radius: width / 2
anchors.centerIn:parent
Image { // PROFILE IMAGE
id: img
anchors.fill: parent
fillMode: Image.PreserveAspectFit
visible: false
}
Image { // CIRCLE MASK
id: mask
fillMode: Image.PreserveAspectFit
visible: false
source: "qrc:/qml/images/extra/clipcircle.png"
}
Image { // PROFILE IMAGE
id: img
anchors.fill: parent
fillMode: Image.PreserveAspectFit
visible: false
}
Image { // CIRCLE MASK
id: mask
fillMode: Image.PreserveAspectFit
visible: false
source: "qrc:/qml/images/extra/clipcircle.png"
}
OpacityMask {
anchors.fill: img
source: img
maskSource: mask
}
OpacityMask {
anchors.fill: img
source: img
maskSource: mask
}
Rectangle { // PRESENCE INDICATOR
visible: showStatus
color: "#FFFFFF"
width: 8
height: 8
radius: 2
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: 4
visible: showStatus
color: "#FFFFFF"
width: 8
height: 8
radius: 2
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: 4
Rectangle { //-2:WtfCodeError,-1:Untrusted,0:Disconnected,1:Connecting,2:Connected,3:Authenticated,4:Failed,5:Killed
color: status == 3 ? "green" : status == -1 ? "blue" : status == 1 ? "orange" : status == 2 ? "orange" : "red"
width: 5
height: 5
radius: 2
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: 1.5
}
}
Rectangle { //-2:WtfCodeError,-1:Untrusted,0:Disconnected,1:Connecting,2:Connected,3:Authenticated,4:Failed,5:Killed
color: status == 3 ? "green" : status == -1 ? "blue" : status == 1 ? "orange" : status == 2 ? "orange" : "red"
width: 5
height: 5
radius: 2
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: 1.5
}
}
}
}

View File

@ -20,6 +20,7 @@ RowLayout { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
property bool deleted
property alias status: imgProfile.status
property string server
property bool background: true
Rectangle { // CONTACT ENTRY BACKGROUND COLOR
@ -28,7 +29,7 @@ RowLayout { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
anchors.right: parent.right
height: childrenRect.height + 3
width: parent.width
color: isHover ? "#D2D2F3" : (isActive ? "#D2D2F3" : "#D2C0DD")
color: background ? (isHover ? "#D2D2F3" : (isActive ? "#D2D2F3" : "#D2C0DD")) : windowItem.cwtch_background_color
RowLayout {

View File

@ -35,12 +35,10 @@ RowLayout {
}
onGroupSendError: function(mid, error) {
console.log("Error " + mid + " " + messageID)
if (mid == messageID) {
root.error = error
}
}
}
@ -50,9 +48,18 @@ RowLayout {
handle: root.from
visible: !fromMe
showStatus: false
highlight: ima.containsMouse
ToolTip.visible: ima.containsMouse
//: Click to DM
ToolTip.text: qsTr("dm-tooltip")
MouseArea {
id: ima
anchors.fill: parent
hoverEnabled: overlay.inGroup
onClicked: {
gcd.broadcast("ResetMessagePane")
theStack.pane = theStack.messagePane
@ -143,7 +150,8 @@ RowLayout {
sourceSize.height: 10
visible: fromMe
ToolTip.visible: ma.containsMouse
ToolTip.text: root.error != "" ? qsTr("Could not send this message: ") + qsTr(root.error) : (root.ackd ? qsTr("Acknowledged") : qsTr("Pending"))
//: Could not send this message
ToolTip.text: root.error != "" ? qsTr("could-not-send-msg-error") + ":" + root.error : (root.ackd ? qsTr("acknowledged-label") : qsTr("pending-label"))
MouseArea {
id: ma
anchors.fill: parent

View File

@ -165,10 +165,12 @@ ColumnLayout {
SimpleButton { // COPY ONION ADDRESS BUTTON
icon: "regular/clipboard"
text: "copy"
//: Button for copying profile onion address to clipboard
text: qsTr("copy-btn")
onClicked: {
gcd.popup("copied to clipboard!")
//: Copied to clipboard
gcd.popup(qsTr("copied-clipboard-notification"))
txtHidden.text = nick.replace(" ", "~") + "~" + onion
txtHidden.selectAll()
txtHidden.copy()
@ -197,7 +199,8 @@ ColumnLayout {
SimpleButton { // CREATE GROUP BUTTON
icon: "regular/clipboard"
text: "new group"
//: create new group button
text: qsTr("new-group-btn")
onClicked: theStack.pane = theStack.addGroupPane
}
@ -206,7 +209,8 @@ ColumnLayout {
TextField {
anchors.horizontalCenter: parent.horizontalCenter
style: CwtchTextFieldStyle{ width: 400 }
placeholderText: "... paste an address here to add a contact ..."
//: ex: "... paste an address here to add a contact ..."
placeholderText: qsTr("paste-address-to-add-contact")
horizontalAlignment: TextInput.AlignHCenter
onTextChanged: {

View File

@ -26,6 +26,7 @@ Rectangle {
property alias font: buttonText.font.family
property string icon
property bool mousedown
property string tooltip
signal clicked
@ -48,6 +49,9 @@ Rectangle {
anchors.leftMargin: 6
visible: button.text != "" && button.text != undefined
}
ToolTip.visible: tooltip != "" && mouseArea.containsMouse
ToolTip.text: tooltip
}
@ -63,6 +67,8 @@ Rectangle {
onPressed: mousedown = true
onReleased: mousedown = false
hoverEnabled: true
}
Keys.onSpacePressed: clicked()

View File

@ -20,6 +20,7 @@ Rectangle { // OVERHEAD BAR ON STACK PANE
property alias text: lbl.text
property alias aux: btnAux
property alias back: btnBack
property alias membership: btnMembership
SimpleButton {// BACK BUTTON
@ -38,11 +39,21 @@ Rectangle { // OVERHEAD BAR ON STACK PANE
anchors.verticalCenter: parent.verticalCenter
}
SimpleButton { // COG BUTTON
id: btnAux
anchors.verticalCenter: parent.verticalCenter
RowLayout {
anchors.right: parent.right
anchors.rightMargin: 6
icon: "solid/cog"
anchors.verticalCenter: parent.verticalCenter
SimpleButton { // Membership Button
id: btnMembership
icon: "solid/users"
tooltip: "View Group Membership"
}
SimpleButton { // COG BUTTON
id: btnAux
icon: "solid/cog"
}
}
}

32
ui.pro Normal file
View File

@ -0,0 +1,32 @@
QT += quick
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.go
RESOURCES += qml.qrc
TRANSLATIONS = i18n/translation_en.ts \
i18n/translation_de.ts
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target