profile manager: screen, unlock, select, back to #238
|
@ -3,3 +3,4 @@ package constants
|
||||||
const Nick = "nick"
|
const Nick = "nick"
|
||||||
const LastRead = "last-read"
|
const LastRead = "last-read"
|
||||||
const Picture = "picture"
|
const Picture = "picture"
|
||||||
|
const DefaultPassword = "default-password"
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func App(gcd *ui.GrandCentralDispatcher, subscribed chan bool) {
|
func App(gcd *ui.GrandCentralDispatcher, subscribed chan bool, reloadingFirst bool) {
|
||||||
q := event.NewQueue()
|
q := event.NewQueue()
|
||||||
the.AppBus.Subscribe(event.NewPeer, q)
|
the.AppBus.Subscribe(event.NewPeer, q)
|
||||||
the.AppBus.Subscribe(event.PeerError, q)
|
the.AppBus.Subscribe(event.PeerError, q)
|
||||||
|
@ -21,9 +21,12 @@ func App(gcd *ui.GrandCentralDispatcher, subscribed chan bool) {
|
||||||
the.AppBus.Subscribe(event.NetworkStatus, q)
|
the.AppBus.Subscribe(event.NetworkStatus, q)
|
||||||
the.AppBus.Subscribe(event.ReloadDone, q)
|
the.AppBus.Subscribe(event.ReloadDone, q)
|
||||||
subscribed <- true
|
subscribed <- true
|
||||||
|
loadingV1Accounts := !reloadingFirst
|
||||||
|
|
||||||
networkOffline := false
|
networkOffline := false
|
||||||
timeSinceLastSuccess := time.Unix(0,0)
|
timeSinceLastSuccess := time.Unix(0, 0)
|
||||||
|
|
||||||
|
gcd.Loaded()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
e := q.Next()
|
e := q.Next()
|
||||||
|
@ -74,65 +77,54 @@ func App(gcd *ui.GrandCentralDispatcher, subscribed chan bool) {
|
||||||
case event.AppError:
|
case event.AppError:
|
||||||
|
|
||||||
if e.Data[event.Error] == event.AppErrLoaded0 {
|
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")
|
if loadingV1Accounts {
|
||||||
if gcd.Version() == "development" {
|
loadingV1Accounts = false
|
||||||
the.CwtchApp.CreatePeer("tester", the.AppPassword)
|
// TODO: only an error if other profiles are not loaded
|
||||||
|
if len(the.CwtchApp.ListPeers()) == 0 {
|
||||||
|
log.Infoln("couldn't load your config file. attempting to create one now")
|
||||||
|
if gcd.Version() == "development" {
|
||||||
|
the.CwtchApp.CreatePeer("tester", the.AppPassword)
|
||||||
|
} else {
|
||||||
|
the.CwtchApp.CreatePeer("alice", the.AppPassword)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
the.CwtchApp.CreatePeer("alice", the.AppPassword)
|
gcd.ErrorLoaded0()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case event.ReloadDone:
|
case event.ReloadDone:
|
||||||
if the.Peer == nil {
|
if the.Peer == nil {
|
||||||
|
loadingV1Accounts = true
|
||||||
the.CwtchApp.LoadProfiles(the.AppPassword)
|
the.CwtchApp.LoadProfiles(the.AppPassword)
|
||||||
}
|
}
|
||||||
case event.NewPeer:
|
case event.NewPeer:
|
||||||
if the.Peer != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
onion := e.Data[event.Identity]
|
onion := e.Data[event.Identity]
|
||||||
|
peer := the.CwtchApp.GetPeer(onion)
|
||||||
|
|
||||||
|
if loadingV1Accounts {
|
||||||
|
the.CwtchApp.GetPeer(onion).SetAttribute(constants.DefaultPassword, "true")
|
||||||
|
loadingV1Accounts = false
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("NewPeer for %v\n", onion)
|
||||||
|
gcd.UIManager.AddProfile(onion)
|
||||||
|
|
||||||
the.CwtchApp.AddPeerPlugin(onion, plugins.CONNECTIONRETRY)
|
the.CwtchApp.AddPeerPlugin(onion, plugins.CONNECTIONRETRY)
|
||||||
the.CwtchApp.AddPeerPlugin(onion, plugins.NETWORKCHECK)
|
the.CwtchApp.AddPeerPlugin(onion, plugins.NETWORKCHECK)
|
||||||
|
|
||||||
the.Peer = the.CwtchApp.GetPeer(onion)
|
|
||||||
the.EventBus = the.CwtchApp.GetEventBus(onion)
|
|
||||||
|
|
||||||
incSubscribed := make(chan bool)
|
incSubscribed := make(chan bool)
|
||||||
go PeerHandler(&gcd.UIManager, incSubscribed)
|
go PeerHandler(onion, &gcd.UIManager, incSubscribed)
|
||||||
<-incSubscribed
|
<-incSubscribed
|
||||||
|
|
||||||
pic, exists := the.Peer.GetAttribute(constants.Picture)
|
|
||||||
if !exists {
|
|
||||||
pic = ui.RandomProfileImage(the.Peer.GetProfile().Onion)
|
|
||||||
the.Peer.SetAttribute(constants.Picture, pic)
|
|
||||||
}
|
|
||||||
gcd.UpdateMyProfile(the.Peer.GetProfile().Name, the.Peer.GetProfile().Onion, pic)
|
|
||||||
|
|
||||||
contacts := the.Peer.GetContacts()
|
|
||||||
for i := range contacts {
|
|
||||||
gcd.UIManager.AddContact(contacts[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
groups := the.Peer.GetGroups()
|
|
||||||
for i := range groups {
|
|
||||||
// Only join servers for active and explicitly accepted groups.
|
|
||||||
gcd.UIManager.AddContact(groups[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.Data[event.Status] != "running" {
|
if e.Data[event.Status] != "running" {
|
||||||
the.CwtchApp.LaunchPeers()
|
peer.Listen()
|
||||||
|
peer.StartPeersConnections()
|
||||||
|
peer.StartGroupConnections()
|
||||||
}
|
}
|
||||||
|
|
||||||
// load ui preferences
|
blockUnkownPeers, exists := peer.GetProfile().GetAttribute(constants.BlockUnknownPeersSetting)
|
||||||
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" {
|
if exists && blockUnkownPeers == "true" {
|
||||||
the.EventBus.Publish(event.NewEvent(event.BlockUnknownPeers, map[event.Field]string{}))
|
the.EventBus.Publish(event.NewEvent(event.BlockUnknownPeers, map[event.Field]string{}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,18 +9,20 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PeerHandler(uiManager *ui.Manager, subscribed chan bool) {
|
func PeerHandler(onion string, uiManager *ui.Manager, subscribed chan bool) {
|
||||||
|
peer := the.CwtchApp.GetPeer(onion)
|
||||||
|
eventBus := the.CwtchApp.GetEventBus(onion)
|
||||||
q := event.NewQueue()
|
q := event.NewQueue()
|
||||||
the.EventBus.Subscribe(event.NewMessageFromPeer, q)
|
eventBus.Subscribe(event.NewMessageFromPeer, q)
|
||||||
the.EventBus.Subscribe(event.PeerAcknowledgement, q)
|
eventBus.Subscribe(event.PeerAcknowledgement, q)
|
||||||
the.EventBus.Subscribe(event.NewMessageFromGroup, q)
|
eventBus.Subscribe(event.NewMessageFromGroup, q)
|
||||||
the.EventBus.Subscribe(event.NewGroupInvite, q)
|
eventBus.Subscribe(event.NewGroupInvite, q)
|
||||||
the.EventBus.Subscribe(event.SendMessageToGroupError, q)
|
eventBus.Subscribe(event.SendMessageToGroupError, q)
|
||||||
the.EventBus.Subscribe(event.SendMessageToPeerError, q)
|
eventBus.Subscribe(event.SendMessageToPeerError, q)
|
||||||
the.EventBus.Subscribe(event.ServerStateChange, q)
|
eventBus.Subscribe(event.ServerStateChange, q)
|
||||||
the.EventBus.Subscribe(event.PeerStateChange, q)
|
eventBus.Subscribe(event.PeerStateChange, q)
|
||||||
the.EventBus.Subscribe(event.PeerCreated, q)
|
eventBus.Subscribe(event.PeerCreated, q)
|
||||||
the.EventBus.Subscribe(event.NetworkStatus, q)
|
eventBus.Subscribe(event.NetworkStatus, q)
|
||||||
|
|
||||||
subscribed <- true
|
subscribed <- true
|
||||||
|
|
||||||
|
@ -43,8 +45,8 @@ func PeerHandler(uiManager *ui.Manager, subscribed chan bool) {
|
||||||
case event.NewMessageFromPeer: //event.TimestampReceived, event.RemotePeer, event.Data
|
case event.NewMessageFromPeer: //event.TimestampReceived, event.RemotePeer, event.Data
|
||||||
ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampReceived])
|
ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampReceived])
|
||||||
uiManager.AddMessage(e.Data[event.RemotePeer], e.Data[event.RemotePeer], e.Data[event.Data], false, e.EventID, ts, true)
|
uiManager.AddMessage(e.Data[event.RemotePeer], e.Data[event.RemotePeer], e.Data[event.Data], false, e.EventID, ts, true)
|
||||||
if the.Peer.GetContact(e.Data[event.RemotePeer]) == nil {
|
if peer.GetContact(e.Data[event.RemotePeer]) == nil {
|
||||||
the.Peer.AddContact(e.Data[event.RemotePeer], e.Data[event.RemotePeer], false)
|
peer.AddContact(e.Data[event.RemotePeer], e.Data[event.RemotePeer], false)
|
||||||
}
|
}
|
||||||
|
|
||||||
case event.PeerAcknowledgement:
|
case event.PeerAcknowledgement:
|
||||||
|
@ -52,10 +54,10 @@ func PeerHandler(uiManager *ui.Manager, subscribed chan bool) {
|
||||||
|
|
||||||
case event.NewMessageFromGroup: //event.TimestampReceived, event.TimestampSent, event.Data, event.GroupID, event.RemotePeer
|
case event.NewMessageFromGroup: //event.TimestampReceived, event.TimestampSent, event.Data, event.GroupID, event.RemotePeer
|
||||||
ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampSent])
|
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] == the.Peer.GetProfile().Onion, e.Data[event.Signature], ts, true)
|
uiManager.AddMessage(e.Data[event.GroupID], e.Data[event.RemotePeer], e.Data[event.Data], e.Data[event.RemotePeer] == peer.GetProfile().Onion, e.Data[event.Signature], ts, true)
|
||||||
case event.NewGroupInvite:
|
case event.NewGroupInvite:
|
||||||
gid, err := the.Peer.GetProfile().ProcessInvite(e.Data[event.GroupInvite], e.Data[event.RemotePeer])
|
gid, err := peer.GetProfile().ProcessInvite(e.Data[event.GroupInvite], e.Data[event.RemotePeer])
|
||||||
group := the.Peer.GetGroup(gid)
|
group := peer.GetGroup(gid)
|
||||||
if err == nil && group != nil {
|
if err == nil && group != nil {
|
||||||
uiManager.AddContact(gid)
|
uiManager.AddContact(gid)
|
||||||
}
|
}
|
||||||
|
@ -70,18 +72,18 @@ func PeerHandler(uiManager *ui.Manager, subscribed chan bool) {
|
||||||
cxnState := connections.ConnectionStateToType[e.Data[event.ConnectionState]]
|
cxnState := connections.ConnectionStateToType[e.Data[event.ConnectionState]]
|
||||||
|
|
||||||
// if it's not in the.PeerHandler it's new. Only add once Authed
|
// if it's not in the.PeerHandler it's new. Only add once Authed
|
||||||
if _, exists := the.Peer.GetProfile().Contacts[e.Data[event.RemotePeer]]; !exists {
|
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
|
// 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
|
// So if we get any other state from an unknown contact we do nothing
|
||||||
// (the next exists check will fail)
|
// (the next exists check will fail)
|
||||||
if cxnState == connections.AUTHENTICATED {
|
if cxnState == connections.AUTHENTICATED {
|
||||||
the.Peer.AddContact(e.Data[event.RemotePeer], e.Data[event.RemotePeer], false)
|
peer.AddContact(e.Data[event.RemotePeer], e.Data[event.RemotePeer], false)
|
||||||
uiManager.AddContact(e.Data[event.RemotePeer])
|
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 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 := the.Peer.GetProfile().Contacts[e.Data[event.RemotePeer]]; exists {
|
if contact, exists := peer.GetProfile().Contacts[e.Data[event.RemotePeer]]; exists {
|
||||||
contact.State = e.Data[event.ConnectionState]
|
contact.State = e.Data[event.ConnectionState]
|
||||||
uiManager.UpdateContactStatus(contact.Onion, int(cxnState), false)
|
uiManager.UpdateContactStatus(contact.Onion, int(cxnState), false)
|
||||||
|
|
||||||
|
@ -89,9 +91,9 @@ func PeerHandler(uiManager *ui.Manager, subscribed chan bool) {
|
||||||
case event.ServerStateChange:
|
case event.ServerStateChange:
|
||||||
serverOnion := e.Data[event.GroupServer]
|
serverOnion := e.Data[event.GroupServer]
|
||||||
state := connections.ConnectionStateToType[e.Data[event.ConnectionState]]
|
state := connections.ConnectionStateToType[e.Data[event.ConnectionState]]
|
||||||
groups := the.Peer.GetGroups()
|
groups := peer.GetGroups()
|
||||||
for _, groupID := range groups {
|
for _, groupID := range groups {
|
||||||
group := the.Peer.GetGroup(groupID)
|
group := peer.GetGroup(groupID)
|
||||||
if group != nil && group.GroupServer == serverOnion {
|
if group != nil && group.GroupServer == serverOnion {
|
||||||
group.State = e.Data[event.ConnectionState]
|
group.State = e.Data[event.ConnectionState]
|
||||||
loading := false
|
loading := false
|
||||||
|
|
44
go/ui/gcd.go
44
go/ui/gcd.go
|
@ -27,6 +27,12 @@ type GrandCentralDispatcher struct {
|
||||||
_ string `property:"version"`
|
_ string `property:"version"`
|
||||||
_ string `property:"buildDate"`
|
_ string `property:"buildDate"`
|
||||||
|
|
||||||
|
// profile management stuff
|
||||||
|
_ func() `signal:"Loaded"`
|
||||||
|
_ func(handle, displayname, image string) `signal:"AddProfile"`
|
||||||
|
_ func() `signal:"ErrorLoaded0"`
|
||||||
|
_ func() `signal:"ResetProfile"`
|
||||||
|
|
||||||
// contact list stuff
|
// contact list stuff
|
||||||
_ 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, blocked bool, loading bool, lastMsgTime int) `signal:"AddContact"`
|
||||||
_ func(handle, displayName string) `signal:"UpdateContactDisplayName"`
|
_ func(handle, displayName string) `signal:"UpdateContactDisplayName"`
|
||||||
|
@ -82,6 +88,8 @@ type GrandCentralDispatcher struct {
|
||||||
_ func() `signal:"allowUnknownPeers,auto"`
|
_ func() `signal:"allowUnknownPeers,auto"`
|
||||||
_ func() `signal:"blockUnknownPeers,auto"`
|
_ func() `signal:"blockUnknownPeers,auto"`
|
||||||
_ func() `signal:"onActivate,auto"`
|
_ func() `signal:"onActivate,auto"`
|
||||||
|
_ func(password string) `signal:"unlockProfiles,auto"`
|
||||||
|
_ func(handle string) `signal:"loadProfile,auto"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *GrandCentralDispatcher) sendMessage(message string, mID string) {
|
func (this *GrandCentralDispatcher) sendMessage(message string, mID string) {
|
||||||
|
@ -295,6 +303,8 @@ 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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,3 +487,37 @@ 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.UIManager.AddContact(contacts[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
groups := the.Peer.GetGroups()
|
||||||
|
for i := range groups {
|
||||||
|
// Only join servers for active and explicitly accepted groups.
|
||||||
|
this.UIManager.AddContact(groups[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// load ui preferences
|
||||||
|
this.RequestSettings()
|
||||||
|
locale, exists := the.Peer.GetProfile().GetAttribute(constants.LocaleSetting)
|
||||||
|
if exists {
|
||||||
|
this.SetLocale_helper(locale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -98,7 +98,7 @@ func updateLastReadTime(id string) {
|
||||||
func countUnread(messages []model.Message, lastRead time.Time) int {
|
func countUnread(messages []model.Message, lastRead time.Time) int {
|
||||||
count := 0
|
count := 0
|
||||||
for i := len(messages) - 1; i >= 0; i-- {
|
for i := len(messages) - 1; i >= 0; i-- {
|
||||||
if messages[i].Timestamp.After(lastRead) {
|
if messages[i].Timestamp.After(lastRead) || messages[i].Timestamp.Equal(lastRead) {
|
||||||
count++
|
count++
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
|
@ -115,6 +115,25 @@ func NewManager(gcd *GrandCentralDispatcher) Manager {
|
||||||
return Manager{gcd}
|
return Manager{gcd}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *Manager) AddProfile(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)
|
||||||
|
}
|
||||||
|
log.Infof("AddProfile %v %v %v\n", handle, nick, pic)
|
||||||
|
this.gcd.AddProfile(handle, nick, pic)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (this *Manager) Acknowledge(mID string) {
|
func (this *Manager) Acknowledge(mID string) {
|
||||||
this.gcd.Acknowledged(mID)
|
this.gcd.Acknowledged(mID)
|
||||||
}
|
}
|
||||||
|
@ -170,13 +189,12 @@ func (this *Manager) AddSendMessageError(peer string, signature string, err stri
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *Manager) AddMessage(handle string, from string, message string, fromMe bool, messageID string, timestamp time.Time, Acknowledged bool) {
|
func (this *Manager) AddMessage(handle string, from string, message string, fromMe bool, messageID string, timestamp time.Time, Acknowledged bool) {
|
||||||
updateLastReadTime(handle)
|
|
||||||
|
|
||||||
nick := getOrDefault(handle, constants.Nick, handle)
|
nick := getOrDefault(handle, constants.Nick, handle)
|
||||||
image := getProfilePic(handle)
|
image := getProfilePic(handle)
|
||||||
|
|
||||||
// If we have this group loaded already
|
// If we have this group loaded already
|
||||||
if this.gcd.CurrentOpenConversation() == handle {
|
if this.gcd.CurrentOpenConversation() == handle {
|
||||||
|
updateLastReadTime(handle)
|
||||||
// If the message is not from the user then add it, otherwise, just acknowledge.
|
// If the message is not from the user then add it, otherwise, just acknowledge.
|
||||||
if !fromMe {
|
if !fromMe {
|
||||||
this.gcd.AppendMessage(handle, from, nick, message, image, messageID, fromMe, timestamp.Format(constants.TIME_FORMAT), false, false)
|
this.gcd.AppendMessage(handle, from, nick, message, image, messageID, fromMe, timestamp.Format(constants.TIME_FORMAT), false, false)
|
||||||
|
@ -187,9 +205,8 @@ func (this *Manager) AddMessage(handle string, from string, message string, from
|
||||||
this.gcd.Acknowledged(messageID)
|
this.gcd.Acknowledged(messageID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
this.gcd.IncContactUnreadCount(handle)
|
|
||||||
}
|
}
|
||||||
|
this.gcd.IncContactUnreadCount(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *Manager) UpdateContactDisplayName(handle string, name string) {
|
func (this *Manager) UpdateContactDisplayName(handle string, name string) {
|
||||||
|
|
|
@ -145,18 +145,18 @@
|
||||||
<translation>Klicken, um DM zu senden</translation>
|
<translation>Klicken, um DM zu senden</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="161"/>
|
<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>Nachricht konnte nicht gesendet werden</translation>
|
<translation>Nachricht konnte nicht gesendet werden</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="161"/>
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>acknowledged-label</source>
|
<source>acknowledged-label</source>
|
||||||
<translation>bestätigt</translation>
|
<translation>bestätigt</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="161"/>
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>pending-label</source>
|
<source>pending-label</source>
|
||||||
<translation>Bestätigung ausstehend</translation>
|
<translation>Bestätigung ausstehend</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -164,25 +164,25 @@
|
||||||
<context>
|
<context>
|
||||||
<name>MyProfile</name>
|
<name>MyProfile</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/MyProfile.qml" line="169"/>
|
<location filename="../qml/widgets/MyProfile.qml" line="183"/>
|
||||||
<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>Kopieren</translation>
|
<translation>Kopieren</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/MyProfile.qml" line="173"/>
|
<location filename="../qml/widgets/MyProfile.qml" line="187"/>
|
||||||
<source>copied-clipboard-notification</source>
|
<source>copied-clipboard-notification</source>
|
||||||
<extracomment>Copied to clipboard</extracomment>
|
<extracomment>Copied to clipboard</extracomment>
|
||||||
<translation>in die Zwischenablage kopiert</translation>
|
<translation>in die Zwischenablage kopiert</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/MyProfile.qml" line="203"/>
|
<location filename="../qml/widgets/MyProfile.qml" line="217"/>
|
||||||
<source>new-group-btn</source>
|
<source>new-group-btn</source>
|
||||||
<extracomment>create new group button</extracomment>
|
<extracomment>create new group button</extracomment>
|
||||||
<translation>Neue Gruppe anlegen</translation>
|
<translation>Neue Gruppe anlegen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/MyProfile.qml" line="213"/>
|
<location filename="../qml/widgets/MyProfile.qml" line="227"/>
|
||||||
<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>Adresse hier hinzufügen, um einen Kontakt aufzunehmen</translation>
|
<translation>Adresse hier hinzufügen, um einen Kontakt aufzunehmen</translation>
|
||||||
|
@ -273,6 +273,27 @@
|
||||||
<translation>löschen</translation>
|
<translation>löschen</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</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="41"/>
|
||||||
|
<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="51"/>
|
||||||
|
<source>unlock</source>
|
||||||
|
<extracomment>Unlock</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>SettingsPane</name>
|
<name>SettingsPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
Binary file not shown.
|
@ -103,7 +103,7 @@
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/InplaceEditText.qml" line="85"/>
|
<location filename="../qml/widgets/InplaceEditText.qml" line="85"/>
|
||||||
<source>Update</source>
|
<source>Update</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation>Update</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
@ -145,18 +145,18 @@
|
||||||
<translation>Click to DM</translation>
|
<translation>Click to DM</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="161"/>
|
<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>Could not send this message</translation>
|
<translation>Could not send this message</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="161"/>
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>acknowledged-label</source>
|
<source>acknowledged-label</source>
|
||||||
<translation>Acknowledged</translation>
|
<translation>Acknowledged</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="161"/>
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>pending-label</source>
|
<source>pending-label</source>
|
||||||
<translation>Pending</translation>
|
<translation>Pending</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -164,25 +164,25 @@
|
||||||
<context>
|
<context>
|
||||||
<name>MyProfile</name>
|
<name>MyProfile</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/MyProfile.qml" line="169"/>
|
<location filename="../qml/widgets/MyProfile.qml" line="183"/>
|
||||||
<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>Copy</translation>
|
<translation>Copy</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/MyProfile.qml" line="173"/>
|
<location filename="../qml/widgets/MyProfile.qml" line="187"/>
|
||||||
<source>copied-clipboard-notification</source>
|
<source>copied-clipboard-notification</source>
|
||||||
<extracomment>Copied to clipboard</extracomment>
|
<extracomment>Copied to clipboard</extracomment>
|
||||||
<translation>Copied to clipboard</translation>
|
<translation>Copied to clipboard</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/MyProfile.qml" line="203"/>
|
<location filename="../qml/widgets/MyProfile.qml" line="217"/>
|
||||||
<source>new-group-btn</source>
|
<source>new-group-btn</source>
|
||||||
<extracomment>create new group button</extracomment>
|
<extracomment>create new group button</extracomment>
|
||||||
<translation>Create new group</translation>
|
<translation>Create new group</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/MyProfile.qml" line="213"/>
|
<location filename="../qml/widgets/MyProfile.qml" line="227"/>
|
||||||
<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>... paste an address here to add a contact...</translation>
|
<translation>... paste an address here to add a contact...</translation>
|
||||||
|
@ -273,6 +273,27 @@
|
||||||
<translation>Delete</translation>
|
<translation>Delete</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</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="41"/>
|
||||||
|
<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="51"/>
|
||||||
|
<source>unlock</source>
|
||||||
|
<extracomment>Unlock</extracomment>
|
||||||
|
<translation>Unlock</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>SettingsPane</name>
|
<name>SettingsPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -145,18 +145,18 @@
|
||||||
<translation>Envoyer un message privé</translation>
|
<translation>Envoyer un message privé</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="161"/>
|
<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>Impossible d'envoyer ce message</translation>
|
<translation>Impossible d'envoyer ce message</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="161"/>
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>acknowledged-label</source>
|
<source>acknowledged-label</source>
|
||||||
<translation>Confirmé</translation>
|
<translation>Confirmé</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="161"/>
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>pending-label</source>
|
<source>pending-label</source>
|
||||||
<translation>En attente</translation>
|
<translation>En attente</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -164,25 +164,25 @@
|
||||||
<context>
|
<context>
|
||||||
<name>MyProfile</name>
|
<name>MyProfile</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/MyProfile.qml" line="169"/>
|
<location filename="../qml/widgets/MyProfile.qml" line="183"/>
|
||||||
<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>Copier</translation>
|
<translation>Copier</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/MyProfile.qml" line="173"/>
|
<location filename="../qml/widgets/MyProfile.qml" line="187"/>
|
||||||
<source>copied-clipboard-notification</source>
|
<source>copied-clipboard-notification</source>
|
||||||
<extracomment>Copied to clipboard</extracomment>
|
<extracomment>Copied to clipboard</extracomment>
|
||||||
<translation>Copié dans le presse-papier</translation>
|
<translation>Copié dans le presse-papier</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/MyProfile.qml" line="203"/>
|
<location filename="../qml/widgets/MyProfile.qml" line="217"/>
|
||||||
<source>new-group-btn</source>
|
<source>new-group-btn</source>
|
||||||
<extracomment>create new group button</extracomment>
|
<extracomment>create new group button</extracomment>
|
||||||
<translation>Créer un nouveau groupe</translation>
|
<translation>Créer un nouveau groupe</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/MyProfile.qml" line="213"/>
|
<location filename="../qml/widgets/MyProfile.qml" line="227"/>
|
||||||
<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>... coller une adresse ici pour ajouter un contact...</translation>
|
<translation>... coller une adresse ici pour ajouter un contact...</translation>
|
||||||
|
@ -273,6 +273,27 @@
|
||||||
<translation>Effacer</translation>
|
<translation>Effacer</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</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="41"/>
|
||||||
|
<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="51"/>
|
||||||
|
<source>unlock</source>
|
||||||
|
<extracomment>Unlock</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>SettingsPane</name>
|
<name>SettingsPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -145,18 +145,18 @@
|
||||||
<translation>Clique para DM</translation>
|
<translation>Clique para DM</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="161"/>
|
<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>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="161"/>
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>acknowledged-label</source>
|
<source>acknowledged-label</source>
|
||||||
<translation>Confirmada</translation>
|
<translation>Confirmada</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/Message.qml" line="161"/>
|
<location filename="../qml/widgets/Message.qml" line="162"/>
|
||||||
<source>pending-label</source>
|
<source>pending-label</source>
|
||||||
<translation>Pendente</translation>
|
<translation>Pendente</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -164,25 +164,25 @@
|
||||||
<context>
|
<context>
|
||||||
<name>MyProfile</name>
|
<name>MyProfile</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/MyProfile.qml" line="169"/>
|
<location filename="../qml/widgets/MyProfile.qml" line="183"/>
|
||||||
<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>Copiar</translation>
|
<translation>Copiar</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/MyProfile.qml" line="173"/>
|
<location filename="../qml/widgets/MyProfile.qml" line="187"/>
|
||||||
<source>copied-clipboard-notification</source>
|
<source>copied-clipboard-notification</source>
|
||||||
<extracomment>Copied to clipboard</extracomment>
|
<extracomment>Copied to clipboard</extracomment>
|
||||||
<translation>Copiado</translation>
|
<translation>Copiado</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/MyProfile.qml" line="203"/>
|
<location filename="../qml/widgets/MyProfile.qml" line="217"/>
|
||||||
<source>new-group-btn</source>
|
<source>new-group-btn</source>
|
||||||
<extracomment>create new group button</extracomment>
|
<extracomment>create new group button</extracomment>
|
||||||
<translation>Criar novo grupo</translation>
|
<translation>Criar novo grupo</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../qml/widgets/MyProfile.qml" line="213"/>
|
<location filename="../qml/widgets/MyProfile.qml" line="227"/>
|
||||||
<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>… cole um endereço aqui para adicionar um contato…</translation>
|
<translation>… cole um endereço aqui para adicionar um contato…</translation>
|
||||||
|
@ -273,6 +273,27 @@
|
||||||
<translation>Deletar</translation>
|
<translation>Deletar</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</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="41"/>
|
||||||
|
<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="51"/>
|
||||||
|
<source>unlock</source>
|
||||||
|
<extracomment>Unlock</extracomment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>SettingsPane</name>
|
<name>SettingsPane</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
2
main.go
2
main.go
|
@ -255,7 +255,7 @@ func loadNetworkingAndFiles(gcd *ui.GrandCentralDispatcher, service bool, client
|
||||||
if !service {
|
if !service {
|
||||||
the.AppBus = the.CwtchApp.GetPrimaryBus()
|
the.AppBus = the.CwtchApp.GetPrimaryBus()
|
||||||
subscribed := make(chan bool)
|
subscribed := make(chan bool)
|
||||||
go handlers.App(gcd, subscribed)
|
go handlers.App(gcd, subscribed, clientUI)
|
||||||
<-subscribed
|
<-subscribed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
qml.qrc
1
qml.qrc
|
@ -13,6 +13,7 @@
|
||||||
<file>qml/panes/PeerSettingsPane.qml</file>
|
<file>qml/panes/PeerSettingsPane.qml</file>
|
||||||
<file>qml/panes/SettingsPane.qml</file>
|
<file>qml/panes/SettingsPane.qml</file>
|
||||||
<file>qml/panes/SplashPane.qml</file>
|
<file>qml/panes/SplashPane.qml</file>
|
||||||
|
<file>qml/panes/ProfileManagerPane.qml</file>
|
||||||
<file>qml/styles/CwtchComboBoxStyle.qml</file>
|
<file>qml/styles/CwtchComboBoxStyle.qml</file>
|
||||||
<file>qml/styles/CwtchExpandingButton.qml</file>
|
<file>qml/styles/CwtchExpandingButton.qml</file>
|
||||||
<file>qml/styles/CwtchTextAreaStyle.qml</file>
|
<file>qml/styles/CwtchTextAreaStyle.qml</file>
|
||||||
|
|
24
qml/main.qml
24
qml/main.qml
|
@ -113,9 +113,14 @@ ApplicationWindow {
|
||||||
|
|
||||||
StackLayout {
|
StackLayout {
|
||||||
id: parentStack
|
id: parentStack
|
||||||
currentIndex: 0
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
currentIndex: 0
|
||||||
|
readonly property int splashPane: 0
|
||||||
|
readonly property int managementPane: 1
|
||||||
|
readonly property int profilePane: 2
|
||||||
|
property alias pane: parentStack.currentIndex
|
||||||
|
|
||||||
Rectangle { // Splash pane
|
Rectangle { // Splash pane
|
||||||
color: "#FFFFFF"
|
color: "#FFFFFF"
|
||||||
//Layout.fillHeight: true
|
//Layout.fillHeight: true
|
||||||
|
@ -131,6 +136,18 @@ ApplicationWindow {
|
||||||
running: true
|
running: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle { // Profile login/management pane
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: false
|
||||||
|
color: "#D2C0DD"
|
||||||
|
|
||||||
|
ProfileManagerPane {
|
||||||
|
id: profilesPane
|
||||||
|
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
|
||||||
anchors.top: ratio >= 0.92 ? toolbar.bottom : parent.top
|
anchors.top: ratio >= 0.92 ? toolbar.bottom : parent.top
|
||||||
|
@ -247,6 +264,11 @@ ApplicationWindow {
|
||||||
onSetToolbarTitle: function(str) {
|
onSetToolbarTitle: function(str) {
|
||||||
theStack.title = str
|
theStack.title = str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onLoaded: function() {
|
||||||
|
parentStack.pane = parentStack.managementPane
|
||||||
|
splashPane.running = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
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"
|
||||||
|
import "../widgets/controls"
|
||||||
|
import "../styles"
|
||||||
|
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: thecol
|
||||||
|
anchors.fill: parent
|
||||||
|
//leftPadding: 10
|
||||||
|
//spacing: 5
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
ProfileList {
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -99,6 +99,10 @@ ColumnLayout {
|
||||||
contactsModel.move(i, 0, 1)
|
contactsModel.move(i, 0, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onResetProfile: function() {
|
||||||
|
contactsModel.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,6 +121,7 @@ ColumnLayout {
|
||||||
status: _status
|
status: _status
|
||||||
blocked: _blocked
|
blocked: _blocked
|
||||||
loading: _loading
|
loading: _loading
|
||||||
|
type: "contact"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
|
||||||
property alias status: imgProfile.status
|
property alias status: imgProfile.status
|
||||||
property string server
|
property string server
|
||||||
property bool background: true
|
property bool background: true
|
||||||
|
property string type
|
||||||
|
|
||||||
|
|
||||||
Rectangle { // CONTACT ENTRY BACKGROUND COLOR
|
Rectangle { // CONTACT ENTRY BACKGROUND COLOR
|
||||||
|
@ -39,23 +40,42 @@ Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
|
||||||
|
|
||||||
ContactPicture {
|
ContactPicture {
|
||||||
id: imgProfile
|
id: imgProfile
|
||||||
showStatus: true
|
showStatus: type == "contact"
|
||||||
}
|
}
|
||||||
|
|
||||||
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.strikeout: blocked
|
|
||||||
textFormat: Text.PlainText
|
Label { // CONTACT NAME
|
||||||
//fontSizeMode: Text.HorizontalFit
|
id: cn
|
||||||
elide: Text.ElideRight
|
leftPadding: 10
|
||||||
color: "#000000"
|
rightPadding: 10
|
||||||
|
//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?
|
||||||
|
@ -116,15 +136,22 @@ 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
|
||||||
badge = 0
|
gcd.loadMessagesPane(handle)
|
||||||
if (handle.length == 32) {
|
badge = 0
|
||||||
gcd.requestGroupSettings(handle)
|
if (handle.length == 32) {
|
||||||
}
|
gcd.requestGroupSettings(handle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (type == "profile") {
|
||||||
|
gcd.broadcast("ResetMessagePane")
|
||||||
|
gcd.broadcast("ResetProfile")
|
||||||
|
gcd.loadProfile(handle)
|
||||||
|
parentStack.pane = parentStack.profilePane
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +191,7 @@ Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
|
||||||
}
|
}
|
||||||
|
|
||||||
onIncContactUnreadCount: function(handle) {
|
onIncContactUnreadCount: function(handle) {
|
||||||
if (handle == _handle) {
|
if (handle == _handle && gcd.currentOpenConversation != handle) {
|
||||||
badge++
|
badge++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,20 @@ 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() {
|
||||||
|
parentStack.pane = parentStack.managementPane
|
||||||
|
theStack.pane = theStack.emptyPane
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Item{ height: 6 }
|
Item{ height: 6 }
|
||||||
|
|
||||||
Item { // PROFILE IMAGE
|
Item { // PROFILE IMAGE
|
||||||
|
@ -229,8 +243,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,92 @@
|
||||||
|
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) {
|
||||||
|
|
||||||
|
console.log("ProfileList onAddProfile for: " + handle)
|
||||||
|
for (var i = 0; i < profilesModel.count; i++) {
|
||||||
|
if (profilesModel.get(i)["_handle"] == handle) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
profilesModel.append({
|
||||||
|
"_handle": handle,
|
||||||
|
"_displayName": displayName,
|
||||||
|
"_image": image
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
ListModel { // Profile OBJECTS ARE STORED HERE ...
|
||||||
|
id: profilesModel
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: profilesModel // ... AND DISPLAYED HERE
|
||||||
|
delegate: ContactRow {
|
||||||
|
handle: _handle
|
||||||
|
displayName: _displayName
|
||||||
|
image: _image
|
||||||
|
server: ""
|
||||||
|
badge: 0
|
||||||
|
status: 0
|
||||||
|
blocked: false
|
||||||
|
loading: false
|
||||||
|
type: "profile"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue