diff --git a/Messages.sh b/Messages.sh index 57687811..160fdcf7 100644 --- a/Messages.sh +++ b/Messages.sh @@ -1,3 +1,3 @@ $EXTRACTRC `find . -name \*.rc -o -name \*.ui -o -name \*.kcfg` >> rc.cpp -$XGETTEXT `find . -name \*.cc -o -name \*.cpp -o -name \*.h` -o $podir/ring-kde.pot +$XGETTEXT `find . -name \*.cc -o -name \*.cpp -o -name \*.h -o -name \*.qml` -o $podir/ring-kde.pot rm -rf rc.cpp diff --git a/src/callview/qml/callbackground.qml b/src/callview/qml/callbackground.qml index 911dbc84..09bcaf04 100644 --- a/src/callview/qml/callbackground.qml +++ b/src/callview/qml/callbackground.qml @@ -1,182 +1,182 @@ /*************************************************************************** * 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 RingQmlWidgets 1.0 import Ring 1.0 Rectangle { property QtObject call: null; property string mode: "PREVIEW" id: placeholderMessage color: "black" Text { id: defaultText color: "white" - text: qsTr("[No video]") + text: i18n("[No video]") anchors.centerIn: parent visible: false } NewCall { id: newCall visible: false anchors.centerIn: parent } Ringing { id: ringingIndicator anchors.centerIn: parent running: false visible: false } Searching { id: searchingIndicator anchors.centerIn: parent visible: false running: false } Progress { id: progresIndicator anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.bottom anchors.margins: 5 visible: false } Rectangle { id: callEnded radius: 5 color: "white" width: 100 height: 30 visible: false anchors.centerIn: parent Text { color: "black" text: "Call Ended" anchors.centerIn: parent } } onCallChanged: { if (call && (call.state == Call.RINGING || call.state == 1 /*Call.INCOMING*/)) callStateGroup.state = "RINGING" else if (call && (call.state == Call.CONNECTED || call.state == 14 /*Call.INITIALIZATION*/)) callStateGroup.state = "CONNECTED" else callStateGroup.state = "DEFAULT" lifecycleStateGroup.state = "INITIALIZATION" progresIndicator.call = call } Timer { id: clearNotifications interval: 3000 running: false repeat: false onTriggered: { if (call.lifeCycleState == Call.FINISHED) call = null } } StateGroup { id: callStateGroup states: [ State { name: "DEFAULT" when: !call PropertyChanges { target: defaultText visible: mode == "PREVIEW" } PropertyChanges { target: newCall visible: mode != "PREVIEW" } }, State { name: "RINGING" when: call && (call.state == Call.RINGING || call.state == 1 /*Call.INCOMING*/) PropertyChanges { target: ringingIndicator visible: true running: true } }, State { name: "CONNECTED" when: call && (call.state == Call.CONNECTED || call.state == 14 /*Call.INITIALIZATION*/) PropertyChanges { target: searchingIndicator visible: true running: true } }, State { name: "ENDED" when: call.lifeCycleState == Call.FINISHED PropertyChanges { target: callEnded visible: true } PropertyChanges { target: clearNotifications running: true } } ] } StateGroup { id: lifecycleStateGroup states: [ State { name: "CREATION" when: call.lifeCycleState == Call.CREATION PropertyChanges { target: progresIndicator visible: true } }, State { name: "INITIALIZATION" when: call.lifeCycleState == Call.INITIALIZATION PropertyChanges { target: progresIndicator visible: true } }, State { name: "PROGRESS" when: call.lifeCycleState == Call.PROGRESS }, State { name: "FINISHED" when: (!call) || call.lifeCycleState == Call.FINISHED } ] } } diff --git a/src/callview/qml/devicesetting.qml b/src/callview/qml/devicesetting.qml index 9d647096..313b5582 100644 --- a/src/callview/qml/devicesetting.qml +++ b/src/callview/qml/devicesetting.qml @@ -1,75 +1,75 @@ /*************************************************************************** * 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 import QtQuick.Layouts 1.0 import RingQmlWidgets 1.0 import Ring 1.0 GridLayout { property alias deviceSelectionModel : device.selectionModel property alias channelSelectionModel : channel.selectionModel property alias resolutionSelectionModel: resolution.selectionModel property alias rateSelectionModel : rate.selectionModel columns: 2 Text { color: "white" - text: qsTr("Device") + text: i18n("Device") } BindedComboBox { id: device Layout.fillWidth: true selectionModel: VideoDeviceSelectionModel } Text { color: "white" - text: qsTr("Channel") + text: i18n("Channel") } BindedComboBox { id: channel selectionModel: VideoChannelSelectionModel Layout.fillWidth: true } Text { color: "white" - text: qsTr("Resolution") + text: i18n("Resolution") } BindedComboBox { id: resolution selectionModel: VideoResolutionSelectionModel Layout.fillWidth: true } Text { color: "white" - text: qsTr("Frame rate") + text: i18n("Frame rate") } BindedComboBox { id: rate selectionModel: VideoRateSelectionModel Layout.fillWidth: true } //I got no idea why. If there is no extra row, the column width is wrong Item { Layout.fillHeight: true } } diff --git a/src/callview/qml/screensharing.qml b/src/callview/qml/screensharing.qml index 369cc154..2f356712 100644 --- a/src/callview/qml/screensharing.qml +++ b/src/callview/qml/screensharing.qml @@ -1,117 +1,117 @@ /*************************************************************************** * 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.Layouts 1.0 import RingQmlWidgets 1.0 import QtQuick.Controls 2.0 GridLayout { id: screenSharing property QtObject call: null columns: 2 Text { color: "white" - text: qsTr("Screen") + text: i18n("Screen") } ComboBox { id: screens Layout.fillWidth: true model: ["First", "Second", "Third"] } Text { color: "white" - text: qsTr("X offset") + text: i18n("X offset") } SpinBox { id: xOffset editable: true from: 0 to: 99999 } Text { color: "white" - text: qsTr("Y offset") + text: i18n("Y offset") } SpinBox { id: yOffset editable: true from: 0 to: 99999 } Text { color: "white" - text: qsTr("Width") + text: i18n("Width") } SpinBox { id: width editable: true from: 0 to: 99999 } Text { color: "white" - text: qsTr("Height") + text: i18n("Height") } SpinBox { id: height editable: true from: 0 to: 99999 } Item {} Item { Layout.fillHeight: true } Item {} Item { Layout.fillWidth: true height: shareButton.height Button { id: shareButton anchors.right: parent.right anchors.top: parent.top text: "Share" onClicked: { if (!screenSharing.call) return if (!screenSharing.call.sourceModel) return screenSharing.call.sourceModel.setDisplay( screens.currentIndex, Qt.rect( xOffset.value, yOffset.value, width.value, height.value ) ) } } } } diff --git a/src/timeline/qml/chatbox.qml b/src/timeline/qml/chatbox.qml index 330f9e5f..7165c23c 100644 --- a/src/timeline/qml/chatbox.qml +++ b/src/timeline/qml/chatbox.qml @@ -1,243 +1,243 @@ /*************************************************************************** * 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 import QtQuick.Layouts 1.0 import Ring 1.0 Rectangle { property QtObject call: null property alias textColor: messageTextArea.color property alias backgroundColor: chatBox.color property var emojiColor: undefined id: chatBox signal sendMessage(string message, string richMessage) color: "blue" SystemPalette { id: inactivePalette colorGroup: SystemPalette.Disabled } ListModel { id: emoji ListElement { symbol: "😀" } ListElement { symbol: "😁" } ListElement { symbol: "😂" } ListElement { symbol: "😃" } ListElement { symbol: "😄" } ListElement { symbol: "😅" } ListElement { symbol: "😆" } ListElement { symbol: "😇" } ListElement { symbol: "😈" } ListElement { symbol: "😉" } ListElement { symbol: "😊" } ListElement { symbol: "😋" } ListElement { symbol: "😌" } ListElement { symbol: "😍" } ListElement { symbol: "😎" } ListElement { symbol: "😏" } ListElement { symbol: "😐" } ListElement { symbol: "😑" } ListElement { symbol: "😒" } ListElement { symbol: "😓" } ListElement { symbol: "😔" } ListElement { symbol: "😕" } ListElement { symbol: "😖" } ListElement { symbol: "😗" } ListElement { symbol: "😘" } ListElement { symbol: "😙" } ListElement { symbol: "😚" } ListElement { symbol: "😛" } ListElement { symbol: "😜" } ListElement { symbol: "😝" } ListElement { symbol: "😞" } ListElement { symbol: "😟" } ListElement { symbol: "😠" } ListElement { symbol: "😡" } ListElement { symbol: "😢" } ListElement { symbol: "😣" } ListElement { symbol: "😤" } ListElement { symbol: "😥" } ListElement { symbol: "😦" } ListElement { symbol: "😧" } ListElement { symbol: "😨" } ListElement { symbol: "😩" } ListElement { symbol: "😪" } ListElement { symbol: "😫" } ListElement { symbol: "😬" } ListElement { symbol: "😭" } ListElement { symbol: "😮" } ListElement { symbol: "😯" } ListElement { symbol: "😰" } ListElement { symbol: "😱" } ListElement { symbol: "😲" } ListElement { symbol: "😳" } ListElement { symbol: "😴" } ListElement { symbol: "😵" } ListElement { symbol: "😶" } ListElement { symbol: "😷" } ListElement { symbol: "😸" } ListElement { symbol: "😹" } ListElement { symbol: "😺" } ListElement { symbol: "😻" } ListElement { symbol: "😼" } ListElement { symbol: "😽" } ListElement { symbol: "😾" } ListElement { symbol: "😿" } ListElement { symbol: "🙀" } ListElement { symbol: "🙁" } ListElement { symbol: "🙂" } ListElement { symbol: "🙃" } ListElement { symbol: "🙄" } ListElement { symbol: "🙅" } ListElement { symbol: "🙆" } ListElement { symbol: "🙇" } ListElement { symbol: "🙈" } ListElement { symbol: "🙉" } ListElement { symbol: "🙊" } ListElement { symbol: "🙋" } ListElement { symbol: "🙌" } ListElement { symbol: "🙍" } ListElement { symbol: "🙎" } ListElement { symbol: "🙏" } } Rectangle { id: emojiButton property bool checked: false opacity: 0 radius: 999 width: 30 height: 30 anchors.bottomMargin: -15 anchors.bottom: parent.top anchors.horizontalCenter: parent.horizontalCenter color: "transparent" border.width: 2 border.color: inactivePalette.text Text { anchors.centerIn: parent text: "😀" font.family: "Noto Color Emoji" font.pixelSize : 18 } MouseArea { anchors.fill: parent onClicked: { emojiButton.checked = !emojiButton.checked } } Behavior on opacity { NumberAnimation {duration: 100; easing.type: Easing.InQuad} } Behavior on anchors.bottomMargin { NumberAnimation {duration: 100; easing.type: Easing.InQuad} } states: [ State { name: "checked" when: emojiButton.checked PropertyChanges { target: emojiButton color: "#00AA00" } } ] } Grid { id: emojis visible: false anchors.fill: parent spacing: 2 rows: 2 Repeater { model: emoji Rectangle { width: 30 height: 30 color: emojiColor radius: 2 Text { anchors.centerIn: parent font.family: "Noto Color Emoji" font.pixelSize : 18 text: symbol } MouseArea { anchors.fill: parent onClicked: { messageTextArea.insert(messageTextArea.length, symbol) emojiButton.checked = false } } } } } RowLayout { id: textMessagePanel anchors.fill: parent TextArea { id: messageTextArea Layout.fillHeight: true Layout.fillWidth: true textFormat: TextEdit.RichText font.family: "Noto Color Emoji" font.pixelSize : 18 - placeholderText: qsTr("Write a message and press enter...") + placeholderText: i18n("Write a message and press enter...") Keys.onReturnPressed: { var rawText = getText(0, length) var richText = getFormattedText(0, length) sendMessage(rawText, richText) } persistentSelection: true states: [ State { name: "focus" when: messageTextArea.cursorVisible || chatBox.state == "emoji" || emojis.visible == true PropertyChanges { target: emojiButton opacity: 1 anchors.bottomMargin: 0 } } ] } Button { text: "Send" Layout.fillHeight: true onClicked: { var rawText = messageTextArea.getText(0, messageTextArea.length) var richText = messageTextArea.getFormattedText(0, messageTextArea.length) sendMessage(rawText, richText) } } } StateGroup { id: chatStateGroup states: [ State { name: "text" when: !emojiButton.checked PropertyChanges { target: messageTextArea focus: true } }, State { name: "emoji" when: emojiButton.checked PropertyChanges { target: textMessagePanel visible: false } PropertyChanges { target: emojis visible: true } } ] } Connections { target: chatBox onSendMessage: { console.log(message) messageTextArea.text = "" } } } diff --git a/src/timeline/qml/contactheader.qml b/src/timeline/qml/contactheader.qml index bd3b7940..51784ffa 100644 --- a/src/timeline/qml/contactheader.qml +++ b/src/timeline/qml/contactheader.qml @@ -1,202 +1,202 @@ /*************************************************************************** * 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 import QtQuick.Layouts 1.0 import Ring 1.0 import RingQmlWidgets 1.0 import PhotoSelectorPlugin 1.0 Rectangle { id: contactHeader property QtObject currentContactMethod: null property alias backgroundColor: contactHeader.color property var textColor: undefined property var cachedPhoto: undefined onCurrentContactMethodChanged: { primaryName.text = currentContactMethod.primaryName photo.pixmap = currentContactMethod.person ? currentContactMethod.person.photo : undefined bookmarkSwitch.source = (currentContactMethod && currentContactMethod.bookmarked) ? "icons/bookmarked.svg" : "icons/not_bookmarked.svg" } Connections { target: currentContactMethod onBookmarkedChanged: { bookmarkSwitch.source = (currentContactMethod && currentContactMethod.bookmarked) ? "icons/bookmarked.svg" : "icons/not_bookmarked.svg" } } Connections { target: currentContactMethod onChanged: { primaryName.text = currentContactMethod.primaryName photo.pixmap = currentContactMethod.person ? currentContactMethod.person.photo : undefined bookmarkSwitch.source = (currentContactMethod && currentContactMethod.bookmarked) ? "icons/bookmarked.svg" : "icons/not_bookmarked.svg" } } color: "gray" height: 100 Layout.fillWidth: true PersistentCallControls { anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter } RowLayout { anchors.fill: parent anchors.margins: 8 Rectangle { id: photoRect clip: true radius: 5 height: 90 width: 90 color: "white" PixmapWrapper { id: photo anchors.fill: parent } function onNewPhoto(p) { contactHeader.cachedPhoto = p photo.pixmap = p } MouseArea { anchors.fill: parent z: 100 onClicked: { var component = Qt.createComponent("PhotoEditor.qml") if (component.status == Component.Ready) { var window = component.createObject(contactHeader) window.person = currentContactMethod ? currentContactMethod.person : null window.newPhoto.connect(photoRect.onNewPhoto) } else console.log("ERROR", component.status, component.errorString()) } } } ColumnLayout { Layout.fillWidth: true Layout.fillHeight: true RowLayout { Text { id: primaryName font.bold: true font.pointSize: 16 text: "My name" color: textColor } Image { id: bookmarkSwitch anchors.rightMargin: 1 anchors.topMargin: 3 height: 16 width: 16 source: (currentContactMethod && currentContactMethod.bookmarked) ? "icons/bookmarked.svg" : "icons/not_bookmarked.svg" z: 100 MouseArea { anchors.fill: parent onClicked: { mouse.accepted = true currentContactMethod.bookmarked = !currentContactMethod.bookmarked bookmarkSwitch.source = currentContactMethod.bookmarked ? "icons/bookmarked.svg" : "icons/not_bookmarked.svg" } } } Item { Layout.fillWidth: true } } RowLayout { id: buttonBox Button { id: button - text: qsTr("Call") + text: i18n("Call") onClicked: { if (currentContactMethod == null) return CallModel.dialingCall(currentContactMethod) .performAction(Call.ACCEPT) } } Button { id: button2 - text: qsTr("Video") + text: i18n("Video") onClicked: { if (currentContactMethod == null) return CallModel.dialingCall(currentContactMethod) .performAction(Call.ACCEPT) } } Button { - text: qsTr("Screen sharing") + text: i18n("Screen sharing") onClicked: { if (currentContactMethod == null) return CallModel.dialingCall(currentContactMethod) .performAction(Call.ACCEPT) } } } } } states: [ State { name: "compact" PropertyChanges { target: contactHeader height: 40 Layout.maximumHeight: 40 } PropertyChanges { target: buttonBox visible: false } PropertyChanges { target: photoRect height: 30 width: 30 Layout.maximumHeight: 30 Layout.maximumWidth: 30 } } ] } diff --git a/src/timeline/qml/contactinfo.qml b/src/timeline/qml/contactinfo.qml index 48d7c137..941db6ee 100644 --- a/src/timeline/qml/contactinfo.qml +++ b/src/timeline/qml/contactinfo.qml @@ -1,539 +1,539 @@ /*************************************************************************** * 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 import QtQuick.Layouts 1.0 import Ring 1.0 import PhotoSelectorPlugin 1.0 import RingQmlWidgets 1.0 Item { id: contactViewPage property var currentContactMethod: null property var currentPerson: null signal changed() property bool showStat: true property bool showImage: false property bool showSave: true property var labelColor: undefined property var cachedPhoto: undefined function save() { if ((!currentContactMethod) && (!currentPerson)) return // Changing the CM will flush the content, preserve it var old_formattedName = formattedName.text var old_firstName = firstName.text var old_secondName = lastName.text var old_preferredEmail = email.text var old_organization = organization.text // Create a real contact method in case this is a temporary one if (currentContactMethod && currentContactMethod.type == ContactMethod.TEMPORARY) currentContactMethod = PhoneDirectoryModel.getNumber( currentContactMethod.uri, null, currentContactMethod.account ) var person = currentPerson if (!currentPerson) person = contactBuilder.from(currentContactMethod) person.formattedName = old_formattedName person.firstName = old_firstName person.secondName = old_secondName person.preferredEmail = old_preferredEmail person.organization = old_organization if (contactViewPage.cachedPhoto != undefined) person.photo = contactViewPage.cachedPhoto person.save() currentPerson = person } function getLastContacted() { - var d = currentContactMethod.lastUsed == 0 ? qsTr("Never") : + var d = currentContactMethod.lastUsed == 0 ? i18n("Never") : new Date(currentContactMethod.lastUsed * 1000).toLocaleString() - return qsTr("Last contacted on: ") + d + "[?]" + return i18n("Last contacted on: ") + d + "[?]" } function getTotalCall() { - return qsTr("Called: ") + currentContactMethod.callCount + + return i18n("Called: ") + currentContactMethod.callCount + " (" + (currentContactMethod.totalSpentTime/60) + " minutes) [?]" } function getTotalText() { - return qsTr("Texted: ") + currentContactMethod.textRecording.instantTextMessagingModel.rowCount() + return i18n("Texted: ") + currentContactMethod.textRecording.instantTextMessagingModel.rowCount() } SystemPalette { id: activePalette colorGroup: SystemPalette.Active } state: "desktop" onCurrentContactMethodChanged: { if (!currentContactMethod) return currentPerson = currentContactMethod.person // Stats lastContactedTime.text = getLastContacted() totalCall.text = getTotalCall() totalText.text = getTotalText() } onCurrentPersonChanged: { // Sub-models phoneNumbersModel.model = currentPerson ? currentPerson.phoneNumbersModel : null addresses.model = currentPerson ? currentPerson.addressesModel : null // Contact info formattedName.text = currentPerson ? currentPerson.formattedName : "" firstName.text = currentPerson ? currentPerson.firstName : "" lastName.text = currentPerson ? currentPerson.secondName : "" email.text = currentPerson ? currentPerson.preferredEmail : "" organization.text = currentPerson ? currentPerson.organization : "" photo.pixmap = currentPerson ? currentPerson.photo : undefined phoneNumbersModel.person = currentPerson } /** * When showing the profile or adding a contact, display the image at the top. * * When showing the main GUI, this image is part of the header and should * not be shown. */ Item { id: contactPicture visible: showImage height: showImage ? 90 : 0 width: parent.width anchors.top: parent.top Rectangle { id: photoRect visible: showImage anchors.centerIn: parent clip: true radius: 5 height: 90 width: 90 color: "white" PixmapWrapper { id: photo anchors.fill: parent } function onNewPhoto(p) { contactViewPage.cachedPhoto = p photo.pixmap = p contactViewPage.changed() } MouseArea { anchors.fill: parent z: 100 onClicked: { var component = Qt.createComponent("PhotoEditor.qml") if (component.status == Component.Ready) { var window = component.createObject(contactViewPage) window.person = currentContactMethod ? currentContactMethod.person : null window.newPhoto.connect(photoRect.onNewPhoto) } else console.log("ERROR", component.status, component.errorString()) } } } } GroupBox { id: advanced - title: qsTr("Advanced") + title: i18n("Advanced") clip: true ColumnLayout { id: tabbedContactInfo clip: true anchors.fill: parent TabBar { Layout.fillWidth: true id: tabBar // Avoid showing invisible pages by default currentIndex: contactViewPage.state != "phone" && sv.currentIndex == 0 ? 1 : sv.currentIndex TabButton { id: detailsButton - text: qsTr("Details") + text: i18n("Details") visible: false width: 0 } TabButton { - text: qsTr("Phone numbers") + text: i18n("Phone numbers") } TabButton { - text: qsTr("Addresses") + text: i18n("Addresses") } TabButton { id: statButton - text: qsTr("Statistics") + text: i18n("Statistics") visible: false width: 0 } } SwipeView { id: sv Layout.fillWidth: true Layout.fillHeight: true // Avoid showing invisible pages by default currentIndex: contactViewPage.state != "phone" && tabBar.currentIndex == 0 ? 1 : tabBar.currentIndex background: Rectangle { color: activePalette.base } Page { Layout.fillWidth: true Layout.fillHeight: true GridLayout { id: mainInfo height: implicitHeight columns: 2 rowSpacing: 10 columnSpacing: 10 Label { id: label - text: qsTr("Formatted name:") + text: i18n("Formatted name:") color: labelColor ? labelColor : activePalette.text } TextField { id: formattedName onTextChanged: { contactViewPage.changed() } } Label { - text: qsTr("Primary name:") + text: i18n("Primary name:") color: labelColor ? labelColor : activePalette.text } TextField { id: firstName onTextChanged: { contactViewPage.changed() } } Label { - text: qsTr("Last name:") + text: i18n("Last name:") color: labelColor ? labelColor : activePalette.text } TextField { id: lastName onTextChanged: { contactViewPage.changed() } } Label { - text: qsTr("Email:") + text: i18n("Email:") color: labelColor ? labelColor : activePalette.text } TextField { id: email onTextChanged: { contactViewPage.changed() } } Label { - text: qsTr("Organization:") + text: i18n("Organization:") color: labelColor ? labelColor : activePalette.text } TextField { id: organization onTextChanged: { contactViewPage.changed() } } } background: Rectangle { color: activePalette.base } } Page { Layout.fillWidth: true Layout.fillHeight: true PhoneNumbers { id: phoneNumbersModel anchors.fill: parent onPersonCreated: { if (!currentPerson) { console.log("Setting the person from a phone number") currentPerson = phoneNumbersModel.person } } } background: Rectangle { color: activePalette.base } } Page { Layout.fillWidth: true Layout.fillHeight: true Addresses { id: addresses anchors.fill: parent } background: Rectangle { color: activePalette.base } } Page { Layout.fillWidth: true Layout.fillHeight: true background: Rectangle { color: activePalette.base } ColumnLayout { id: statistics visible: showStat Layout.fillWidth: true Rectangle { color: activePalette.text height: 1 Layout.fillWidth: true } Label { id: lastContactedTime color: activePalette.text } Label { id: totalCall color: activePalette.text } Label { id: totalText color: activePalette.text } Rectangle { color: activePalette.text height: 1 Layout.fillWidth: true } } } } } } ContactBuilder { id: contactBuilder } Button { anchors.bottom: parent.bottom anchors.right: parent.right anchors.margins: 5 - text: qsTr("Save") + text: i18n("Save") visible: showSave onClicked: { contactViewPage.save() } } /** * To make this page scale down, reparent everything depending on the * resolution. */ states: [ // In tablet mode, use 3 columns for the details State { name: "tablet" ParentChange { target: advanced parent: contactViewPage } ParentChange { target: mainInfo parent: contactViewPage } ParentChange { target: statistics parent: contactViewPage } AnchorChanges { target: advanced anchors.right: contactViewPage.right anchors.bottom: contactViewPage.bottom anchors.top: contactPicture.bottom anchors.left: undefined } AnchorChanges { target: statistics anchors.top: contactPicture.bottom anchors.left: contactViewPage.left } AnchorChanges { target: mainInfo anchors.left: contactViewPage.left anchors.top: statistics.bottom } PropertyChanges { target: advanced visible: true width: contactViewPage.width / 2 } PropertyChanges { target: statistics width: contactViewPage.width / 2 height: statistics.implicitHeight } PropertyChanges { target: mainInfo width: contactViewPage.width / 2 } }, // In desktop mode, put everything on top of each other and get rid // of the second tabbar State { name: "desktop" extend: "tablet" AnchorChanges { target: advanced anchors.right: undefined anchors.bottom: undefined anchors.left: contactViewPage.left anchors.top: mainInfo.bottom } PropertyChanges { target: statistics width: contactViewPage.width } PropertyChanges { target: mainInfo width: mainInfo.implicitWidth height: mainInfo.implicitHeight anchors.topMargin: 10 } PropertyChanges { target: advanced width: contactViewPage.width * 0.66 height: 300 anchors.topMargin: 10 } }, // On the phone, use 2 tab bars at the top and bottom to fit all pages // in the tiny space State { name: "phone" ParentChange { target: tabbedContactInfo parent: contactViewPage } PropertyChanges { target: mainInfo anchors.fill: mainInfo.parent } PropertyChanges { target: statistics anchors.fill: statistics.parent } PropertyChanges { target: detailsButton visible: true width: undefined } PropertyChanges { target: statButton visible: true width: undefined } PropertyChanges { target: tabbedContactInfo anchors.fill: contactViewPage } PropertyChanges { target: advanced visible: false } } ] // For some reason, the `when` clause of the state never fire onHeightChanged: { var isPhone = contactViewPage.height <= 400 || ( contactViewPage.height > contactViewPage.width && contactViewPage.height < 600 ) var isTablet = ( contactViewPage.height < 300 /*advanced default*/ + statistics.implicitHeight + mainInfo.implicitHeight ) && ( contactViewPage.height > 400 ) && advanced.implicitWidth + mainInfo.implicitWidth < contactViewPage.width if (isPhone) state = "phone" else if (isTablet) state = "tablet" else state = "desktop" } } diff --git a/src/timeline/qml/peerstimeline.qml b/src/timeline/qml/peerstimeline.qml index 7c0430fb..5e6af8d9 100644 --- a/src/timeline/qml/peerstimeline.qml +++ b/src/timeline/qml/peerstimeline.qml @@ -1,353 +1,353 @@ /*************************************************************************** * 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 1.4 import QtQuick.Controls 2.0 as Controls2 import Ring 1.0 import QtQuick.Layouts 1.0 import QtGraphicalEffects 1.0 import RingQmlWidgets 1.0 Rectangle { SystemPalette { id: activePalette colorGroup: SystemPalette.Active } SystemPalette { id: inactivePalette colorGroup: SystemPalette.Disabled } color: activePalette.base id: recentDock visible: true property alias overlayVisible: scrollBar.overlayVisible signal contactMethodSelected(var cm) FontMetrics { id: fontMetrics } Component { id: contactDelegate ContactMethodDelegate { height: 4*fontMetrics.height pixmapHeight: 4*fontMetrics.height - 4 } } // To allow multiple places to set the contact method without knowing // it's index, use a selectionModel PeersTimelineSelectionModel { id: selectionMapper objectName: "selectionMapper" onCurrentIndexChanged: { recentView.currentIndex = current.row } } // Give time to all the code to run before invalidating the temporary // contact method. By then the code will have created a real one. Timer { id: clearTimer running: false repeat: false interval: 0 // Run idle onTriggered: { search.text = "" } } onContactMethodSelected: { clearTimer.running = true } ColumnLayout { anchors.fill: parent Controls2.TextField { id: search Layout.fillWidth: true - placeholderText: qsTr("Find someone") + placeholderText: i18n("Find someone") onTextChanged: { var call = CallModel.dialingCall() call.dialNumber = search.text CompletionModel.call = call } Keys.onDownPressed: { searchView.currentIndex = (searchView.currentIndex == searchView.count - 1) ? 0 : searchView.currentIndex + 1 } Keys.onUpPressed: { searchView.currentIndex = (searchView.currentIndex == 0) ? searchView.count - 1 : searchView.currentIndex - 1 } Keys.onReturnPressed: { if (searchStateGroup.state != "searchActive") return var cm = searchView.currentItem.contactMethod if (!cm) return contactMethodSelected(cm) } } Item { Layout.fillWidth: true Layout.fillHeight: true Item { id: newUserHelper width: parent.width - 20 height: 200 anchors.horizontalCenter: parent.horizontalCenter anchors.topMargin: 10 Rectangle { anchors.fill: parent color: activePalette.text opacity: 0.1 radius: 10 } Text { anchors.fill: parent anchors.margins: 10 font.bold: true wrapMode: Text.WordWrap color: activePalette.base - text: qsTr("To begin using Ring-KDE, enter an username in the box above and press enter or add new contacts") + text: i18n("To begin using Ring-KDE, enter an username in the box above and press enter or add new contacts") } } ListView { id: recentView clip: true anchors.fill: parent highlightMoveVelocity: Infinity //HACK delegate: contactDelegate highlight: Rectangle { color: activePalette.highlight } model: PeersTimelineModel.deduplicatedTimelineModel onCountChanged: { if (count > 0) newUserHelper.visible = false scrollBar.visible = count*50 > recentDock.height scrollBar.handleHeight = recentDock.height * (recentDock.height/(count*50)) } onHeightChanged: { scrollBar.handleHeight = recentDock.height * (recentDock.height/(count*50)) } } TimelineScrollbar { id: scrollBar height: parent.height anchors.top: parent.top anchors.right: parent.right width: 10 model: PeersTimelineModel.timelineSummaryModel z: 100 onWidthChanged: { burryOverlay.width = scrollBar.fullWidth + 15 } visible: PeersTimelineModel.deduplicatedTimelineModel.count*50 > recentDock.height onPositionChanged: { recentView.contentY = (recentView.contentHeight-recentView.height)*scrollBar.position } } // Add a blurry background ShaderEffectSource { id: effectSource visible: false sourceItem: recentView anchors.right: recentView.right anchors.top: recentView.top width: scrollBar.fullWidth + 15 height: recentView.height sourceRect: Qt.rect( parent.width - scrollBar.fullWidth - 15, 0, scrollBar.fullWidth + 15, recentView.height ) } Item { id: burryOverlay visible: false opacity: 0 anchors.right: recentView.right anchors.top: recentView.top width: scrollBar.fullWidth + 15 height: recentView.height clip: true Repeater { anchors.fill: parent model: 5 FastBlur { anchors.fill: parent source: effectSource radius: 30 } } Rectangle { anchors.fill: parent color: "black" opacity: 0.75 } } FindPeers { id: searchView visible: false anchors.fill: parent } } } /*Rectangle { color: "red" anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right height: 200 Component { id: contactRequestDelegate Text { height: 40 text: display } } ListView { anchors.fill: parent model: AccountModel.incomingContactRequestModel delegate: contactRequestDelegate Component.onCompleted: { console.log("\n\n\nCOMPLETED!!!!", AccountModel.incomingContactRequestModel , AccountModel.incomingContactRequestModel.rowCount() ) } } }*/ onHeightChanged: { scrollBar.handleHeight = recentDock.height * (recentDock.height/(recentView.count*50)) } // Timeline scrollbar StateGroup { states: [ State { name: "overlay" when: scrollBar.overlayVisible PropertyChanges { target: burryOverlay visible: true } PropertyChanges { target: burryOverlay opacity: 1 } PropertyChanges { target: effectSource visible: true } } ] transitions: [ Transition { to: "overlay" NumberAnimation { properties: "opacity" easing.type: Easing.InQuad duration: 400 loops: 1 } } ] } // Search StateGroup { id: searchStateGroup states: [ State { name: "searchActive" when: search.text != "" PropertyChanges { target: scrollBar visible: false } PropertyChanges { target: searchView visible: true } PropertyChanges { target: burryOverlay visible: true opacity: 1 width: recentView.width height: recentView.height } PropertyChanges { target: effectSource sourceRect: Qt.rect(0, 0, parent.width, parent.height) } } ] transitions: [ Transition { to: "searchActive" NumberAnimation { properties: "opacity" easing.type: Easing.InQuad duration: 200 loops: 1 } NumberAnimation { properties: "width,height" easing.type: Easing.InQuad duration: 0 loops: 1 } } ] } } diff --git a/src/timeline/qml/phonenumbers.qml b/src/timeline/qml/phonenumbers.qml index 93b393d9..3e4ff6b9 100644 --- a/src/timeline/qml/phonenumbers.qml +++ b/src/timeline/qml/phonenumbers.qml @@ -1,191 +1,191 @@ /*************************************************************************** * 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 import QtQuick.Layouts 1.0 import Ring 1.0 import RingQmlWidgets 1.0 Item { id: phoneNumbers property alias model : numbers.model property QtObject person: null signal personCreated(QtObject newPerson) SystemPalette { id: activePalette colorGroup: SystemPalette.Active } SystemPalette { id: inactivePalette colorGroup: SystemPalette.Disabled } ColumnLayout { anchors.fill: parent ListView { id: numbers Layout.fillWidth: true Layout.fillHeight: true anchors.margins: 3 delegate: Item { height: 30 width: phoneNumbers.width RowLayout { anchors.fill: parent PixmapWrapper { Layout.preferredHeight: parent.height Layout.preferredWidth: parent.height pixmap: decoration } Text { text: display Layout.fillWidth: true color: activePalette.text } Text { text: categoryName color: inactivePalette.text } Rectangle { id: videoButton visible: isReachable Layout.preferredWidth: parent.height Layout.preferredHeight: parent.height color: "transparent" radius: 3 Image { anchors.fill: parent smooth : false source: "sharedassets/phone_dark/accept_video.svg" sourceSize.width: parent.height sourceSize.height: parent.height } MouseArea { anchors.fill: parent hoverEnabled: true onEntered: videoButton.color = activePalette.highlight onExited: videoButton.color = "transparent" onClicked: CallModel.dialingCall(object).performAction(Call.ACCEPT) } } Rectangle { id: callButton visible: isReachable Layout.preferredWidth: parent.height Layout.preferredHeight: parent.height color: "transparent" radius: 3 Image { anchors.fill: parent smooth : false source: "sharedassets/phone_dark/accept.svg" sourceSize.width: parent.height sourceSize.height: parent.height } MouseArea { anchors.fill: parent hoverEnabled: true onEntered: callButton.color = activePalette.highlight onExited: callButton.color = "transparent" onClicked: CallModel.dialingCall(object).performAction(Call.ACCEPT) } } Rectangle { id: remove visible: isReachable Layout.preferredWidth: parent.height Layout.preferredHeight: parent.height color: "transparent" radius: 3 Image { anchors.fill: parent smooth : false source: "image://icon/list-remove" sourceSize.width: parent.height sourceSize.height: parent.height } MouseArea { anchors.fill: parent hoverEnabled: true onEntered: remove.color = activePalette.highlight onExited: remove.color = "transparent" // onClicked: CallModel.dialingCall(object).performAction(Call.ACCEPT) } } Item { Layout.preferredWidth: 5 } } } } ContactBuilder { id: contactBuilder } RowLayout { Layout.fillWidth: true Layout.preferredHeight: 40 ComboBox { id: numbertype model: NumberCategoryModel textRole: "display" onActivated: { } } TextField { Layout.fillWidth: true id: newPhoneNumber } Button { id: button - text: qsTr("Add") + text: i18n("Add") onClicked: { if (newPhoneNumber.text == "") { console.log("No number added, the field is empty") return } var cm = contactBuilder.addPhoneNumber( person, newPhoneNumber.text, numbertype.index ) console.log("adding", newPhoneNumber.text, cm) if (cm && cm.person) { console.log("Setting the person") person = cm.person phoneNumbers.model = cm.person.phoneNumbersModel personCreated(cm.person) } } } } } } diff --git a/src/timeline/qml/viewcontact.qml b/src/timeline/qml/viewcontact.qml index ae55431b..ac7b54ec 100644 --- a/src/timeline/qml/viewcontact.qml +++ b/src/timeline/qml/viewcontact.qml @@ -1,282 +1,282 @@ /*************************************************************************** * 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 import QtQuick.Layouts 1.0 import Ring 1.0 Rectangle { id: viewContact property var currentContactMethod: null property var currentPerson: null property string currentPage: "" clip: true SystemPalette { id: activePalette colorGroup: SystemPalette.Active } color: activePalette.base onCurrentContactMethodChanged: { contactHeader.currentContactMethod = currentContactMethod contactInfo.currentContactMethod = currentContactMethod callHistory.currentContactMethod = currentContactMethod timelinePage.currentContactMethod = currentContactMethod if (currentContactMethod && currentContactMethod.person) personConn.target = currentContactMethod.person // Check if the CM already has an active call, switch to it for (var i=0; i * * * * 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.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 // Align left Button { id: backButton Layout.fillHeight: true - text: qsTr("Back") + text: i18n("Back") //visible: false //FIXME } Item { Layout.fillWidth: true } // Align right BusyIndicator { id: busyIndicator visible: false Layout.fillHeight: true } Label { id: missingFields - text: qsTr("Please fill the required fields") + text: i18n("Please fill the required fields") verticalAlignment: Text.AlignVCenter color: "red" visible: true Layout.fillHeight: true } Button { id: nextButton Layout.fillHeight: true - text: qsTr("Next") + text: i18n("Next") visible: false } Button { id: skipButton Layout.fillHeight: true - text: qsTr("Skip") + 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: qsTr("Please wait") + 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: "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 70fade33..21d27600 100644 --- a/src/wizard/qml/CreateRing.qml +++ b/src/wizard/qml/CreateRing.qml @@ -1,456 +1,456 @@ /*************************************************************************** * 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 import Ring 1.0 Item { id: item1 property alias registerUserName: registerUserName property bool nextAvailable: false property bool busy: false property var account: null signal registrationCompleted() function isNextAvailable() { nextAvailable = (userName.text.length > 0 || !registerUserName.checked) && (password.text.length > 0) && (password.text == repeatPassword.text) } function createAccount() { if (!nextAvailable) { console.log("Account creation failed: missing fields") return; } // Prevent trigger happy people from DDOSing the daemon with entropy // starvation nextAvailable = false busy = true // Display the progress popup state = "registrationResult" registrationTimeout.running = true var name = userName.text == "" ? WelcomeDialog.defaultUserName : userName.text // Make sure they are unique name = name + AccountModel.getSimilarAliasIndex(name) account = AccountModel.add(name, Account.RING); account.displayName = name account.archivePassword = password.text account.upnpEnabled = true; account.performAction(Account.SAVE) account.performAction(Account.RELOAD) } ColumnLayout { anchors.fill: parent Switch { id: registerUserName height: 40 - text: qsTr("Register public username (experimental)*") + text: i18n("Register public username (experimental)*") checked: true opacity: 1 Layout.fillWidth: true onCheckedChanged: isNextAvailable() } Label { id: label2 clip: true x: -7 y: 170 height: 14 - text: qsTr("Enter an username") + text: i18n("Enter an username") color: "white" anchors.leftMargin: 8 anchors.left: parent.left Layout.fillWidth: true /*Behavior on Layout.maximumHeight { NumberAnimation { easing.type: Easing.OutQuad duration: 500 } }*/ } TextField { id: userName clip: true x: 8 y: 74 text: WelcomeDialog.defaultUserName height: 40 Layout.fillWidth: true /*Behavior on Layout.maximumHeight { NumberAnimation { easing.type: Easing.OutQuad duration: 500 } }*/ onTextChanged: { isNextAvailable() busyIndicator.visible = true if (userName.text != "") NameDirectory.lookupName(undefined, "", userName.text) } } RowLayout { id: rowLayout clip: true x: 44 y: 127 height: 37 Layout.fillHeight: false Layout.maximumHeight: 37 Layout.fillWidth: true spacing: 6 Item { width: 37 height: 37 Layout.fillHeight: true Layout.preferredWidth: 37 BusyIndicator { id: busyIndicator anchors.fill: parent visible: false } Image { id: image anchors.fill: parent } } Label { id: registerFoundLabel - text: qsTr("Please enter an username") + text: i18n("Please enter an username") verticalAlignment: Text.AlignVCenter color: "white" Layout.fillHeight: true Layout.fillWidth: true } /*Behavior on Layout.maximumHeight { NumberAnimation { easing.type: Easing.OutQuad duration: 500 } }*/ } Label { id: label1 x: -1 y: 233 height: 14 - text: qsTr("Enter an archive password") + text: i18n("Enter an archive password") color: "white" Layout.fillWidth: true anchors.leftMargin: 8 anchors.left: parent.left } TextField { id: password x: 8 y: 187 height: 40 echoMode: "Password" Layout.fillWidth: true onTextChanged: isNextAvailable() } Label { id: label x: -1 y: 54 height: 14 color: "white" - text: qsTr("Repeat the new password") + text: i18n("Repeat the new password") Layout.fillWidth: true anchors.leftMargin: 8 } TextField { id: repeatPassword echoMode: "Password" x: 8 y: 253 height: 40 Layout.fillWidth: true onTextChanged: isNextAvailable() } Label { id: label4 color: "red" - text: qsTr("Passwords don't match") + 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 } } ] /*Behavior on opacity { NumberAnimation { easing.type: Easing.OutQuad duration: 200 } }*/ } Item { height: 10 Layout.fillWidth: true } Label { id: labelInfo color: "white" - text: qsTr("(*) registered usernames can be reached by their username-string instead of their generated ring-id number only.") + 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 { id: registrationPopup width: 200 height: 75 color: "#eeeeee" visible: false z: 200 anchors.centerIn: item1 RowLayout { anchors.verticalCenter: parent.verticalCenter BusyIndicator { id: registrationIndicator Layout.fillHeight: false } Label { id: registrationStatus - text: qsTr("Creating account") + text: i18n("Creating account") Layout.fillHeight: false Layout.fillWidth: true color: "black" } } } // Hide the error message after a second Timer { id: hidePopup repeat: false running: false interval: 1000 onTriggered: { registrationPopup.visible = false } } // Remove the popup after 30 seconds if it didn't finish by then Timer { id: registrationTimeout repeat: false interval: 30000 running: false onTriggered: { registrationPopup.color = "red" - registerFoundLabel.text = qsTr("Timeout") + 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: userName Layout.maximumHeight: 0 opacity: 0 } PropertyChanges { target: rowLayout 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: NameDirectory onRegisteredNameFound: { // Race conditions if (userName.text != name) return; busyIndicator.visible = false if (status == 2) { //NameDirectory.NOT_FOUND - registerFoundLabel.text = qsTr("The username is available") + registerFoundLabel.text = i18n("The username is available") registerFoundLabel.color = "green" } else if (name == "") { - registerFoundLabel.text = qsTr("Please enter an username") + registerFoundLabel.text = i18n("Please enter an username") registerFoundLabel.color = "" nextAvailable = false } else { - registerFoundLabel.text = qsTr("The username is not available") + registerFoundLabel.text = i18n("The username is not available") registerFoundLabel.color = "red" nextAvailable = false } } } 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 = qsTr("Success") + registrationStatus.text = i18n("Success") busy = false item1.registrationCompleted() break case 1: //WRONG_PASSWORD - registrationStatus.text = qsTr("Password mismatch") + registrationStatus.text = i18n("Password mismatch") break case 2: //INVALID_NAME - registrationStatus.text = qsTr("Invalid name") + registrationStatus.text = i18n("Invalid name") break case 3: //ALREADY_TAKEN - registrationStatus.text = qsTr("Already taken") + registrationStatus.text = i18n("Already taken") break case 4: //NETWORK_ERROR - registrationStatus.text = qsTr("Network error") + registrationStatus.text = i18n("Network error") break } } } Connections { target: account onStateChanged: { if (state == Account.READY) { if (registerUserName.checked) { if (account.registerName(password.text, account.displayName)) { - registrationStatus.text = qsTr("Registration") + registrationStatus.text = i18n("Registration") registrationTimeout.stop() } else { registrationPopup.color = "red" - registrationStatus.text = qsTr("Can't register") + registrationStatus.text = i18n("Can't register") registrationTimeout.stop() } } else { registrationTimeout.stop() registrationIndicator.visible = false busy = false item1.registrationCompleted() } account = null } } } } diff --git a/src/wizard/qml/ImportRing.qml b/src/wizard/qml/ImportRing.qml index 307f81b3..ffa35a3d 100644 --- a/src/wizard/qml/ImportRing.qml +++ b/src/wizard/qml/ImportRing.qml @@ -1,194 +1,194 @@ /*************************************************************************** * 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 import Ring 1.0 Item { id: importRing property bool nextAvailable: false property var account: null signal registrationCompleted() function isNextAvailable() { nextAvailable = pinField.text.length > 0 && password.text.length > 0 } function createAccount() { if (!nextAvailable) { console.log("Account creation failed: missing fields") return; } registrationPopup.visible = true registrationTimeout.running = true registrationPopup.color = "white" account = AccountModel.add(WelcomeDialog.defaultUserName, Account.RING) account.archivePassword = password.text account.archivePin = pinField.text account.upnpEnabled = true; account.performAction(Account.SAVE) account.performAction(Account.RELOAD) } ColumnLayout { anchors.fill: parent Label { id: label2 clip: false - text: qsTr("Link this device") + text: i18n("Link this device") verticalAlignment: Text.AlignVCenter padding: 0 font.bold: true horizontalAlignment: Text.AlignHCenter anchors.leftMargin: 8 anchors.left: parent.left Layout.fillWidth: true /*Behavior on Layout.maximumHeight { NumberAnimation { easing.type: Easing.OutQuad duration: 500 } }*/ } Label { id: label1 - text: qsTr("Enter your main Ring account password") + text: i18n("Enter your main Ring account password") Layout.fillWidth: true anchors.leftMargin: 8 anchors.left: parent.left } TextField { id: password echoMode: "Password" Layout.fillWidth: true onTextChanged: isNextAvailable() } Label { id: label wrapMode: "WordWrap" - text: qsTr("Enter the PIN number form another configured Ring account. Use the \"Export account on Ring\" feature to obtain a PIN.") + text: i18n("Enter the PIN number form another configured Ring account. Use the \"Export account on Ring\" feature to obtain a PIN.") Layout.fillWidth: true anchors.leftMargin: 8 } TextField { id: pinField echoMode: "Password" Layout.fillWidth: true onTextChanged: isNextAvailable() } Rectangle { Layout.fillHeight: true } } Rectangle { id: registrationPopup width: 200 height: 75 color: "#eeeeee" visible: false z: 200 anchors.centerIn: item1 RowLayout { anchors.verticalCenter: parent.verticalCenter BusyIndicator { id: registrationIndicator Layout.fillHeight: false } Label { id: registrationStatus - text: qsTr("Importing account") + text: i18n("Importing account") Layout.fillHeight: false Layout.fillWidth: true color: "black" } } } // Hide the error message after a second Timer { id: hidePopup repeat: false running: false interval: 1000 onTriggered: { registrationPopup.visible = false } } // Remove the popup after 30 seconds if it didn't finish by then Timer { id: registrationTimeout repeat: false interval: 30000 running: false onTriggered: { registrationPopup.color = "red" - registerFoundLabel.text = qsTr("Timeout") + registerFoundLabel.text = i18n("Timeout") hidePopup.running = true } } /*transitions: Transition { NumberAnimation { properties: "opacity" easing.type: Easing.OutQuad duration: 500 onStopped: { label2.visible = false userName.visible = false rowLayout.visible = false } } }*/ Connections { target: account onStateChanged: { switch(state) { case Account.ERROR: registrationPopup.color = "red" - registrationStatus.text = qsTr("Importing failed") + registrationStatus.text = i18n("Importing failed") hidePopup.running = true registrationTimeout.stop() break case Account.READY: registrationPopup.visible = false registrationTimeout.stop() importRing.registrationCompleted() account = null break } } } } diff --git a/src/wizard/qml/Page1Form.ui.qml b/src/wizard/qml/Page1Form.ui.qml index 60370f8e..da253748 100644 --- a/src/wizard/qml/Page1Form.ui.qml +++ b/src/wizard/qml/Page1Form.ui.qml @@ -1,131 +1,127 @@ /*************************************************************************** * 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 import QtQuick.Layouts 1.0 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: 423 height: 86 - text: qsTr("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") + 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" } Button { id: createRingAccount anchors.horizontalCenter: parent.horizontalCenter y: 246 - text: qsTr("Create a new GNU Ring account") + text: i18n("Create a new GNU Ring account") } Button { id: importRingAccount anchors.horizontalCenter: parent.horizontalCenter y: 300 - text: qsTr("Import an existing account") + text: i18n("Import an existing account") } Button { id: createAnonRingAccount anchors.horizontalCenter: parent.horizontalCenter y: 354 - text: qsTr("Use an anonymous account") + text: i18n("Use an anonymous account") visible: false } Button { id: importSIPAccount anchors.horizontalCenter: parent.horizontalCenter y: 408 - text: qsTr("Import a SIP account") + text: i18n("Import a SIP account") visible: false } Button { id: createIp2IPAccount anchors.horizontalCenter: parent.horizontalCenter y: 462 - text: qsTr("Use on local network") + text: i18n("Use on local network") visible: false } Image { id: image anchors.horizontalCenter: parent.horizontalCenter y: 43 width: 100 height: 100 source: "ring-kde.svg" } CreateRing { id: createRing x: -20 y: text1.height + 8 opacity: 0 visible: false width: logo.width + text1.width } ImportRing { id: importRing x: -20 y: text1.height + 8 opacity: 0 visible: false width: logo.width + text1.width } 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/StartingPageForm.ui.qml b/src/wizard/qml/StartingPageForm.ui.qml index 71bd7c80..fff69798 100644 --- a/src/wizard/qml/StartingPageForm.ui.qml +++ b/src/wizard/qml/StartingPageForm.ui.qml @@ -1,207 +1,207 @@ /*************************************************************************** * 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.4 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.3 Item { property alias background: background property alias whatsNew: swipeView width: 400 height: 400 Rectangle { id: background anchors.fill: parent color: "#0886a0" x: 51 y: 40 width: 200 height: 200 ColumnLayout { id: columnLayout anchors.fill: parent RowLayout { id: rowLayout clip: true Layout.maximumHeight: 500 Layout.fillWidth: true Image { id: image1 height: 200 Layout.maximumHeight: 200 Layout.alignment: Qt.AlignRight | Qt.AlignVCenter fillMode: Image.PreserveAspectFit source: "beta_logo.svg" Layout.fillHeight: true Layout.fillWidth: true } Image { id: image fillMode: Image.PreserveAspectFit height: widthparent.maxHeight ? parent.maxHeight : width ) width: (parent.rowWidth) < parent.minWidth ? parent.minWidth : ( parent.rowWidth > parent.maxWidth ? parent.maxWidth : parent.rowWidth) source: "people.svg" Layout.fillHeight: true Layout.fillWidth: false Layout.maximumHeight: 300 Layout.maximumWidth: 300 Layout.preferredHeight: parent.height Layout.preferredWidth: parent.height anchors.verticalCenter: parent.verticalCenter } } Item { height: 40 } SwipeView { id: swipeView clip: true Layout.fillHeight: true Layout.fillWidth: true RowLayout { Image { Layout.fillHeight: true source: "image://icon/channel-secure-symbolic" Layout.preferredWidth: 100 fillMode: Image.PreserveAspectFit } Label { wrapMode: Text.WordWrap clip: true - text: qsTr("Ring-KDE allows you to communicate privately with your friends. It uses peer to peer technologies popularised by BitTorrent to create a decentralized network of users. There is no central server and all communications are end-to-end encrypted. ") + text: i18n("Ring-KDE allows you to communicate privately with your friends. It uses peer to peer technologies popularised by BitTorrent to create a decentralized network of users. There is no central server and all communications are end-to-end encrypted. ") Layout.fillWidth: true Layout.fillHeight: true } } RowLayout { Image { Layout.fillHeight: true source: "image://icon/text-directory" Layout.preferredWidth: 100 fillMode: Image.PreserveAspectFit } Label { wrapMode: Text.WordWrap clip: true - text: qsTr("Ring-KDE stores all data locally using standard formats such as JSON, vCard, MIME, PCM/WAV, INI ans X-509. No data is ever uploaded to external servers.") + text: i18n("Ring-KDE stores all data locally using standard formats such as JSON, vCard, MIME, PCM/WAV, INI ans X-509. No data is ever uploaded to external servers.") Layout.fillWidth: true Layout.fillHeight: true } } RowLayout { Image { Layout.fillHeight: true source: "image://icon/call-start" Layout.preferredWidth: 100 fillMode: Image.PreserveAspectFit } Label { wrapMode: Text.WordWrap clip: true - text: qsTr("Ring-KDE supports your office phone account. Answers, transfer and record your phone calls directly from KDE") + text: i18n("Ring-KDE supports your office phone account. Answers, transfer and record your phone calls directly from KDE") Layout.fillWidth: true Layout.fillHeight: true } } RowLayout { Image { Layout.fillHeight: true source: "image://icon/standard-connector" Layout.preferredWidth: 100 fillMode: Image.PreserveAspectFit } Label { wrapMode: Text.WordWrap clip: true - text: qsTr("Ring is based on open standards and is can interoperate with other SIP compliant systems.") + text: i18n("Ring is based on open standards and is can interoperate with other SIP compliant systems.") Layout.fillWidth: true Layout.fillHeight: true } } RowLayout { Image { Layout.fillHeight: true source: "image://icon/text-x-python" Layout.preferredWidth: 100 fillMode: Image.PreserveAspectFit } Label { wrapMode: Text.WordWrap clip: true - text: qsTr("Ring offers an user friendly DBus API to automate all aspects of the application.") + text: i18n("Ring offers an user friendly DBus API to automate all aspects of the application.") Layout.fillWidth: true Layout.fillHeight: true } } RowLayout { Image { Layout.fillHeight: true source: "image://icon/call-start" Layout.preferredWidth: 100 fillMode: Image.PreserveAspectFit } Label { wrapMode: Text.WordWrap clip: true - text: qsTr("Ring-KDE can call real phone numbers. Cheap credits are available from thousand of providers worldwide. Use your favorite search engine to locate a local SIP phone provider.") + text: i18n("Ring-KDE can call real phone numbers. Cheap credits are available from thousand of providers worldwide. Use your favorite search engine to locate a local SIP phone provider.") Layout.fillWidth: true Layout.fillHeight: true } } } Label { id: label color: "white" - text: qsTr("Press anywhere to begin") + text: i18n("Press anywhere to begin") font.pointSize: 12 horizontalAlignment: Text.AlignHCenter Layout.fillWidth: true font.bold: true Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter } } } } diff --git a/src/wizard/qml/frontpage.qml b/src/wizard/qml/frontpage.qml index 081e3682..151df212 100644 --- a/src/wizard/qml/frontpage.qml +++ b/src/wizard/qml/frontpage.qml @@ -1,54 +1,54 @@ /*************************************************************************** * 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 import QtQuick.Layouts 1.0 ApplicationWindow { visible: true width: 640 height: 480 - title: qsTr("Hello World") + title: i18n("Hello World") SwipeView { id: swipeView anchors.fill: parent currentIndex: tabBar.currentIndex Page1 { } Page { Label { - text: qsTr("Second page") + text: i18n("Second page") anchors.centerIn: parent } } } footer: TabBar { id: tabBar currentIndex: swipeView.currentIndex TabButton { - text: qsTr("First") + text: i18n("First") } TabButton { - text: qsTr("Second") + text: i18n("Second") } } } diff --git a/src/wizard/qml/main.qml b/src/wizard/qml/main.qml index 185330f6..e14f674e 100644 --- a/src/wizard/qml/main.qml +++ b/src/wizard/qml/main.qml @@ -1,414 +1,414 @@ /*************************************************************************** * 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 import QtQuick.Layouts 1.0 ApplicationWindow { id: applicationWindow visible: true - title: qsTr("Ring-KDE wizard") + title: i18n("Ring-KDE wizard") color: "#004d61" flags: Qt.Dialog height: 720 width: 1024 property string previousState: "" StartingPage { 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 = "locked" } } onQuit: { applicationWindow.close() RingApplication.newInstance() } } Page1 { id: frontPage anchors.fill: parent anchors.bottomMargin: footer.height visible: true } 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: { applicationWindow.close() RingApplication.newInstance() } } // 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() break; case 'importRing': frontPage.importRing.createAccount() break; case '*': stateGroup.state = "*" stateGroup.state = "showProfile" footer.state = "finish" break; case 'showProfile': frontPage.profilePage.save() applicationWindow.close() RingApplication.newInstance() break; } } } Connections { target: frontPage.createRing onRegistrationCompleted: { stateGroup.state = "showProfile" footer.state = "finish" } onAccountChanged: { var acc = frontPage.importRing.account if (!acc) return frontPage.profilePage.currentPerson = acc.profile.person } } 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.person } } Timer { interval: 3000 repeat: false running: wizardWelcomeOnly onTriggered: { applicationWindow.close() RingApplication.newInstance() } } 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: qsTr("Import a SIP account") + text: i18n("Import a SIP account") } PropertyChanges { target: frontPage.createIp2IPAccount x: 771 y: 96 opacity: 0 } PropertyChanges { target: frontPage.logo x: 8 y: 8 } PropertyChanges { target: frontPage.welcomeMessage x: 114 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: 8 y: frontPage.welcomeMessage.height + 8 } }, // 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: 8 y: frontPage.welcomeMessage.height + 8 } }, // 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 } } ]*/ } }