diff --git a/go/ui/gcd.go b/go/ui/gcd.go
index ca066b5f..8e441618 100644
--- a/go/ui/gcd.go
+++ b/go/ui/gcd.go
@@ -41,6 +41,8 @@ type GrandCentralDispatcher struct {
_ func(handle, displayname, image string) `signal:"AddProfile"`
_ func() `signal:"ErrorLoaded0"`
_ func() `signal:"ResetProfile"`
+ _ func() `signal:"ResetProfileList"`
+ _ func(onion string) `signal:"deleteProfile"`
// contact list stuff
_ func(handle, displayName, image, server string, badge, status int, blocked bool, loading bool, lastMsgTime int) `signal:"AddContact"`
@@ -72,6 +74,16 @@ type GrandCentralDispatcher struct {
_ func(onion, nick string, blocked bool) `signal:"SupplyPeerSettings"`
// signals emitted from the ui (written in go, below)
+ // ui
+ _ func() `signal:"onActivate,auto"`
+ _ func(locale string) `signal:"setLocale,auto"`
+ // profile managemenet
+ _ func(onion, nick string) `signal:"updateNick,auto"`
+ _ func(handle string) `signal:"loadProfile,auto"`
+ _ func(nick, password string) `signal:"createProfile,auto"`
+ _ func(password string) `signal:"unlockProfiles,auto"`
+ _ func() `signal:"reloadProfileList,auto"`
+ // operating a profile
_ func(message string, mid string) `signal:"sendMessage,auto"`
_ func(onion string) `signal:"blockPeer,auto"`
_ func(onion string) `signal:"unblockPeer,auto"`
@@ -80,7 +92,6 @@ type GrandCentralDispatcher struct {
_ func(str string) `signal:"importString,auto"`
_ func(str string) `signal:"createContact,auto"`
_ func(str string) `signal:"popup,auto"`
- _ func(nick string) `signal:"updateNick,auto"`
_ func(server, groupName string) `signal:"createGroup,auto"`
_ func(groupID string) `signal:"leaveGroup,auto"`
_ func(groupID string) `signal:"acceptGroup,auto"`
@@ -93,12 +104,8 @@ type GrandCentralDispatcher struct {
_ func(onion, groupID string) `signal:"inviteToGroup,auto"`
_ func(onion, key, nick string) `signal:"setAttribute,auto"`
_ func(onion string) `signal:"deleteContact,auto"`
- _ func(locale string) `signal:"setLocale,auto"`
_ 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() `constructor:"init"`
}
@@ -473,11 +480,14 @@ func (this *GrandCentralDispatcher) popup(str string) {
this.InvokePopup(str)
}
-func (this *GrandCentralDispatcher) updateNick(nick string) {
- the.Peer.GetProfile().Name = nick
- the.EventBus.Publish(event.NewEvent(event.SetProfileName, map[event.Field]string{
- event.ProfileName: nick,
- }))
+func (this *GrandCentralDispatcher) updateNick(onion, nick string) {
+ peer := the.CwtchApp.GetPeer(onion)
+ if peer != nil {
+ peer.GetProfile().Name = nick
+ the.CwtchApp.GetEventBus(onion).Publish(event.NewEvent(event.SetProfileName, map[event.Field]string{
+ event.ProfileName: nick,
+ }))
+ }
}
func (this *GrandCentralDispatcher) createGroup(server, groupName string) {
@@ -608,3 +618,19 @@ func (this *GrandCentralDispatcher) loadProfile(onion string) {
this.SetLocale_helper(locale)
}
}
+
+func (this *GrandCentralDispatcher) createProfile(nick, password string) {
+ the.CwtchApp.CreatePeer(nick, password)
+}
+
+func (this *GrandCentralDispatcher) reloadProfileList() {
+ this.ResetProfileList()
+
+ for onion, _ := range the.CwtchApp.ListPeers() {
+ AddProfile(this, onion)
+ }
+}
+
+func (this *GrandCentralDispatcher) deleteProfile(onion string) {
+ //the.CwtchApp.
+}
diff --git a/i18n/translation_de.ts b/i18n/translation_de.ts
index 5398cd7a..47ebb17e 100644
--- a/i18n/translation_de.ts
+++ b/i18n/translation_de.ts
@@ -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,91 @@
löschen
+
+ ProfileAddEditPane
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Profile name
+
+
+
+
+
+
+ default suggested profile name
+
+
+
+
+
+ Profile Onion
+
+
+
+
+
+ Password
+
+
+
+
+
+ Reenter password
+
+
+
+
+
+ Create Profile || Save Profile
+
+
+
+
+
+
+
+
+
+
+ Passwords do not match
+
+
+
+
+
+ Delete Profile
+
+
+
+
+
+ Type DELETE to confirm
+
+
+
+
+
+ Really Delete Profile
+
+
+
+
+
+ DELETE
+
+
+
ProfileManagerPane
@@ -339,7 +424,7 @@
StackToolbar
-
+
View Group Membership
diff --git a/i18n/translation_en.qm b/i18n/translation_en.qm
index 5149964b..f14e39c3 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 2f41ac53..575e96fb 100644
--- a/i18n/translation_en.ts
+++ b/i18n/translation_en.ts
@@ -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,91 @@
Delete
+
+ ProfileAddEditPane
+
+
+
+ Add new profile
+
+
+
+
+ Edit Profile
+
+
+
+
+ Profile name
+ Display name
+
+
+
+
+
+ default suggested profile name
+ Alice
+
+
+
+
+ Profile Onion
+ Onion
+
+
+
+
+ Password
+ Password
+
+
+
+
+ Reenter password
+ Password
+
+
+
+
+ Create Profile || Save Profile
+ Create Profile
+
+
+
+
+ Save Profile
+
+
+
+
+ Passwords do not match
+ Passwords do not match
+
+
+
+
+ Delete Profile
+ Delete Profile
+
+
+
+
+ Type DELETE to confirm
+ Type DELETE to confirm
+
+
+
+
+ Really Delete Profile
+ Really Delete Profile
+
+
+
+
+ DELETE
+ DELETE
+
+
ProfileManagerPane
@@ -339,7 +424,7 @@
StackToolbar
-
+
View Group Membership
View Group Membership
diff --git a/i18n/translation_fr.ts b/i18n/translation_fr.ts
index f8fe744e..157be8fa 100644
--- a/i18n/translation_fr.ts
+++ b/i18n/translation_fr.ts
@@ -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,91 @@
Effacer
+
+ ProfileAddEditPane
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Profile name
+
+
+
+
+
+
+ default suggested profile name
+
+
+
+
+
+ Profile Onion
+
+
+
+
+
+ Password
+
+
+
+
+
+ Reenter password
+
+
+
+
+
+ Create Profile || Save Profile
+
+
+
+
+
+
+
+
+
+
+ Passwords do not match
+
+
+
+
+
+ Delete Profile
+
+
+
+
+
+ Type DELETE to confirm
+
+
+
+
+
+ Really Delete Profile
+
+
+
+
+
+ DELETE
+
+
+
ProfileManagerPane
@@ -339,7 +424,7 @@
StackToolbar
-
+
View Group Membership
diff --git a/i18n/translation_pt.ts b/i18n/translation_pt.ts
index a5f828f2..f7ab7e7a 100644
--- a/i18n/translation_pt.ts
+++ b/i18n/translation_pt.ts
@@ -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,91 @@
Deletar
+
+ ProfileAddEditPane
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Profile name
+
+
+
+
+
+
+ default suggested profile name
+
+
+
+
+
+ Profile Onion
+
+
+
+
+
+ Password
+
+
+
+
+
+ Reenter password
+
+
+
+
+
+ Create Profile || Save Profile
+
+
+
+
+
+
+
+
+
+
+ Passwords do not match
+
+
+
+
+
+ Delete Profile
+
+
+
+
+
+ Type DELETE to confirm
+
+
+
+
+
+ Really Delete Profile
+
+
+
+
+
+ DELETE
+
+
+
ProfileManagerPane
@@ -339,7 +424,7 @@
StackToolbar
-
+
View Group Membership
diff --git a/qml.qrc b/qml.qrc
index 7f33a9a4..f7d266c6 100644
--- a/qml.qrc
+++ b/qml.qrc
@@ -14,6 +14,7 @@
qml/panes/SettingsPane.qml
qml/panes/SplashPane.qml
qml/panes/ProfileManagerPane.qml
+ qml/panes/ProfileAddEditPane.qml
qml/styles/CwtchComboBoxStyle.qml
qml/styles/CwtchExpandingButton.qml
qml/styles/CwtchTextAreaStyle.qml
diff --git a/qml/main.qml b/qml/main.qml
index dcc2a1b4..0540d843 100644
--- a/qml/main.qml
+++ b/qml/main.qml
@@ -118,7 +118,8 @@ ApplicationWindow {
currentIndex: 0
readonly property int splashPane: 0
readonly property int managementPane: 1
- readonly property int profilePane: 2
+ readonly property int addEditProfilePane: 2
+ readonly property int profilePane: 3
property alias pane: parentStack.currentIndex
Rectangle { // Splash pane
@@ -148,6 +149,18 @@ ApplicationWindow {
}
}
+ Rectangle { // Profile login/management pane
+ anchors.fill: parent
+ color: "#EEEEFF"
+
+
+ ProfileAddEditPane{
+ id: profileAddEditPane
+ 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
diff --git a/qml/panes/ProfileAddEditPane.qml b/qml/panes/ProfileAddEditPane.qml
new file mode 100644
index 00000000..97e371ef
--- /dev/null
+++ b/qml/panes/ProfileAddEditPane.qml
@@ -0,0 +1,200 @@
+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 "../widgets"
+import "../styles"
+
+ColumnLayout { // Add Profile Pane
+ id: profileAddEditPane
+ anchors.fill: parent
+
+ property string mode // edit or add
+
+ StackToolbar {
+ id: stb
+ text: mode == "add" ? qsTr("add-profile-title") : qsTr("edit-profile-title")
+ aux.visible: false
+ membership.visible: false
+ stack: "management"
+ }
+
+ function reset() {
+ txtProfileName.text = qsTr("default-profile-name")
+ txtPassword1.text = ""
+ txtPassword2.text = ""
+ deleteReset()
+ }
+
+ function load(onion, name, pass) {
+ onionLabel.text = onion
+ txtProfileName.text = name
+ txtPassword1.text = pass
+ txtPassword2.text = pass
+
+ deleteReset()
+ }
+
+ function deleteReset() {
+ deleteConfirmLabel.visible = false
+ deleteConfirmLabel.visible = false
+ deleteConfirmLabel.color = "black"
+ confirmDeleteTxt.visible = false
+ confirmDeleteTxt.text = ""
+ confirmDeleteBtn.visible = false
+ }
+
+ Flickable {
+ anchors.top: stb.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ boundsBehavior: Flickable.StopAtBounds
+ clip:true
+ contentWidth: tehcol.width
+ contentHeight: tehcol.height
+
+ Column {
+ id: tehcol
+ leftPadding: 10
+ spacing: 5
+ width: profileAddEditPane.width
+
+ ScalingLabel {
+ //: Onion
+ text: qsTr("profile-onion-label") + ":"
+ visible: mode == "edit"
+ }
+
+ ScalingLabel {
+ id: onionLabel
+ visible: mode == "edit"
+ }
+
+ ScalingLabel {
+ //: Display name
+ text: qsTr("profile-name") + ":"
+ }
+
+ TextField {
+ id: txtProfileName
+ Layout.fillWidth: true
+ style: CwtchTextFieldStyle{ width: tehcol.width * 0.8 }
+ //: default suggested profile name
+ text: qsTr("default-profile-name")
+ }
+
+ ScalingLabel {
+ //: Password
+ text: qsTr("password1-label") + ":"
+ }
+
+ TextField {
+ id: txtPassword1
+ Layout.fillWidth: true
+ style: CwtchTextFieldStyle{ width: tehcol.width * 0.8 }
+ echoMode: TextInput.Password
+ readOnly: mode == "edit"
+ }
+
+
+ ScalingLabel {
+ //: Reenter password
+ text: qsTr("password2-label") + ":"
+ }
+
+ TextField {
+ id: txtPassword2
+ Layout.fillWidth: true
+ style: CwtchTextFieldStyle{ width: tehcol.width * 0.8 }
+ echoMode: TextInput.Password
+ readOnly: mode == "edit"
+
+ }
+
+ SimpleButton {
+ //: Create Profile || Save Profile
+ text: mode == "add" ? qsTr("create-profile-btn") : qsTr("save-profile-btn")
+
+ onClicked: {
+ if (txtPassword1.text != txtPassword2.text) {
+ passwordErrorLabel.visible = true
+ } else {
+ if (mode == "add") {
+ gcd.createProfile(txtProfileName.text, txtPassword1.text)
+ } else {
+ gcd.updateNick(onionLabel.text, txtProfileName.text)
+ }
+ gcd.reloadProfileList()
+ parentStack.pane = parentStack.managementPane
+ }
+ }
+ }
+
+ ScalingLabel {
+ id: passwordErrorLabel
+ //: Passwords do not match
+ text: qsTr("password-error-match")
+ visible: false
+ color: "red"
+ }
+
+ SimpleButton {
+ //: Delete Profile
+ text: qsTr("delete-profile-btn")
+ icon: "regular/trash-alt"
+ visible: mode == "edit"
+
+
+ onClicked: {
+ deleteConfirmLabel.visible = true
+ deleteConfirmLabel.visible = true
+ confirmDeleteTxt.visible = true
+ confirmDeleteBtn.visible = true
+ }
+ }
+
+ ScalingLabel {
+ id: deleteConfirmLabel
+ //: Type DELETE to confirm
+ text: qsTr("delete-confirm-label")+ ":"
+ visible: false
+ }
+
+ TextField {
+ id: confirmDeleteTxt
+ Layout.fillWidth: true
+ style: CwtchTextFieldStyle{ width: tehcol.width * 0.8 }
+ visible: false
+ }
+
+ SimpleButton {
+ id: confirmDeleteBtn
+ icon: "regular/trash-alt"
+
+ //: Really Delete Profile
+ text: qsTr("delete-profile-confirm-btn")
+ color: "red"
+ visible: false
+
+ onClicked: {
+ //: DELETE
+ if (confirmDeleteTxt.text == qsTr("delete-confirm-text")) {
+ gcd.deleteProfile(onionLabel.text)
+ gcd.reloadProfileList()
+ parentStack.pane = parentStack.managementPane
+ } else {
+ deleteConfirmLabel.color = "red"
+ }
+
+ }
+ }
+
+
+ }//end of column with padding
+ }//end of flickable
+}
\ No newline at end of file
diff --git a/qml/widgets/ContactPicture.qml b/qml/widgets/ContactPicture.qml
index 42971be5..d8b9ead6 100644
--- a/qml/widgets/ContactPicture.qml
+++ b/qml/widgets/ContactPicture.qml
@@ -17,6 +17,7 @@ Item {
property bool isGroup
property bool showStatus
property bool highlight
+ property bool button
property real logscale: 4 * Math.log10(gcd.themeScale + 1)
property int baseWidth: 48 * logscale
@@ -30,7 +31,7 @@ Item {
Rectangle {
width: highlight ? baseWidth - 4 : baseWidth
height: highlight ? baseWidth - 4 : baseWidth
- color: "#FFFFFF"
+ color: button ? windowItem.cwtch_dark_color: "#FFFFFF"
radius: width / 2
anchors.centerIn:parent
diff --git a/qml/widgets/ContactRow.qml b/qml/widgets/ContactRow.qml
index e5de3639..6e619d09 100644
--- a/qml/widgets/ContactRow.qml
+++ b/qml/widgets/ContactRow.qml
@@ -10,6 +10,7 @@ import QtQuick.Controls.Styles 1.4
Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
+ id: crItem
anchors.left: parent.left
anchors.right: parent.right
height: 48 * logscale + 3
@@ -22,12 +23,17 @@ Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
property int badge
property bool isActive
property bool isHover
+ property bool background: true
+ property string type // profile or contact or button
+
+ // Profile
+ property bool defaultPassword
+
+ // Contact
property bool blocked
property bool loading
- property alias status: imgProfile.status
- property string server
- property bool background: true
- property string type
+ property alias status: imgProfile.status
+ property string server
Rectangle { // CONTACT ENTRY BACKGROUND COLOR
@@ -41,6 +47,7 @@ Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
ContactPicture {
id: imgProfile
showStatus: type == "contact"
+ button: type == "button"
}
ColumnLayout {
@@ -105,6 +112,11 @@ Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
}
}
+ // Profile
+
+
+
+ // Contact
ProgressBar { // LOADING ?
id: loadingProgress
property bool running
@@ -153,6 +165,10 @@ Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
gcd.selectedProfile = handle
gcd.loadProfile(handle)
parentStack.pane = parentStack.profilePane
+ } else if (type == "button") { // Add profile button
+ profileAddEditPane.mode = "add"
+ profileAddEditPane.reset()
+ parentStack.pane = parentStack.addEditProfilePane
}
}
@@ -165,6 +181,28 @@ Item { // LOTS OF NESTING TO DEAL WITH QT WEIRDNESS, SORRY
}
}
+ SimpleButton {// Edit BUTTON
+ id: btnEdit
+ icon: "solid/user-edit"
+
+ anchors.right: parent.right
+
+ //rectUnread.left
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.leftMargin: 1 * gcd.themeScale
+ anchors.rightMargin: 20 * gcd.themeScale
+ height: parent.height * 0.75
+
+ visible: type == "profile"
+
+
+ onClicked: {
+ profileAddEditPane.mode = "edit"
+ profileAddEditPane.load(handle, displayName, "")
+ parentStack.pane = parentStack.addEditProfilePane
+ }
+ }
+
Connections { // UPDATE UNREAD MESSAGES COUNTER
target: gcd
diff --git a/qml/widgets/MyProfile.qml b/qml/widgets/MyProfile.qml
index cdcd96e0..dc7df543 100644
--- a/qml/widgets/MyProfile.qml
+++ b/qml/widgets/MyProfile.qml
@@ -29,6 +29,7 @@ ColumnLayout {
anchors.topMargin: 2
onClicked: function() {
gcd.selectedProfile = "none"
+ gcd.reloadProfileList()
parentStack.pane = parentStack.managementPane
theStack.pane = theStack.emptyPane
}
@@ -120,7 +121,7 @@ ColumnLayout {
Layout.alignment: Qt.AlignHCenter
onUpdated: {
- gcd.updateNick(lblNick.text)
+ gcd.updateNick(onion, lblNick.text)
}
}
diff --git a/qml/widgets/ProfileList.qml b/qml/widgets/ProfileList.qml
index 8e8db340..f039416f 100644
--- a/qml/widgets/ProfileList.qml
+++ b/qml/widgets/ProfileList.qml
@@ -50,10 +50,12 @@ ColumnLayout {
}
}
- profilesModel.append({
+ profilesModel.insert(profilesModel.count-1,
+ {
"_handle": handle,
"_displayName": displayName,
- "_image": image
+ "_image": image,
+ "_type": "profile"
})
}
@@ -67,10 +69,27 @@ ColumnLayout {
}
}
}*/
+
+ onResetProfileList: function() {
+ profilesModel.clear()
+ profilesModel.append({
+ _handle: "",
+ _displayName: qsTr("add-new-profile-btn"),
+ _image: "qrc:/qml/images/fontawesome/solid/user-plus.svg",
+ _type: "button",
+ })
+ }
}
ListModel { // Profile OBJECTS ARE STORED HERE ...
id: profilesModel
+
+ ListElement {
+ _handle: ""
+ _displayName: qsTr("add-new-profile-btn")
+ _image: "qrc:/qml/images/fontawesome/solid/user-plus.svg"
+ _type: "button"
+ }
}
Repeater {
@@ -84,7 +103,7 @@ ColumnLayout {
status: 0
blocked: false
loading: false
- type: "profile"
+ type: _type
}
}
}
diff --git a/qml/widgets/StackToolbar.qml b/qml/widgets/StackToolbar.qml
index c3b917c0..3b9f91e5 100644
--- a/qml/widgets/StackToolbar.qml
+++ b/qml/widgets/StackToolbar.qml
@@ -21,6 +21,7 @@ Rectangle { // OVERHEAD BAR ON STACK PANE
property alias aux: btnAux
property alias back: btnBack
property alias membership: btnMembership
+ property string stack: "profile" // profile(theStack) or management(parentStack)
SimpleButton {// BACK BUTTON
@@ -29,7 +30,13 @@ Rectangle { // OVERHEAD BAR ON STACK PANE
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 6
- onClicked: theStack.pane = theStack.emptyPane
+ onClicked: {
+ if (stack == "profile") {
+ theStack.pane = theStack.emptyPane
+ } else {
+ parentStack.pane = parentStack.managementPane
+ }
+ }
}
ScalingLabel { // TEXT