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 - + copy-btn Button for copying profile onion address to clipboard Kopieren - + copied-clipboard-notification Copied to clipboard in die Zwischenablage kopiert - + new-group-btn create new group button Neue Gruppe anlegen - + paste-address-to-add-contact ex: "... paste an address here to add a contact ..." Adresse hier hinzufügen, um einen Kontakt aufzunehmen @@ -273,6 +273,91 @@ löschen + + ProfileAddEditPane + + + add-profile-title + + + + + edit-profile-title + + + + + profile-name + Profile name + + + + + + default-profile-name + default suggested profile name + + + + + profile-onion-label + Profile Onion + + + + + password1-label + Password + + + + + password2-label + Reenter password + + + + + create-profile-btn + Create Profile || Save Profile + + + + + save-profile-btn + + + + + password-error-match + Passwords do not match + + + + + delete-profile-btn + Delete Profile + + + + + delete-confirm-label + Type DELETE to confirm + + + + + delete-profile-confirm-btn + Really Delete Profile + + + + + delete-confirm-text + DELETE + + + ProfileManagerPane @@ -339,7 +424,7 @@ StackToolbar - + view-group-membership-tooltip 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 - + copy-btn Button for copying profile onion address to clipboard Copy - + copied-clipboard-notification Copied to clipboard Copied to clipboard - + new-group-btn create new group button Create new group - + paste-address-to-add-contact ex: "... paste an address here to add a contact ..." ... paste an address here to add a contact... @@ -273,6 +273,91 @@ Delete + + ProfileAddEditPane + + + add-profile-title + Add new profile + + + + edit-profile-title + Edit Profile + + + + profile-name + Profile name + Display name + + + + + default-profile-name + default suggested profile name + Alice + + + + profile-onion-label + Profile Onion + Onion + + + + password1-label + Password + Password + + + + password2-label + Reenter password + Password + + + + create-profile-btn + Create Profile || Save Profile + Create Profile + + + + save-profile-btn + Save Profile + + + + password-error-match + Passwords do not match + Passwords do not match + + + + delete-profile-btn + Delete Profile + Delete Profile + + + + delete-confirm-label + Type DELETE to confirm + Type DELETE to confirm + + + + delete-profile-confirm-btn + Really Delete Profile + Really Delete Profile + + + + delete-confirm-text + DELETE + DELETE + + ProfileManagerPane @@ -339,7 +424,7 @@ StackToolbar - + view-group-membership-tooltip 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 - + copy-btn Button for copying profile onion address to clipboard Copier - + copied-clipboard-notification Copied to clipboard Copié dans le presse-papier - + new-group-btn create new group button Créer un nouveau groupe - + paste-address-to-add-contact ex: "... paste an address here to add a contact ..." ... coller une adresse ici pour ajouter un contact... @@ -273,6 +273,91 @@ Effacer + + ProfileAddEditPane + + + add-profile-title + + + + + edit-profile-title + + + + + profile-name + Profile name + + + + + + default-profile-name + default suggested profile name + + + + + profile-onion-label + Profile Onion + + + + + password1-label + Password + + + + + password2-label + Reenter password + + + + + create-profile-btn + Create Profile || Save Profile + + + + + save-profile-btn + + + + + password-error-match + Passwords do not match + + + + + delete-profile-btn + Delete Profile + + + + + delete-confirm-label + Type DELETE to confirm + + + + + delete-profile-confirm-btn + Really Delete Profile + + + + + delete-confirm-text + DELETE + + + ProfileManagerPane @@ -339,7 +424,7 @@ StackToolbar - + view-group-membership-tooltip 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 - + copy-btn Button for copying profile onion address to clipboard Copiar - + copied-clipboard-notification Copied to clipboard Copiado - + new-group-btn create new group button Criar novo grupo - + paste-address-to-add-contact ex: "... paste an address here to add a contact ..." … cole um endereço aqui para adicionar um contato… @@ -273,6 +273,91 @@ Deletar + + ProfileAddEditPane + + + add-profile-title + + + + + edit-profile-title + + + + + profile-name + Profile name + + + + + + default-profile-name + default suggested profile name + + + + + profile-onion-label + Profile Onion + + + + + password1-label + Password + + + + + password2-label + Reenter password + + + + + create-profile-btn + Create Profile || Save Profile + + + + + save-profile-btn + + + + + password-error-match + Passwords do not match + + + + + delete-profile-btn + Delete Profile + + + + + delete-confirm-label + Type DELETE to confirm + + + + + delete-profile-confirm-btn + Really Delete Profile + + + + + delete-confirm-text + DELETE + + + ProfileManagerPane @@ -339,7 +424,7 @@ StackToolbar - + view-group-membership-tooltip 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