diff --git a/go/constants/attributes.go b/go/constants/attributes.go
index 10065d64..0868de16 100644
--- a/go/constants/attributes.go
+++ b/go/constants/attributes.go
@@ -3,3 +3,4 @@ package constants
const Nick = "nick"
const LastRead = "last-read"
const Picture = "picture"
+const DefaultPassword = "default-password"
diff --git a/go/handlers/appHandler.go b/go/handlers/appHandler.go
index 50f2cd5e..7baa03d6 100644
--- a/go/handlers/appHandler.go
+++ b/go/handlers/appHandler.go
@@ -12,7 +12,7 @@ import (
"time"
)
-func App(gcd *ui.GrandCentralDispatcher, subscribed chan bool) {
+func App(gcd *ui.GrandCentralDispatcher, subscribed chan bool, reloadingFirst bool) {
q := event.NewQueue()
the.AppBus.Subscribe(event.NewPeer, 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.ReloadDone, q)
subscribed <- true
+ loadingV1Accounts := !reloadingFirst
networkOffline := false
- timeSinceLastSuccess := time.Unix(0,0)
+ timeSinceLastSuccess := time.Unix(0, 0)
+
+ gcd.Loaded()
for {
e := q.Next()
@@ -74,65 +77,54 @@ func App(gcd *ui.GrandCentralDispatcher, subscribed chan bool) {
case event.AppError:
if e.Data[event.Error] == event.AppErrLoaded0 {
- // TODO: only an error if other profiles are not loaded
- log.Infoln("couldn't load your config file. attempting to create one now")
- if gcd.Version() == "development" {
- the.CwtchApp.CreatePeer("tester", the.AppPassword)
+
+ if loadingV1Accounts {
+ loadingV1Accounts = false
+ // 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 {
- the.CwtchApp.CreatePeer("alice", the.AppPassword)
+ gcd.ErrorLoaded0()
}
}
case event.ReloadDone:
if the.Peer == nil {
+ loadingV1Accounts = true
the.CwtchApp.LoadProfiles(the.AppPassword)
}
case event.NewPeer:
- if the.Peer != nil {
- continue
- }
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.NETWORKCHECK)
- the.Peer = the.CwtchApp.GetPeer(onion)
- the.EventBus = the.CwtchApp.GetEventBus(onion)
-
incSubscribed := make(chan bool)
- go PeerHandler(&gcd.UIManager, incSubscribed)
+ go PeerHandler(onion, &gcd.UIManager, 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" {
- the.CwtchApp.LaunchPeers()
+ peer.Listen()
+ peer.StartPeersConnections()
+ peer.StartGroupConnections()
}
- // load ui preferences
- gcd.RequestSettings()
- locale, exists := the.Peer.GetProfile().GetAttribute(constants.LocaleSetting)
- if exists {
- gcd.SetLocale_helper(locale)
- }
-
- blockUnkownPeers, exists := the.Peer.GetProfile().GetAttribute(constants.BlockUnknownPeersSetting)
+ blockUnkownPeers, exists := peer.GetProfile().GetAttribute(constants.BlockUnknownPeersSetting)
if exists && blockUnkownPeers == "true" {
the.EventBus.Publish(event.NewEvent(event.BlockUnknownPeers, map[event.Field]string{}))
}
diff --git a/go/handlers/peerHandler.go b/go/handlers/peerHandler.go
index 497f28f7..a753db98 100644
--- a/go/handlers/peerHandler.go
+++ b/go/handlers/peerHandler.go
@@ -9,18 +9,20 @@ import (
"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()
- the.EventBus.Subscribe(event.NewMessageFromPeer, q)
- the.EventBus.Subscribe(event.PeerAcknowledgement, q)
- the.EventBus.Subscribe(event.NewMessageFromGroup, q)
- the.EventBus.Subscribe(event.NewGroupInvite, q)
- the.EventBus.Subscribe(event.SendMessageToGroupError, q)
- the.EventBus.Subscribe(event.SendMessageToPeerError, q)
- the.EventBus.Subscribe(event.ServerStateChange, q)
- the.EventBus.Subscribe(event.PeerStateChange, q)
- the.EventBus.Subscribe(event.PeerCreated, q)
- the.EventBus.Subscribe(event.NetworkStatus, q)
+ eventBus.Subscribe(event.NewMessageFromPeer, q)
+ eventBus.Subscribe(event.PeerAcknowledgement, q)
+ eventBus.Subscribe(event.NewMessageFromGroup, q)
+ eventBus.Subscribe(event.NewGroupInvite, q)
+ eventBus.Subscribe(event.SendMessageToGroupError, q)
+ eventBus.Subscribe(event.SendMessageToPeerError, q)
+ eventBus.Subscribe(event.ServerStateChange, q)
+ eventBus.Subscribe(event.PeerStateChange, q)
+ eventBus.Subscribe(event.PeerCreated, q)
+ eventBus.Subscribe(event.NetworkStatus, q)
subscribed <- true
@@ -43,8 +45,8 @@ func PeerHandler(uiManager *ui.Manager, subscribed chan bool) {
case event.NewMessageFromPeer: //event.TimestampReceived, event.RemotePeer, event.Data
ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampReceived])
uiManager.AddMessage(e.Data[event.RemotePeer], e.Data[event.RemotePeer], e.Data[event.Data], false, e.EventID, ts, true)
- if the.Peer.GetContact(e.Data[event.RemotePeer]) == nil {
- the.Peer.AddContact(e.Data[event.RemotePeer], e.Data[event.RemotePeer], false)
+ if peer.GetContact(e.Data[event.RemotePeer]) == nil {
+ peer.AddContact(e.Data[event.RemotePeer], e.Data[event.RemotePeer], false)
}
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
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:
- gid, err := the.Peer.GetProfile().ProcessInvite(e.Data[event.GroupInvite], e.Data[event.RemotePeer])
- group := the.Peer.GetGroup(gid)
+ gid, err := peer.GetProfile().ProcessInvite(e.Data[event.GroupInvite], e.Data[event.RemotePeer])
+ group := peer.GetGroup(gid)
if err == nil && group != nil {
uiManager.AddContact(gid)
}
@@ -70,18 +72,18 @@ func PeerHandler(uiManager *ui.Manager, subscribed chan bool) {
cxnState := connections.ConnectionStateToType[e.Data[event.ConnectionState]]
// 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
// So if we get any other state from an unknown contact we do nothing
// (the next exists check will fail)
if cxnState == connections.AUTHENTICATED {
- the.Peer.AddContact(e.Data[event.RemotePeer], e.Data[event.RemotePeer], false)
+ peer.AddContact(e.Data[event.RemotePeer], e.Data[event.RemotePeer], false)
uiManager.AddContact(e.Data[event.RemotePeer])
}
}
// if it's in the.PeerHandler its either existing and needs an update or not in the UI and needs to be added
- if contact, exists := 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]
uiManager.UpdateContactStatus(contact.Onion, int(cxnState), false)
@@ -89,9 +91,9 @@ func PeerHandler(uiManager *ui.Manager, subscribed chan bool) {
case event.ServerStateChange:
serverOnion := e.Data[event.GroupServer]
state := connections.ConnectionStateToType[e.Data[event.ConnectionState]]
- groups := the.Peer.GetGroups()
+ groups := peer.GetGroups()
for _, groupID := range groups {
- group := the.Peer.GetGroup(groupID)
+ group := peer.GetGroup(groupID)
if group != nil && group.GroupServer == serverOnion {
group.State = e.Data[event.ConnectionState]
loading := false
diff --git a/go/ui/gcd.go b/go/ui/gcd.go
index 3ff20789..1c3c8e7b 100644
--- a/go/ui/gcd.go
+++ b/go/ui/gcd.go
@@ -27,6 +27,12 @@ type GrandCentralDispatcher struct {
_ string `property:"version"`
_ 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
_ func(handle, displayName, image, server string, badge, status int, blocked bool, loading bool, lastMsgTime int) `signal:"AddContact"`
_ func(handle, displayName string) `signal:"UpdateContactDisplayName"`
@@ -82,6 +88,8 @@ type GrandCentralDispatcher struct {
_ func() `signal:"allowUnknownPeers,auto"`
_ func() `signal:"blockUnknownPeers,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) {
@@ -295,6 +303,8 @@ func (this *GrandCentralDispatcher) broadcast(signal string) {
log.Debugf("unhandled broadcast signal: %v", signal)
case "ResetMessagePane":
this.ResetMessagePane()
+ case "ResetProfile":
+ this.ResetProfile()
}
}
@@ -477,3 +487,37 @@ func (this *GrandCentralDispatcher) SetLocale_helper(locale string) {
core.QCoreApplication_InstallTranslator(this.Translator)
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)
+ }
+}
diff --git a/go/ui/manager.go b/go/ui/manager.go
index 11423539..b2f0ad34 100644
--- a/go/ui/manager.go
+++ b/go/ui/manager.go
@@ -98,7 +98,7 @@ func updateLastReadTime(id string) {
func countUnread(messages []model.Message, lastRead time.Time) int {
count := 0
for i := len(messages) - 1; i >= 0; i-- {
- if messages[i].Timestamp.After(lastRead) {
+ if messages[i].Timestamp.After(lastRead) || messages[i].Timestamp.Equal(lastRead) {
count++
} else {
break
@@ -115,6 +115,25 @@ func NewManager(gcd *GrandCentralDispatcher) Manager {
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) {
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) {
- updateLastReadTime(handle)
-
nick := getOrDefault(handle, constants.Nick, handle)
image := getProfilePic(handle)
// If we have this group loaded already
if this.gcd.CurrentOpenConversation() == handle {
+ updateLastReadTime(handle)
// If the message is not from the user then add it, otherwise, just acknowledge.
if !fromMe {
this.gcd.AppendMessage(handle, from, nick, message, image, messageID, fromMe, timestamp.Format(constants.TIME_FORMAT), false, false)
@@ -187,9 +205,8 @@ func (this *Manager) AddMessage(handle string, from string, message string, from
this.gcd.Acknowledged(messageID)
}
}
- } else {
- this.gcd.IncContactUnreadCount(handle)
}
+ this.gcd.IncContactUnreadCount(handle)
}
func (this *Manager) UpdateContactDisplayName(handle string, name string) {
diff --git a/i18n/translation_de.ts b/i18n/translation_de.ts
index e7a778a9..5398cd7a 100644
--- a/i18n/translation_de.ts
+++ b/i18n/translation_de.ts
@@ -145,18 +145,18 @@
Klicken, um DM zu senden
-
+
Could not send this message
Nachricht konnte nicht gesendet werden
-
+
bestätigt
-
+
Bestätigung ausstehend
@@ -164,25 +164,25 @@
MyProfile
-
+
Button for copying profile onion address to clipboard
Kopieren
-
+
Copied to clipboard
in die Zwischenablage kopiert
-
+
create new group button
Neue Gruppe anlegen
-
+
ex: "... paste an address here to add a contact ..."
Adresse hier hinzufügen, um einen Kontakt aufzunehmen
@@ -273,6 +273,27 @@
löschen
+
+ ProfileManagerPane
+
+
+
+ Please enter password:
+
+
+
+
+
+ 0 profiles loaded with that password
+
+
+
+
+
+ Unlock
+
+
+
SettingsPane
diff --git a/i18n/translation_en.qm b/i18n/translation_en.qm
index 6ec2aa99..5149964b 100644
Binary files a/i18n/translation_en.qm and b/i18n/translation_en.qm differ
diff --git a/i18n/translation_en.ts b/i18n/translation_en.ts
index 97294b40..2f41ac53 100644
--- a/i18n/translation_en.ts
+++ b/i18n/translation_en.ts
@@ -103,7 +103,7 @@
-
+ Update
@@ -145,18 +145,18 @@
Click to DM
-
+
Could not send this message
Could not send this message
-
+
Acknowledged
-
+
Pending
@@ -164,25 +164,25 @@
MyProfile
-
+
Button for copying profile onion address to clipboard
Copy
-
+
Copied to clipboard
Copied to clipboard
-
+
create new group button
Create new group
-
+
ex: "... paste an address here to add a contact ..."
... paste an address here to add a contact...
@@ -273,6 +273,27 @@
Delete
+
+ ProfileManagerPane
+
+
+
+ Please enter password:
+ Please enter password
+
+
+
+
+ 0 profiles loaded with that password
+ 0 profiles loaded with that password
+
+
+
+
+ Unlock
+ Unlock
+
+
SettingsPane
diff --git a/i18n/translation_fr.ts b/i18n/translation_fr.ts
index 0cdbf03a..f8fe744e 100644
--- a/i18n/translation_fr.ts
+++ b/i18n/translation_fr.ts
@@ -145,18 +145,18 @@
Envoyer un message privé
-
+
Could not send this message
Impossible d'envoyer ce message
-
+
Confirmé
-
+
En attente
@@ -164,25 +164,25 @@
MyProfile
-
+
Button for copying profile onion address to clipboard
Copier
-
+
Copied to clipboard
Copié dans le presse-papier
-
+
create new group button
Créer un nouveau groupe
-
+
ex: "... paste an address here to add a contact ..."
... coller une adresse ici pour ajouter un contact...
@@ -273,6 +273,27 @@
Effacer
+
+ ProfileManagerPane
+
+
+
+ Please enter password:
+
+
+
+
+
+ 0 profiles loaded with that password
+
+
+
+
+
+ Unlock
+
+
+
SettingsPane
diff --git a/i18n/translation_pt.ts b/i18n/translation_pt.ts
index 72acd517..a5f828f2 100644
--- a/i18n/translation_pt.ts
+++ b/i18n/translation_pt.ts
@@ -145,18 +145,18 @@
Clique para DM
-
+
Could not send this message
Não deu para enviar esta mensagem
-
+
Confirmada
-
+
Pendente
@@ -164,25 +164,25 @@
MyProfile
-
+
Button for copying profile onion address to clipboard
Copiar
-
+
Copied to clipboard
Copiado
-
+
create new group button
Criar novo grupo
-
+
ex: "... paste an address here to add a contact ..."
… cole um endereço aqui para adicionar um contato…
@@ -273,6 +273,27 @@
Deletar
+
+ ProfileManagerPane
+
+
+
+ Please enter password:
+
+
+
+
+
+ 0 profiles loaded with that password
+
+
+
+
+
+ Unlock
+
+
+
SettingsPane
diff --git a/main.go b/main.go
index 1b514f52..b6da2e69 100644
--- a/main.go
+++ b/main.go
@@ -255,7 +255,7 @@ func loadNetworkingAndFiles(gcd *ui.GrandCentralDispatcher, service bool, client
if !service {
the.AppBus = the.CwtchApp.GetPrimaryBus()
subscribed := make(chan bool)
- go handlers.App(gcd, subscribed)
+ go handlers.App(gcd, subscribed, clientUI)
<-subscribed
}
diff --git a/qml.qrc b/qml.qrc
index b4097e8e..7f33a9a4 100644
--- a/qml.qrc
+++ b/qml.qrc
@@ -13,6 +13,7 @@
qml/panes/PeerSettingsPane.qml
qml/panes/SettingsPane.qml
qml/panes/SplashPane.qml
+ qml/panes/ProfileManagerPane.qml
qml/styles/CwtchComboBoxStyle.qml
qml/styles/CwtchExpandingButton.qml
qml/styles/CwtchTextAreaStyle.qml
diff --git a/qml/main.qml b/qml/main.qml
index 71b3db84..dcc2a1b4 100644
--- a/qml/main.qml
+++ b/qml/main.qml
@@ -113,9 +113,14 @@ ApplicationWindow {
StackLayout {
id: parentStack
- currentIndex: 0
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
color: "#FFFFFF"
//Layout.fillHeight: true
@@ -131,6 +136,18 @@ ApplicationWindow {
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
/* anchors.left: ratio >= 0.92 ? parent.left : toolbar.right
anchors.top: ratio >= 0.92 ? toolbar.bottom : parent.top
@@ -247,6 +264,11 @@ ApplicationWindow {
onSetToolbarTitle: function(str) {
theStack.title = str
}
+
+ onLoaded: function() {
+ parentStack.pane = parentStack.managementPane
+ splashPane.running = false
+ }
}
Connections {
diff --git a/qml/panes/ProfileManagerPane.qml b/qml/panes/ProfileManagerPane.qml
new file mode 100644
index 00000000..cd0e1d0c
--- /dev/null
+++ b/qml/panes/ProfileManagerPane.qml
@@ -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
+ }
+ }
+
+
+}
diff --git a/qml/widgets/ContactList.qml b/qml/widgets/ContactList.qml
index bcacf3be..1552475d 100644
--- a/qml/widgets/ContactList.qml
+++ b/qml/widgets/ContactList.qml
@@ -99,6 +99,10 @@ ColumnLayout {
contactsModel.move(i, 0, 1)
}
}
+ }
+
+ onResetProfile: function() {
+ contactsModel.clear()
}
}
@@ -117,6 +121,7 @@ ColumnLayout {
status: _status
blocked: _blocked
loading: _loading
+ type: "contact"
}
}
diff --git a/qml/widgets/ContactRow.qml b/qml/widgets/ContactRow.qml
index 5f497ec5..e6dd9e67 100644
--- a/qml/widgets/ContactRow.qml
+++ b/qml/widgets/ContactRow.qml
@@ -27,6 +27,7 @@ Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
property alias status: imgProfile.status
property string server
property bool background: true
+ property string type
Rectangle { // CONTACT ENTRY BACKGROUND COLOR
@@ -39,23 +40,42 @@ Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
ContactPicture {
id: imgProfile
- showStatus: true
+ showStatus: type == "contact"
}
- Label { // CONTACT NAME
- id: cn
- leftPadding: 10
- rightPadding: 10
- //wrapMode: Text.WordWrap
+ ColumnLayout {
+
anchors.left: imgProfile.right
anchors.right: loading ? loadingProgress.left : rectUnread.left
anchors.verticalCenter: parent.verticalCenter
- font.pixelSize: 16 * gcd.themeScale
- font.strikeout: blocked
- textFormat: Text.PlainText
- //fontSizeMode: Text.HorizontalFit
- elide: Text.ElideRight
- color: "#000000"
+
+
+ Label { // CONTACT NAME
+ id: cn
+ leftPadding: 10
+ 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?
@@ -116,15 +136,22 @@ Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
hoverEnabled: true
onClicked: {
- if (displayName != "me") {
- gcd.broadcast("ResetMessagePane")
- isActive = true
- theStack.pane = theStack.messagePane
- gcd.loadMessagesPane(handle)
- badge = 0
- if (handle.length == 32) {
- gcd.requestGroupSettings(handle)
- }
+ if (type == "contact") {
+ if (displayName != "me") {
+ gcd.broadcast("ResetMessagePane")
+ isActive = true
+ theStack.pane = theStack.messagePane
+ gcd.loadMessagesPane(handle)
+ badge = 0
+ 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) {
- if (handle == _handle) {
+ if (handle == _handle && gcd.currentOpenConversation != handle) {
badge++
}
}
diff --git a/qml/widgets/MyProfile.qml b/qml/widgets/MyProfile.qml
index 78599a5a..d634c69a 100644
--- a/qml/widgets/MyProfile.qml
+++ b/qml/widgets/MyProfile.qml
@@ -19,6 +19,20 @@ ColumnLayout {
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 { // PROFILE IMAGE
@@ -229,8 +243,6 @@ ColumnLayout {
lblNick.text = _nick
onion = _onion
image = _image
- parentStack.currentIndex = 1
- splashPane.running = false
}
onTorStatus: function(code, str) {
diff --git a/qml/widgets/ProfileList.qml b/qml/widgets/ProfileList.qml
new file mode 100644
index 00000000..8e8db340
--- /dev/null
+++ b/qml/widgets/ProfileList.qml
@@ -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"
+ }
+ }
+ }
+ }
+}