diff --git a/src/wizard/policies.cpp b/src/wizard/policies.cpp index 1652cbd6..ecd1e53f 100644 --- a/src/wizard/policies.cpp +++ b/src/wizard/policies.cpp @@ -1,92 +1,93 @@ /************************************************************************************ * Copyright (C) 2019 by BlueSystems GmbH * * Author : Emmanuel Lepage Vallee * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * ***********************************************************************************/ #include "policies.h" // LibRingQt #include #include // JamiKDEIntegration #include "../jamikdeintegration/kcfg_settings.h" //FIXME export this #include "../jamikdeintegration/src/windowevent.h" //FIXME export this // If there's more than 1 instance, this is worth fixing. static enum { UNDECIDED, DISCARDED, YES, NO, } s_DisplayWizard; class WizardPoliciesWatcher : public QObject { Q_OBJECT public: public Q_SLOTS: void slotAccountAdded(); }; WizardPolicies::WizardPolicies(QObject* parent) : QObject(parent) {} WizardPolicies::~WizardPolicies() { } bool WizardPolicies::displayWizard() { + return true; static bool dw = ConfigurationSkeleton::enableWizard() || ConfigurationSkeleton::showSplash(); const bool dos = ConfigurationSkeleton::displayOnStart() && !WindowEvent::instance()->startIconified(); // The first run wizard if (dos && dw) { if (dw && !Session::instance()->accountModel()->size()) { WindowEvent::instance()->showWizard(); s_DisplayWizard = YES; } else s_DisplayWizard = NO; // ConfigurationSkeleton::setEnableWizard(false); emit changed(); } return s_DisplayWizard == YES; } void WizardPolicies::setWizardFinished(bool f) { s_DisplayWizard = f ? DISCARDED : UNDECIDED; emit changed(); } void WizardPoliciesWatcher::slotAccountAdded() { // } #include diff --git a/src/wizard/qml/buttonBar.qml b/src/wizard/qml/buttonBar.qml index 45cda3d6..c34b3479 100644 --- a/src/wizard/qml/buttonBar.qml +++ b/src/wizard/qml/buttonBar.qml @@ -1,174 +1,175 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * **************************************************************************/ import QtQuick 2.0 import QtQuick.Controls 2.0 as Controls import QtQuick.Layouts 1.3 Item { id: buttonBar property alias backButton: backButton property alias nextButton: nextButton property alias skipButton: skipButton property bool displayBusy: false Rectangle { id: rectangle color: "#0886a0" anchors.fill: parent // Left buttons RowLayout { anchors.fill: parent // The kirigami handle Item { width: 40 } // Align left Controls.Button { id: backButton Layout.fillHeight: true text: i18n("Back") //visible: false //FIXME } Item { Layout.fillWidth: true } // Align right Controls.BusyIndicator { id: busyIndicator visible: false Layout.fillHeight: true } Controls.Label { id: missingFields text: i18n("Please fill the required fields") verticalAlignment: Text.AlignVCenter - color: "red" + color: "#ff1111" + font.bold: true visible: true Layout.fillHeight: true } Controls.Button { id: nextButton Layout.fillHeight: true text: i18n("Next") visible: false } Controls.Button { id: skipButton Layout.fillHeight: true text: i18n("Skip") } } } states: [ State { name: "shown" PropertyChanges { target: buttonBar visible: true y: buttonBar.parent.height - buttonBar.height state: "nextAvailable" } }, State { name: "locked" PropertyChanges { target: buttonBar anchors.right: buttonBar.parent.right anchors.left: buttonBar.parent.left anchors.bottom: buttonBar.parent.bottom anchors.leftMargin: 0 visible: true } }, State { name: "firstStep" PropertyChanges { target: backButton visible: false } }, State { name: "busy" extend: "locked" PropertyChanges { target: missingFields text: i18n("Please wait") } PropertyChanges { target: busyIndicator visible: true } }, State { name: "nextAvailable" extend: "locked" PropertyChanges { target: nextButton visible: true } PropertyChanges { target: missingFields visible: false } }, State { name: i18n("finish") extend: "nextAvailable" PropertyChanges { target: skipButton visible: false } PropertyChanges { target: nextButton text: "Finish" } } ] /*transitions: [ Transition { from: "*"; to: "shown" // Slide-in the new account form NumberAnimation { target: buttonBar easing.type: Easing.OutQuad properties: "y"; duration: 700 } } ]*/ } diff --git a/src/wizard/qml/createRing.qml b/src/wizard/qml/createRing.qml index be82b4e9..a838e8b1 100644 --- a/src/wizard/qml/createRing.qml +++ b/src/wizard/qml/createRing.qml @@ -1,474 +1,301 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * **************************************************************************/ import QtQuick 2.9 -import QtQuick.Controls 2.0 as Controls +import QtQuick.Controls 2.2 as Controls import QtQuick.Layouts 1.0 +import org.kde.kirigami 2.2 as Kirigami import net.lvindustries.ringqtquick 1.0 as RingQtQuick Item { id: createRing property alias registerUserName: registerUserName + property alias account: ringAccountBuilder.account + property alias nextAvailable: ringAccountBuilder.canCreate - property bool nextAvailable: false property bool busy: false property var lookupState: 2 - property var account: null - signal registrationCompleted(QtObject account) width: Math.min(createForm.implicitWidth, parent.width - 20) height: createForm.implicitHeight - function isNextAvailable() { - nextAvailable = (userName.text.length > 2 || !registerUserName.checked) - && (password.text.length > 0) - && (password.text == repeatPassword.text) - && (lookupState == 2 || !registerUserName.checked) + function createAccount() { + ringAccountBuilder.create() } - function performLookup() { - if (userName.text != "" && userName.text.length > 2 && registerUserName.checked) { - registerFoundLabel.text = i18n("Please enter an username") - registerFoundLabel.color = "white" - createRing.lookupState = 2 - NameDirectory.lookupName(undefined, "", userName.text) - } - else - createRing.lookupState = 2 + function commitAccount() { + ringAccountBuilder.commit() } - function createAccount() { - if (!nextAvailable) { - console.log("Account creation failed: missing fields") - return; + /** + * Business logic and validation logic + */ + RingQtQuick.RingAccountBuilder { + id: ringAccountBuilder + registerRingName : registerUserName.checked + registeredRingName: userName.text + repeatPassword : repeatPasswordTxt.text + password : passwordTxt.text + usePassword : usePassword.checked + onFinished: { + registrationCompleted(account) + console.log("\n\nCOMMIT") } - - // Prevent trigger happy people from DDOSing the daemon with entropy - // starvation - nextAvailable = false - busy = true - - // Display the progress popup - state = "registrationResult" - registrationTimeout.running = true - - // The alias is not selected by the profile (if necessary) - var name = userName.text - - // Make sure they are unique - name = name + RingSession.accountModel.getSimilarAliasIndex(name) - - account = RingSession.accountModel.add(name, RingQtQuick.Account.RING); - account.displayName = name - account.archivePassword = password.text - account.upnpEnabled = true; - - account.performAction(RingQtQuick.Account.SAVE) - account.performAction(RingQtQuick.Account.RELOAD) - console.log("Account creation in progress") } ColumnLayout { id: createForm - anchors.fill: parent + width: parent.width Controls.Switch { id: registerUserName height: 40 - text: i18n("Register public username*") - checked: true + text: i18n("Register a public username*") opacity: 1 Layout.fillWidth: true - onCheckedChanged: { - performLookup() - isNextAvailable() - } + checked: true//ringAccountBuilder.registerRingName //FIXME race contentItem: Text { text: registerUserName.text font: registerUserName.font color: "white" verticalAlignment: Text.AlignVCenter leftPadding: registerUserName.indicator.width + registerUserName.spacing } } Controls.Label { id: label2 - clip: true - x: -7 - y: 170 - height: 14 + opacity: ringAccountBuilder.registerRingName ? 1 : 0 text: i18n("Enter an username") color: "white" anchors.leftMargin: 8 Layout.fillWidth: true - - /*Behavior on Layout.maximumHeight { + Behavior on opacity { NumberAnimation { easing.type: Easing.OutQuad - duration: 500 + duration: 200 } - }*/ + } } Controls.TextField { id: userName - clip: true - x: 8 - y: 74 - height: 40 color: "white" Layout.fillWidth: true - - onTextChanged: { - performLookup() - - busyIndicator.visible = userName.text != "" - isNextAvailable() + opacity: ringAccountBuilder.registerRingName ? 1 : 0 + enabled: ringAccountBuilder.registerRingName + Behavior on opacity { + NumberAnimation { + easing.type: Easing.OutQuad + duration: 200 + } } } RowLayout { id: rowLayout clip: true Layout.fillHeight: false Layout.maximumHeight: 37 Layout.fillWidth: true - visible: registerUserName.checked + opacity: ringAccountBuilder.registerRingName ? 1 : 0 spacing: 6 Item { width: 37 height: 37 Layout.fillHeight: true Layout.preferredWidth: 37 Controls.BusyIndicator { id: busyIndicator anchors.fill: parent - visible: false - } - - Image { - id: image - anchors.fill: parent + visible: ringAccountBuilder.nameLookup } } Controls.Label { id: registerFoundLabel - text: i18n("Please enter an username") + text: ringAccountBuilder.nameStatusMessage verticalAlignment: Text.AlignVCenter - color: "white" + color: ringAccountBuilder.nameLookupError ? "#ff1111" : ( + ringAccountBuilder.nameStatus == RingQtQuick.NameDirectory.NOT_FOUND ? + "#66ff66" : "white" + ) + font.bold: ringAccountBuilder.nameLookupError || ( + ringAccountBuilder.nameStatus == RingQtQuick.NameDirectory.NOT_FOUND + ) Layout.fillHeight: true Layout.fillWidth: true + Behavior on color { + ColorAnimation {duration: 100} + } } + } - /*Behavior on Layout.maximumHeight { - NumberAnimation { - easing.type: Easing.OutQuad - duration: 500 - } - }*/ + Controls.Switch { + id: usePassword + text: i18n("Protect your crypto keys with a password") + opacity: 1 + enabled: !ringAccountBuilder.registerRingName + Layout.fillWidth: true + checked: ringAccountBuilder.usePassword + contentItem: Text { + text: usePassword.text + font: usePassword.font + color: "white" + verticalAlignment: Text.AlignVCenter + leftPadding: usePassword.indicator.width + usePassword.spacing + } } Controls.Label { id: label1 text: i18n("Enter an archive password") + opacity: ringAccountBuilder.usePassword ? 1 : 0 + enabled: ringAccountBuilder.usePassword color: "white" Layout.fillWidth: true anchors.leftMargin: 8 + Behavior on opacity { + NumberAnimation { + easing.type: Easing.OutQuad + duration: 200 + } + } } Controls.TextField { - id: password + id: passwordTxt echoMode: "Password" + opacity: ringAccountBuilder.usePassword ? 1 : 0 + enabled: ringAccountBuilder.usePassword + text: ringAccountBuilder.password Layout.fillWidth: true color: "white" - onTextChanged: isNextAvailable() + Behavior on opacity { + NumberAnimation { + easing.type: Easing.OutQuad + duration: 200 + } + } } Controls.Label { id: label color: "white" + opacity: ringAccountBuilder.usePassword ? 1 : 0 + enabled: ringAccountBuilder.usePassword text: i18n("Repeat the new password") Layout.fillWidth: true anchors.leftMargin: 8 + Behavior on opacity { + NumberAnimation { + easing.type: Easing.OutQuad + duration: 200 + } + } } Controls.TextField { - id: repeatPassword + id: repeatPasswordTxt echoMode: "Password" + opacity: ringAccountBuilder.usePassword ? 1 : 0 + enabled: ringAccountBuilder.usePassword Layout.fillWidth: true + text: ringAccountBuilder.repeatPassword color: "white" - onTextChanged: isNextAvailable() + Behavior on opacity { + NumberAnimation { + easing.type: Easing.OutQuad + duration: 200 + } + } } Controls.Label { id: label4 - color: "red" + color: "#ff1111" + font.bold: true text: i18n("Passwords don't match") verticalAlignment: Text.AlignVCenter Layout.fillHeight: true Layout.fillWidth: true - opacity: 0 - - // Only show when the passwords mismatch - states: [ - State - { - name: "invisible" - when: repeatPassword.text != password.text - PropertyChanges { - target: label4 - opacity: 1 - } - } - ] + opacity: ringAccountBuilder.passwordMatch ? 0 : 1 Behavior on opacity { NumberAnimation { easing.type: Easing.OutQuad duration: 200 } } } Item { - height: 10 + height: Kirigami.Units.largeSpacing Layout.fillWidth: true } Controls.Label { id: labelInfo color: "white" text: i18n("(*) registered usernames can be reached by their username-string instead of their generated ring-id number only.") Layout.fillWidth: true wrapMode: Text.WordWrap } Rectangle { Layout.fillHeight: true } } - Rectangle { + Rectangle{ id: registrationPopup - width: popupLayout.implicitWidth + 50 + + width: Math.min(applicationWindow.width*0.8, implicitWidth + 50) height: popupLayout.implicitHeight + 10 - color: "#eeeeee" - visible: false - z: 200 anchors.centerIn: createRing + color: "#0886a0" + + visible: ringAccountBuilder.creating + z: 200 RowLayout { id: popupLayout anchors.verticalCenter: parent.verticalCenter Controls.BusyIndicator { id: registrationIndicator Layout.fillHeight: false + visible: ringAccountBuilder.creating } Controls.Label { id: registrationStatus - text: i18n("Creating account") - Layout.fillHeight: false + text: ringAccountBuilder.creationStatusMessage + wrapMode: Text.WordWrap + verticalAlignment: Text.AlignVCenter + Layout.fillHeight: true Layout.fillWidth: true color: "black" } } } - - // Hide the error message after a second - Timer { - id: hidePopup - repeat: false - running: false - interval: 5000 - onTriggered: { - registrationPopup.visible = false - } - } - - // Remove the popup after 30 seconds if it didn't finish by then - Timer { - id: registrationTimeout - repeat: false - interval: 120000 - running: false - onTriggered: { - registrationPopup.color = "red" - registerFoundLabel.text = i18n("Timeout") - hidePopup.running = true - nextAvailable = true - busy = false - } - } - - states: [ - State { - name: "noRegister" - when: !registerUserName.checked - - PropertyChanges { - target: label2 - Layout.maximumHeight: 0 - opacity: 0 - } - - PropertyChanges { - target: label - padding: 0 - } - }, - State { - name: "registrationResult" - - PropertyChanges { - target: registrationPopup - visible: true - } - } - ] - - /*transitions: Transition { - NumberAnimation { - properties: "opacity" - easing.type: Easing.OutQuad - duration: 500 - onStopped: { - label2.visible = false - userName.visible = false - rowLayout.visible = false - } - } - }*/ - - // After each username field change, check availability - Connections { - target: RingSession.nameDirectory - onRegisteredNameFound: { - // Race conditions - if (userName.text != name) - return; - - createRing.lookupState = status - - busyIndicator.visible = false - if (status == 2) { //NameDirectory.NOT_FOUND - registerFoundLabel.text = i18n("The username is available") - registerFoundLabel.color = "green" - } - else if (status == 1 || name == "") { - registerFoundLabel.text = i18n("Please enter an username (3 characters minimum)") - registerFoundLabel.color = "white" - nextAvailable = false - } - else if (status == 3) { - registerFoundLabel.text = i18n("The registered name lookup failed, ignoring") - nextAvailable = true - } - else { - registerFoundLabel.text = i18n("The username is not available") - registerFoundLabel.color = "red" - nextAvailable = false - } - isNextAvailable() - } - } - - Connections { - target: NameDirectory - onNameRegistrationEnded: { - registrationTimeout.stop() - - if (status == 0) - registrationPopup.color = "green" - else { - registrationPopup.color = "red" - hidePopup.running = true - } - - registrationIndicator.visible = false - - switch(status) { - case 0: //SUCCESS - registrationStatus.text = i18n("Success") - busy = false - account.performAction(RingQtQuick.Account.RELOAD) - account.performAction(RingQtQuick.Account.SAVE) - RingSession.accountModel.save() - createRing.registrationCompleted(account) - break - case 1: //WRONG_PASSWORD - registrationStatus.text = i18n("Password mismatch") - break - case 2: //INVALID_NAME - registrationStatus.text = i18n("Invalid name") - break - case 3: //ALREADY_TAKEN - registrationStatus.text = i18n("Already taken") - break - case 4: //NETWORK_ERROR - registrationStatus.text = i18n("Network error") - break - } - } - } - - Connections { - target: account - onStateChanged: { - // Assume UNREGISTERED accounts are ok, otherwise it will have - // false negatives - if (state == RingQtQuick.Account.READY || state == RingQtQuick.Account.UNREGISTERED) { - if (registerUserName.checked) { - if (account.registerName(password.text, account.displayName)) { - registrationStatus.text = i18n("Registration") - registrationTimeout.stop() - } - else { - registrationPopup.color = "red" - registrationStatus.text = i18n("Can't register") - registrationTimeout.stop() - } - } - else { - registrationTimeout.stop() - registrationIndicator.visible = false - busy = false - account.performAction(RingQtQuick.Account.RELOAD) - account.performAction(RingQtQuick.Account.SAVE) - RingSession.accountModel.save() - createRing.registrationCompleted(account) - } - account = null - } - else if (state == RingQtQuick.Account.ERROR) { - console.log("The account creation failed with an invalid state:", - account.lastErrorMessage) - } - else { - console.log("The wizard account creation has state:", state) - } - } - } } diff --git a/src/wizard/qml/profilePage.ui.qml b/src/wizard/qml/profilePage.ui.qml deleted file mode 100644 index 378727bb..00000000 --- a/src/wizard/qml/profilePage.ui.qml +++ /dev/null @@ -1,25 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2017 by Bluesystems * - * Author : Emmanuel Lepage Vallee * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 3 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - **************************************************************************/ -import QtQuick 2.0 -import QtQuick.Controls 2.0 -import QtQuick.Layouts 1.0 - -Item { - id: item1 - -} diff --git a/src/wizard/qml/startPage.qml b/src/wizard/qml/startPage.qml index fd2c47e1..ad83c7d8 100644 --- a/src/wizard/qml/startPage.qml +++ b/src/wizard/qml/startPage.qml @@ -1,95 +1,96 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * **************************************************************************/ import QtQuick 2.7 import org.kde.ringkde.jamiwizard 1.0 as JamiWizard JamiWizard.StartPageUI { anchors.fill: parent property bool nextAvailable: false property bool busy: false // Let the pretty little animation run its course Timer { id: createAccountTimer interval: 1000 running: false repeat: false onTriggered: { stateGroup.state = "createRegRing"; } } Timer { id: importAccountTimer interval: 1000 running: false repeat: false onTriggered: { stateGroup.state = "importRing"; } } importRingAccount.onClicked: { // This will move the current buttons out and the fields in removeAnchors() importAccountTimer.running = true } createRingAccount.onClicked: { // This will move the current buttons out and the fields in removeAnchors() + createRing.createAccount() createAccountTimer.running = true } createRing.onNextAvailableChanged: isNextAvailable() importRing.onNextAvailableChanged: isNextAvailable() createRing.onBusyChanged: { busy = createRing.busy } function isNextAvailable() { switch(state) { case 'createRegRing': nextAvailable = createRing.nextAvailable break case 'importRing': nextAvailable = importRing.nextAvailable break case 'showProfile': nextAvailable = true break; } } function removeAnchors() { // Remove the anchors from the buttons so they can be animated freely var widgets = [ createRingAccount, welcomeMessage, createIp2IPAccount, logo, importRingAccount, importSIPAccount ]; for (var i = 0, len = widgets.length; i < len; i++) { widgets[i].x = parent.x - (widgets[i].width/2); widgets[i].anchors.horizontalCenter = undefined; } stateGroup.state = "hideAccountTypes"; } } diff --git a/src/wizard/qml/startPage.ui.qml b/src/wizard/qml/startPage.ui.qml index 78da055b..2cd649ff 100644 --- a/src/wizard/qml/startPage.ui.qml +++ b/src/wizard/qml/startPage.ui.qml @@ -1,127 +1,128 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * **************************************************************************/ import QtQuick 2.7 import QtQuick.Controls 2.0 as Controls import org.kde.ringkde.jamiwizard 1.0 as JamiWizard Controls.Page { id: frontPage Rectangle { anchors.fill: parent x: -1 color: "#004d61" } property alias importRingAccount: importRingAccount property alias createRingAccount: createRingAccount property alias createAnonRingAccount: createAnonRingAccount property alias importSIPAccount: importSIPAccount property alias createIp2IPAccount: createIp2IPAccount property alias createRing: createRing property alias importRing: importRing property alias profilePage: profilePage property alias welcomeMessage: text1 property alias logo: image Text { id: text1 anchors.horizontalCenter: parent.horizontalCenter y: 149 width: Math.min(423, frontPage.width - 114) height: 86 text: i18n("Welcome to Ring-KDE. Before you can contact your friend, you have to have an account. Don't worry, creating one is easy and doesn't require sharing any personal information. If you are in an office or your phone service provider offers a SIP account, you can also configure Ring-KDE to take your \"real\" phone calls.") wrapMode: Text.WordWrap font.pixelSize: 12 color: "white" } Controls.Button { id: createRingAccount anchors.horizontalCenter: parent.horizontalCenter y: 246 text: i18n("Create a new GNU Ring account") } Controls.Button { id: importRingAccount anchors.horizontalCenter: parent.horizontalCenter y: 300 text: i18n("Import an existing account") } Controls.Button { id: createAnonRingAccount anchors.horizontalCenter: parent.horizontalCenter y: 354 text: i18n("Use an anonymous account") visible: false } Controls.Button { id: importSIPAccount anchors.horizontalCenter: parent.horizontalCenter y: 408 text: i18n("Import a SIP account") visible: false } Controls.Button { id: createIp2IPAccount anchors.horizontalCenter: parent.horizontalCenter y: 462 text: i18n("Use on local network") visible: false } Image { id: image anchors.horizontalCenter: parent.horizontalCenter y: 43 width: 100 height: 100 source: "qrc:/wizard/ring-kde.svg" } JamiWizard.CreateRing { id: createRing - x: frontPage.width/2 - width/2 - 20 - y: frontPage.height/2 - height/2 - anchors.centerIn: frontPage + anchors.top: parent.top + anchors.topMargin: 120 //the logo height is 100 + anchors.bottomMargin: footer.height + 10 + anchors.horizontalCenter: parent.horizontalCenter opacity: 0 visible: false } JamiWizard.ImportRing { id: importRing opacity: 0 visible: false width: logo.width + text1.width x: frontPage.width/2 - width/2 - 20 y: frontPage.height/2 - height/2 } JamiWizard.ProfilePage { id: profilePage visible: false y: text1.height + 8 height: parent.height - text1.height - 8 -45/*footer.height*/ width: parent.width anchors.bottomMargin: 45/*footer.height*/ anchors.topMargin: 12 } } diff --git a/src/wizard/qml/wizard.qml b/src/wizard/qml/wizard.qml index 49829983..d52ae89b 100644 --- a/src/wizard/qml/wizard.qml +++ b/src/wizard/qml/wizard.qml @@ -1,410 +1,410 @@ /*************************************************************************** * Copyright (C) 2017 by Bluesystems * * Author : Emmanuel Lepage Vallee * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * **************************************************************************/ import QtQuick 2.7 import net.lvindustries.ringqtquick 1.0 as RingQtQuick import org.kde.ringkde.jamiwizard 1.0 as JamiWizard Rectangle { id: applicationWindow visible: true color: "#004d61" property string previousState: "" signal wizardFinished() JamiWizard.Splash { id: startingPage anchors.fill: parent anchors.bottomMargin: footer.height z: 2 onVisibleChanged: { if (!visible) { // Force the geometry while the animation is running, anchor it after footer.y = applicationWindow.height + footer.height // Begin the first animation /*ANIM footer.state = "shown"*/ footer.state = "shown" } } onQuit: { applicationWindow.visible = false } } JamiWizard.StartPage { id: frontPage anchors.fill: parent anchors.bottomMargin: footer.height visible: true } JamiWizard.ButtonBar { id: footer height: 45 width: applicationWindow.width visible: false } onWidthChanged: { //HACK footer.width = width } // Display or hide the "next/finish" button in the bar Connections { target: frontPage onNextAvailableChanged: { footer.state = frontPage.nextAvailable ? "nextAvailable" : ( frontPage.busy ? "busy" : "locked" ) } } // Use a better label when next is unavailable because it's busy Connections { target: frontPage onBusyChanged: { footer.state = frontPage.nextAvailable ? "nextAvailable" : ( frontPage.busy ? "busy" : "locked" ) } } // Close the wizard and let the user configure things manually Connections { target: footer.skipButton onClicked: { wizardFinished() } } // Try to restore the previous page Connections { target: footer.backButton onClicked: { var oldPreviousState = previousState previousState = stateGroup.state switch (stateGroup.state) { case 'createRegRing': case 'importRing': stateGroup.state = "*" break; case 'showProfile': previousState = "*" footer.state = "nextUnavailable" //FIXME stateGroup.state = oldPreviousState break; } } } // Show the profile configuration Connections { target: footer.nextButton onClicked: { switch (stateGroup.state) { case 'createRegRing': - frontPage.createRing.createAccount() + frontPage.createRing.commitAccount() break; case 'importRing': frontPage.importRing.createAccount() break; case '*': stateGroup.state = "*" stateGroup.state = "showProfile" footer.state = "finish" break; case 'showProfile': var acc = frontPage.createRing.account if (acc && acc.alias == "") frontPage.createRing.account.alias = frontPage.createRing.account.profile.formattedName frontPage.profilePage.save() wizardFinished() break; } } } Connections { target: frontPage.createRing onRegistrationCompleted: { stateGroup.state = "showProfile" footer.state = "finish" account.createProfile() frontPage.profilePage.individual = account.profile.individual } onAccountChanged: { var acc = frontPage.createRing.account - if ((!acc) || cc.registrationType != RingQtQuick.Account.READY) + if ((!acc) || acc.registrationType != RingQtQuick.Account.READY) return if (!acc.profile) acc.createProfile() //frontPage.profilePage.currentPerson = acc.profile frontPage.profilePage.individual = acc.profile.individual } } Connections { target: frontPage.importRing onRegistrationCompleted: { stateGroup.state = "showProfile" footer.state = "finish" } onAccountChanged: { var acc = frontPage.importRing.account if (!acc) return frontPage.profilePage.currentPerson = acc.profile } } StateGroup { id: stateGroup states: [ // Hide all buttons State { name: "hideAccountTypes" PropertyChanges { target: frontPage.createRingAccount x: -436 y: 322 anchors.horizontalCenter: undefined opacity: 0 } PropertyChanges { target: frontPage.createAnonRingAccount x: 836 y: -322 anchors.horizontalCenter: undefined opacity: 0 } PropertyChanges { target: frontPage.importRingAccount x: -383 y: 575 opacity: 0 } PropertyChanges { target: frontPage.importSIPAccount x: 771 y: 439 opacity: 0 text: i18n("Import a SIP account") } PropertyChanges { target: frontPage.createIp2IPAccount x: 771 y: 96 opacity: 0 } PropertyChanges { target: frontPage.logo x: applicationWindow.width/2 - frontPage.welcomeMessage.width/2 y: 8 } PropertyChanges { target: frontPage.welcomeMessage x: applicationWindow.width/2 - 114/2 y: 8 } }, // Create a new Ring account State { name: "createRegRing" extend: "hideAccountTypes" PropertyChanges { target: frontPage state: "createRegRing" } PropertyChanges { target: frontPage.createRing opacity: 1 visible: true // Use raw [x,y] to avoid following the animation x: frontPage.width/2 - width/2 } }, // Import an existing account from another device State { name: "importRing" extend: "hideAccountTypes" PropertyChanges { target: frontPage state: "importRing" } PropertyChanges { target: frontPage.importRing opacity: 1 visible: true // Use raw [x,y] to avoid following the animation x: frontPage.width/2 - width/2 } }, // Last page, the shared profile information State { name: "showProfile" extend: "hideAccountTypes" PropertyChanges { target: frontPage state: "showProfile" } PropertyChanges { target: frontPage.profilePage opacity: 1 visible: true } PropertyChanges { target: frontPage.importRing opacity: 0 visible: false } PropertyChanges { target: frontPage.createRing opacity: 0 visible: false } } ] transitions: [ Transition { from: "*"; to: "hideAccountTypes" NumberAnimation { targets: [ frontPage.importRingAccount, frontPage.importSIPAccount, frontPage.createIp2IPAccount, frontPage.createRingAccount, frontPage.createAnonRingAccount, frontPage.logo, frontPage.welcomeMessage ] easing.type: Easing.OutBounce properties: "x,y"; duration: 1000 } // Fade-out the irrelevant buttons NumberAnimation { targets: [ frontPage.importRingAccount, frontPage.importSIPAccount, frontPage.createIp2IPAccount, frontPage.createRingAccount, frontPage.createAnonRingAccount, frontPage.logo, frontPage.welcomeMessage ] easing.type: Easing.Linear properties: "opacity"; duration: 500 onStopped: { importRingAccount.visible = false; importSIPAccount.visible = false; createIp2IPAccount.visible = false; createRingAccount.visible = false; createAnonRingAccount.visible = false; } } }, // TO DIALOG Transition { from: "hideAccountTypes"; to: "createRegRing" // Slide-in the new account form NumberAnimation { target: frontPage.createRing easing.type: Easing.OutQuad properties: "x,opacity"; duration: 700 } }, Transition { from: "hideAccountTypes"; to: "importRing" // Slide-in the new account form NumberAnimation { target: frontPage.importRing easing.type: Easing.OutQuad properties: "x,opacity"; duration: 700 } }, // BACK TO FIRST PAGE Transition { from: "createRegRing"; to: "*" // Slide-in the new account form NumberAnimation { target: frontPage.createRing easing.type: Easing.OutQuad properties: "x,opacity"; duration: 700 } }, Transition { from: "importRing"; to: "*" // Slide-in the new account form NumberAnimation { target: frontPage.importRing easing.type: Easing.OutQuad properties: "x,opacity"; duration: 700 } } ] } } diff --git a/views/basic/qml/basic.qml b/views/basic/qml/basic.qml index 2f79677f..ed5e261a 100644 --- a/views/basic/qml/basic.qml +++ b/views/basic/qml/basic.qml @@ -1,216 +1,216 @@ /* * Copyright 2018 Fabian Riethmayer * Copyright 2019 Emmanuel Lepage * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 3, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.6 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.2 import org.kde.kirigami 2.6 as Kirigami import net.lvindustries.ringqtquick.media 1.0 as RingQtMedia import net.lvindustries.ringqtquick 1.0 as RingQtQuick import org.kde.ringkde.basicview 1.0 as BasicView import org.kde.ringkde.jamicontactview 1.0 as JamiContactView import org.kde.ringkde.jamiwizard 1.0 as JamiWizard import org.kde.ringkde.jamikdeintegration 1.0 as JamiKDEIntegration import QtQuick.Controls.Material 2.3 Kirigami.ApplicationWindow { - width: 320 - height: 600 + width: 1024 + height: 768 id: root // Localization is currently broken with the Material theme function i18n(t) {return t;} function showCallPage() { callpage.visible = true if (pageStack.currentItem == callpage) return showChat() for (var i = 0; i < pageStack.depth; i++) { if (pageStack.get(i) == callpage) { pageStack.currentIndex = i return } } pageStack.push(callpage) } function hideCall() { for (var i = 0; i < pageStack.depth; i++) { if (pageStack.get(i) == callpage) { pageStack.pop(callpage) pageStack.currentIndex = 0 return } } } function showChat() { if (pageStack.currentItem == callpage) return for (var i = 0; i < pageStack.depth; i++) { if (pageStack.get(i) == chat) { pageStack.currentIndex = 1 return } } pageStack.push(chat) pageStack.currentIndex = 1 } // Check the network status and other sources to ensure actions *can* work RingQtMedia.AvailabilityTracker { id: availabilityTracker individual: mainPage.currentIndividual } // Allows to free resources when viewing other individuals RingQtQuick.SharedModelLocker { id: mainPage onCallChanged: { if (!call) hideCall() else showCallPage() } onIndividualChanged: { list.currentIndex = RingSession.peersTimelineModel.individualIndex( currentIndividual ).row } } BasicView.ActionCollection { id: actionCollection } BasicView.Contacts { id : mydata Component.onCompleted: { chat.model = mydata.get(3) } } pageStack.initialPage: [list, chat] pageStack.globalToolBar.style: Kirigami.ApplicationHeaderStyle.ToolBar pageStack.globalToolBar.preferredHeight: Kirigami.Units.gridUnit * 3 pageStack.defaultColumnWidth: root.width < 320 ? root.width : 320 BasicView.ListPage { id: list } BasicView.ChatPage { id: chat } BasicView.CallPage { id: callpage visible: false } contextDrawer: Kirigami.ContextDrawer { id: contextDrawer } globalDrawer: BasicView.GlobalDrawer { id: globalDrawer } JamiKDEIntegration.WindowEvent { id: events onRequestsConfigureAccounts: { var component = Qt.createComponent("qrc:/account/qml/accountdialog.qml") if (component.status == Component.Ready) { var window = component.createObject(applicationWindow().contentItem) window.open() } else console.log("ERROR", component.status, component.errorString()) } onRequestsHideWindow: { hide() } onRequestsWizard: { globalDrawer.drawerOpen = false wizardLoader.visible = true wizardLoader.active = true } } /** * Display the wizard when all accounts are deleted. */ JamiWizard.Policies { id: wizardPolicies } Loader { id: wizardLoader active: false anchors.fill: parent z: 999999 onActiveChanged: { if ( list.displayWelcome && !active) list.search() } sourceComponent: JamiWizard.Wizard { anchors.fill: parent z: 999999 onVisibleChanged: { if (!visible) { wizardLoader.visible = false wizardLoader.active = false } } onWizardFinished: { wizardLoader.active = false list.search() } } } Timer { interval: 0 running: true repeat: false onTriggered: { if (wizardPolicies.displayWizard) wizardLoader.active = true else if (list.displayWelcome) list.search() } } }