diff --git a/src/qml/homescreen/CourseDescriptionItem.qml b/src/qml/homescreen/CourseDescriptionItem.qml index f76dec3..c27d1d2 100644 --- a/src/qml/homescreen/CourseDescriptionItem.qml +++ b/src/qml/homescreen/CourseDescriptionItem.qml @@ -1,52 +1,50 @@ /* * Copyright 2012 Sebastian Gottfried * Copyright 2015 Sebastian Gottfried * * 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 2 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.2 import ktouch 1.0 import "../common" Collapsable { id: root property string description onDescriptionChanged: { if (contentItem.opacity === 0) { descriptionLabel.text = description } else { swapContent() } } onContentReadyForSwap: { descriptionLabel.text = description } - Label { id: descriptionLabel leftPadding: 20 rightPadding: 20 topPadding: 10 bottomPadding: 10 } } diff --git a/src/qml/homescreen/InitialProfileDialog.qml b/src/qml/homescreen/InitialProfileDialog.qml index 07196a9..cb0eedc 100644 --- a/src/qml/homescreen/InitialProfileDialog.qml +++ b/src/qml/homescreen/InitialProfileDialog.qml @@ -1,47 +1,46 @@ /* * Copyright 2012 Sebastian Gottfried * Copyright 2015 Sebastian Gottfried * * 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 2 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.2 import QtQuick.Layouts 1.3 import ktouch 1.0 import '../common' PopupDialog { id: root modal: true title: i18n("Welcome to Typewriting Trainer") - closePolicy: Popup.NoAutoClose + closePolicy: PopupDialog.NoAutoClose padding: 20 function save() { var profile = profileDataAccess.createProfile() profile.name = form.name profile.skillLevel = form.skillLevel profileDataAccess.addProfile(profile) close() } contentItem: ProfileForm { id: form doneButtonIconSource: "go-next-view" doneButtonText: i18n("Start Training") onDone: save() } } diff --git a/src/qml/homescreen/KeyboardLayoutMismatchMessage.qml b/src/qml/homescreen/KeyboardLayoutMismatchMessage.qml index ff52f03..30b36b0 100644 --- a/src/qml/homescreen/KeyboardLayoutMismatchMessage.qml +++ b/src/qml/homescreen/KeyboardLayoutMismatchMessage.qml @@ -1,83 +1,81 @@ /* * Copyright 2017 Sebastian Gottfried * * 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 2 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.2 import QtQuick.Layouts 1.3 import ktouch 1.0 -import org.kde.kquickcontrolsaddons 2.0 import "../common" Collapsable { id: root background: Rectangle { color: colorScheme.neutralBackground } Item { implicitWidth: root.width implicitHeight: layout.implicitHeight + 20 GridLayout { id: layout anchors.centerIn: parent width: root.width - 40 rowSpacing: label.font.pixelSize columnSpacing: 10 - QIconItem { + Icon { Layout.column: 0 Layout.row: 0 width: 32 height: 32 icon: "dialog-warning" } Label { id: label Layout.column: 1 Layout.row: 0 Layout.fillWidth: true font.bold: true wrapMode: Text.Wrap text: i18n("The selected course doesn't match your computer's active keyboard layout.") } Label { Layout.column: 1 Layout.row: 1 Layout.columnSpan: configureKeyboardButton.visible? 2: 1 Layout.fillWidth: true wrapMode: Text.Wrap text: i18n("KTouch can't switch or set up keyboard layouts. Before training, you have to configure your computer to use the correct keyboard layout or you will have to use your current keyboard layout to type the lesson text.") opacity: 0.7 } IconButton { id: configureKeyboardButton Layout.column: 2 Layout.row: 0 visible: ktouch.keyboardKCMAvailable text: i18n("Configure Keyboard") onClicked: { ktouch.showKeyboardKCM(); } } } } } diff --git a/src/qml/homescreen/LessonDeletedMessage.qml b/src/qml/homescreen/LessonDeletedMessage.qml index 208cc1d..830674d 100644 --- a/src/qml/homescreen/LessonDeletedMessage.qml +++ b/src/qml/homescreen/LessonDeletedMessage.qml @@ -1,81 +1,80 @@ /* * Copyright 2017 Sebastian Gottfried * * 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 2 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.2 import QtQuick.Layouts 1.3 import ktouch 1.0 import "../common" Collapsable { id: root collapsed: true property Lesson deletedLesson: Lesson {} signal undeleteRequested() property bool completed: false onVisibleChanged: { if (!visible && completed) { destroy(); } } Component.onCompleted: { root.collapsed = false; root.completed = true; } Item { implicitWidth: root.width implicitHeight: layout.implicitHeight + 20 RowLayout { id: layout width: root.width - 40 anchors.centerIn: parent Label { text: root.deletedLesson.title? i18n("Lesson %1 deleted.", root.deletedLesson.title): i18n("Lesson without title deleted.") wrapMode: Text.Wrap Layout.fillWidth: true } IconButton { icon: "edit-undo" text: i18n("Undo") onClicked: { root.undeleteRequested(); root.collapsed = true; } } AutoTriggerButton { id: okButton icon: "dialog-ok" text: i18n("Confirm") onClicked: { root.collapsed = true; } } } } } diff --git a/src/qml/homescreen/LessonEditorDialog.qml b/src/qml/homescreen/LessonEditorDialog.qml index 8cb5167..896c5c0 100644 --- a/src/qml/homescreen/LessonEditorDialog.qml +++ b/src/qml/homescreen/LessonEditorDialog.qml @@ -1,110 +1,110 @@ /* * Copyright 2017 Sebastian Gottfried * * 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 2 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.2 +import QtQuick.Controls 2.2 as Controls import QtQuick.Layouts 1.3 import ktouch 1.0 import '../common' PopupDialog { id: root property Lesson lesson: Lesson {} property KeyboardLayout keyboardLayout: KeyboardLayout {} property Profile profile: Profile {} onClosed: { profileDataAccess.storeCustomLesson(root.lesson, root.profile, root.keyboardLayout.name) } title: i18n("Edit lesson") margins: { left: 40 bottom: 40 right: 40 top: 40 } width: parent.width - leftMargin - rightMargin height: parent.height - topMargin - bottomMargin padding: titleLabel.font.pixelSize contentItem: GridLayout { columnSpacing: titleLabel.font.pixelSize rowSpacing: titleLabel.font.pixelSize Label { id: titleLabel text: i18n("Title:") Layout.row: 0 Layout.column: 0 } TextField { id: titleTextField text: root.lesson? root.lesson.title: "" onTextChanged: { if (root.lesson) { root.lesson.title = text } } Layout.row: 0 Layout.column: 1 Layout.fillWidth: true } - ScrollView { + Controls.ScrollView { Layout.row: 1 Layout.column: 0 Layout.columnSpan: 2 Layout.fillHeight: true Layout.fillWidth: true TextArea { id: lessonTextArea text: root.lesson? root.lesson.text: "" onTextChanged: { if (root.lesson) { root.lesson.text = text } } placeholderText: i18n("Lesson text") font.family: "monospace" LessonTextHighlighter { document: lessonTextArea.textDocument allowedCharacters: root.visible? keyboardLayout.allCharacters(): "" } } } } footer: IconButton { text: i18n("Done") icon: "dialog-ok" bgColor: colorScheme.positiveBackground onClicked: { root.close() } } } diff --git a/src/qml/homescreen/ProfileDetailsItem.qml b/src/qml/homescreen/ProfileDetailsItem.qml index 8f83874..30b4bbe 100644 --- a/src/qml/homescreen/ProfileDetailsItem.qml +++ b/src/qml/homescreen/ProfileDetailsItem.qml @@ -1,275 +1,273 @@ /* * Copyright 2012 Sebastian Gottfried * Copyright 2015 Sebastian Gottfried * Copyright 2017 Sebastian Gottfried * * 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 2 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.2 import QtQuick.Layouts 1.3 -import org.kde.kcoreaddons 1.0 import org.kde.charts 0.1 as Charts import ktouch 1.0 import "../common" Item { id: root property Profile profile function update() { if (profile) { var isNewProfile = root.profile.id === -1 profileForm.name = profile.name profileForm.skillLevel = profile.skillLevel profileForm.skillLevelSelectionEnabled = isNewProfile deleteConfirmationLabel.name = profile.name state = isNewProfile? "editor": "info" } } signal deletionRequest(); onProfileChanged: update() SystemPalette { id: activePalette colorGroup: SystemPalette.Active } Item { id: infoContainer width: parent.width height: childrenRect.height anchors.centerIn: parent Column { width: parent.width height: childrenRect.height spacing: 40 LearningProgressModel { id: learningProgressModel profile: root.profile } Rectangle { anchors.horizontalCenter: parent.horizontalCenter width: parent.width - 40 height: 250 color: activePalette.base border { width: 1 color: activePalette.text } Column { id: column anchors { fill: parent topMargin: column.spacing + spacing + legend.height leftMargin: column.spacing rightMargin: column.spacing bottomMargin: column.spacing } spacing: 20 width: parent.width height: parent.height - legend.height - parent.spacing LearningProgressChart { id: learningProgressChart anchors.horizontalCenter: parent.horizontalCenter width: parent.width height: parent.height - legend.height - parent.spacing model: learningProgressModel } Row { id: legend anchors.horizontalCenter: parent.horizontalCenter spacing: 20 Charts.LegendItem { dimension: learningProgressChart.accuracy } Charts.LegendItem { dimension: learningProgressChart.charactersPerMinute } } } } InformationTable { id: profileInfoTable property int trainedLessonCount: profile && profile.id !== -1? profileDataAccess.lessonsTrained(profile): 0 property list infoModel: [ InfoItem { title: i18n("Lessons trained:") text: profile && profile.id !== -1? profileInfoTable.trainedLessonCount: "" }, InfoItem { title: i18n("Total training time:") text: profile && profile.id !== -1? Format.formatDuration(profileDataAccess.totalTrainingTime(profile)): "" }, InfoItem { title: i18n("Last trained:") text: profile && profile.id !== -1 && profileInfoTable.trainedLessonCount > 0? profileDataAccess.lastTrainingSession(profile).toLocaleDateString(): i18n("Never") } ] model: infoModel } } InlineToolbar { anchors { top: parent.top horizontalCenter: parent.horizontalCenter topMargin: 5 } content: [ IconToolButton { icon: "document-edit" text: i18n("Edit") onClicked: root.state = "editor" }, IconToolButton { icon: "edit-delete" text: i18n("Delete") enabled: profileDataAccess.profileCount > 1 onClicked: root.state = "deleteConfirmation" } ] } } Item { id: editorContainer width: parent.width - 40 height: childrenRect.height anchors.centerIn: parent ProfileForm { id: profileForm width: parent.width showWelcomeLabel: false onDone: { root.profile.name = profileForm.name root.profile.skillLevel = profileForm.skillLevel if (root.profile.id === -1) { profileDataAccess.addProfile(profile) } else { profileDataAccess.updateProfile(profileDataAccess.indexOfProfile(root.profile)) } root.update() root.state = "info" } } } Item { id: deleteConfirmationContainer width: parent.width - 40 height: childrenRect.height anchors.centerIn: parent Column { width: parent.width height: childrenRect.height spacing: 15 Label { property string name id: deleteConfirmationLabel width: parent.width text: i18n("Do you really want to delete the profile \"%1\"?", name) wrapMode: Text.Wrap horizontalAlignment: Text.AlignHCenter } Row { spacing: 10 anchors.horizontalCenter: parent.horizontalCenter width: childrenRect.width height: childrenRect.height IconButton { icon: "edit-delete" text: i18n("Delete") bgColor: colorScheme.negativeBackground onClicked: root.deletionRequest() } IconButton { text: i18n("Cancel") onClicked: root.state = "info" } } } } states: [ State { name: "info" PropertyChanges { target: infoContainer visible: true } PropertyChanges { target: editorContainer visible: false } PropertyChanges { target: deleteConfirmationContainer visible: false } }, State { name: "editor" PropertyChanges { target: infoContainer visible: false } PropertyChanges { target: editorContainer visible: true } PropertyChanges { target: deleteConfirmationContainer visible: false } }, State { name: "deleteConfirmation" PropertyChanges { target: infoContainer visible: false } PropertyChanges { target: editorContainer visible: false } PropertyChanges { target: deleteConfirmationContainer visible: true } } ] } diff --git a/src/qml/homescreen/ProfileSelector.qml b/src/qml/homescreen/ProfileSelector.qml index dcdb855..ec5cbcc 100644 --- a/src/qml/homescreen/ProfileSelector.qml +++ b/src/qml/homescreen/ProfileSelector.qml @@ -1,121 +1,120 @@ /* * Copyright 2012 Sebastian Gottfried * Copyright 2015 Sebastian Gottfried * Copyright 2017 Sebastian Gottfried * * 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 2 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.2 import QtQuick.Layouts 1.3 import ktouch 1.0 import "../common" FocusScope { id: root signal profileChosen(variant profile) function createNewProfile() { var profile = profileDataAccess.createProfile() profileForm.profile = profile } function selectProfile(index) { list.currentIndex = index profileForm.profile = profileDataAccess.profile(index) } KColorScheme { id: listColorScheme colorGroup: KColorScheme.Active colorSet: KColorScheme.View } ColumnLayout { anchors.fill: parent spacing: 0 RowLayout { Layout.fillWidth: true Layout.fillHeight: true ListView { id: list Layout.fillWidth: true Layout.fillHeight: true model: profileDataAccess.profileCount + 1 clip: true delegate: ListItem { property bool isNewButton: index >= profileDataAccess.profileCount width: list.width text: isNewButton? i18n("Create New Profile"): index < profileDataAccess.profileCount? profileDataAccess.profile(index).name: null label.font.italic: isNewButton icon: isNewButton? "list-add": "user-identity" highlighted: ListView.isCurrentItem onClicked: { list.forceActiveFocus() list.currentIndex = index if (isNewButton) { createNewProfile() } else { selectProfile(index) } } onDoubleClicked: { if (!isNewButton) { root.profileChosen(profileDataAccess.profile(list.currentIndex)) } } } onCurrentItemChanged: { if (currentItem.isNewButton) { createNewProfile() } else { selectProfile(currentIndex) } } } ProfileDetailsItem { id: profileForm Layout.fillWidth: true Layout.fillHeight: true onDeletionRequest: { var index = profileDataAccess.indexOfProfile(profileForm.profile) profileForm.profile = null profileDataAccess.removeProfile(index) selectProfile(Math.max(0, list.currentIndex - 1)) } } } IconButton { id: selectButton Layout.fillWidth: true icon: "go-next-view" text: i18n("Use Selected Profile") enabled: list.currentIndex !== -1 && list.currentIndex < profileDataAccess.profileCount bgColor: colorScheme.positiveBackground onClicked: root.profileChosen(profileDataAccess.profile(list.currentIndex)) } } } diff --git a/src/qml/homescreen/StatPopupDialog.qml b/src/qml/homescreen/StatPopupDialog.qml index ce90929..63dbf0f 100644 --- a/src/qml/homescreen/StatPopupDialog.qml +++ b/src/qml/homescreen/StatPopupDialog.qml @@ -1,90 +1,90 @@ /* * Copyright 2017 Sebastian Gottfried * * 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 2 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.2 import QtQuick.Layouts 1.3 import ktouch 1.0 import org.kde.charts 0.1 as Charts import '../common' PopupDialog { id: root property alias course: learningProgressModel.courseFilter property alias lesson: learningProgressModel.lessonFilter property alias profile: learningProgressModel.profile title: i18n("Lesson training statistics") modal: true margins: { left: 40 bottom: 40 right: 40 top: 40 } width: parent.width - leftMargin - rightMargin height: parent.height - topMargin - bottomMargin padding: 0 contentItem: Rectangle { color: colorScheme.normalBackground ColumnLayout { anchors.fill: parent anchors.margins: titleLabel.font.pixelSize spacing: titleLabel.font.pixelSize Label { id: titleLabel text: lesson? lesson.title: "" font.bold: true } LearningProgressChart { id: learningProgressChart Layout.fillHeight: true Layout.fillWidth: true backgroundColor: colorScheme.normalBackground model: LearningProgressModel { id: learningProgressModel } } + Row { spacing: 2 * titleLabel.font.pixelSize Layout.alignment: Qt.AlignTop | Qt.AlignHCenter Charts.LegendItem { id: accuracyLegend dimension: learningProgressChart.accuracy } Charts.LegendItem { id: charactersPerMinuteLegend dimension: learningProgressChart.charactersPerMinute } } } KColorScheme { id: colorScheme colorGroup: KColorScheme.Active colorSet: KColorScheme.View } } }