Improve visuals and usability

Usability has been improved when entering new rows into the database.
The user is now only able to write in the input form when editing
an exiting entry or creating a new entry. The warning message associated
with entering invalid input will now disappear after a few seconds.
The ListView delegate is now slightly larger, and looks slightly better.

Task-number: QTBUG-90884
Change-Id: Idf7ca9c0bb8b86ac06fed80e945800603f7b03d9
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
This commit is contained in:
Oliver Eftevaag 2021-02-10 14:51:42 +01:00
parent e8edea4e95
commit 7b263f7bf5
3 changed files with 130 additions and 46 deletions

View File

@ -1,4 +1,3 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
@ -60,7 +59,8 @@ Item {
height: Screen.height / 7
required property ListView listView
required property Text statusText
signal statusMessage(string msg)
enabled: false
function insertrec() {
var rowid = parseInt(JS.dbInsert(dateInput.text, descInput.text, distInput.text), 10)
@ -125,19 +125,19 @@ Item {
anchors.fill: parent
Label {
text: "Date"
text: qsTr("Date")
font.pixelSize: 22
rightPadding: 10
}
Label {
text: "Description"
text: qsTr("Description")
font.pixelSize: 22
rightPadding: 10
}
Label {
text: "Distance"
text: qsTr("Distance")
font.pixelSize: 22
}
@ -146,14 +146,29 @@ Item {
font.pixelSize: 22
activeFocusOnPress: true
activeFocusOnTab: true
validator: RegularExpressionValidator {
regularExpression: /[0-9/,:.]+/
ToolTip {
parent: dateInput
x: parent.width + 3
y: (parent.height - height) / 2
text: qsTr("Date format = 'YYYY-MM-DD'")
visible: parent.enabled && parent.hovered
delay: 1000
}
onEditingFinished: {
if (dateInput.text == "") {
root.statusText.text = "Please fill in the date"
dateInput.forceActiveFocus()
}
validator: RegularExpressionValidator {
regularExpression: /\d{4}[,.:/-]\d\d?[,.:/-]\d\d?/
}
onFocusChanged: ()=> {
if (!dateInput.focus && !acceptableInput && root.enabled)
root.statusMessage(qsTr("Please fill in the date"));
}
onEditingFinished: ()=> {
let regex = /(\d+)[,.:/-](\d+)[,.:/-](\d+)/
if (dateInput.text.match(regex))
dateInput.text = dateInput.text.replace(regex, '$1-$2-$3')
}
}
@ -162,13 +177,11 @@ Item {
font.pixelSize: 22
activeFocusOnPress: true
activeFocusOnTab: true
onEditingFinished: {
if (descInput.text.length < 8) {
root.statusText.text = "Enter a description of minimum 8 characters"
descInput.forceActiveFocus()
} else {
root.statusText.text = ""
}
property string oldString
onFocusChanged: ()=> { if (focus) oldString = descInput.text; }
onEditingFinished: ()=> {
if (descInput.text.length < 8 && descInput.text != descInput.oldString && root.enabled)
root.statusMessage(qsTr("Enter a description of minimum 8 characters"))
}
}
@ -180,11 +193,11 @@ Item {
validator: RegularExpressionValidator {
regularExpression: /\d{1,3}/
}
onEditingFinished: {
if (distInput.text == "") {
root.statusText.text = "Please fill in the distance"
distInput.forceActiveFocus()
}
property string oldString
onFocusChanged: ()=> { if (focus) oldString = distInput.text; }
onEditingFinished: ()=> {
if (distInput.text == "" && distInput.text != distInput.oldString && root.enabled)
root.statusMessage(qsTr("Please fill in the distance"))
}
}
}

View File

@ -57,8 +57,8 @@ import "Database.js" as JS
Item {
id: delegate
width: parent.width
height: rDate.implicitHeight
width: ListView.view.width
implicitHeight: rDate.implicitHeight * 1.5
required property int index
required property int distance
@ -72,34 +72,43 @@ Item {
anchors.fill: parent
opacity: 0.8
color: delegate.index % 2 ? "lightgrey" : "grey"
border.width: 2
border.color: Qt.lighter(color)
radius: 5
MouseArea {
anchors.fill: parent
onClicked: delegate.clicked()
}
GridLayout {
anchors.fill:parent
columns: 3
RowLayout {
anchors.fill: parent
Label {
id: rDate
Layout.preferredWidth: 42
Layout.alignment: Qt.AlignCenter
horizontalAlignment: Text.AlignHCenter
text: delegate.date
font.pixelSize: 22
Layout.preferredWidth: parent.width / 4
color: "black"
}
Label {
id: rDesc
Layout.preferredWidth: 42
Layout.alignment: Qt.AlignCenter
horizontalAlignment: Text.AlignHCenter
text: delegate.trip_desc
Layout.fillWidth: true
font.pixelSize: 22
color: "black"
}
Label {
id: rDistance
Layout.preferredWidth: 42
Layout.alignment: Qt.AlignCenter
horizontalAlignment: Text.AlignHCenter
text: delegate.distance
font.pixelSize: 22
Layout.alignment: Qt.AlignRight
color: "black"
}
}

View File

@ -69,16 +69,18 @@ Window {
ColumnLayout {
anchors.fill: parent
anchors.margins: 10
Header {
id: input
Layout.fillWidth: true
listView: listView
statusText: statustext
enabled: window.creatingNewEntry || window.editingEntry
}
RowLayout {
Button {
text: "New"
text: qsTr("New")
onClicked: {
input.initrec_new()
window.creatingNewEntry = true
@ -88,7 +90,7 @@ Window {
Button {
id: saveButton
enabled: (window.creatingNewEntry || window.editingEntry) && listView.currentIndex != -1
text: "Save"
text: qsTr("Save")
onClicked: {
var insertedRow = false;
if (listView.model.get(listView.currentIndex).id < 1) {
@ -99,7 +101,7 @@ Window {
insertedRow = true
} else {
// Failed to insert a row; display an error message.
statustext.text = "Failed to insert row"
statustext.displayWarning(qsTr("Failed to insert row"))
}
} else {
// edit mode
@ -120,7 +122,7 @@ Window {
}
Button {
id: editButton
text: "Edit"
text: qsTr("Edit")
enabled: !window.creatingNewEntry && !window.editingEntry && listView.currentIndex != -1
onClicked: {
input.editrec(listView.model.get(listView.currentIndex).date,
@ -133,7 +135,7 @@ Window {
}
Button {
id: deleteButton
text: "Delete"
text: qsTr("Delete")
enabled: !window.creatingNewEntry && listView.currentIndex != -1
onClicked: {
JS.dbDeleteRow(listView.model.get(listView.currentIndex).id)
@ -147,7 +149,7 @@ Window {
}
Button {
id: cancelButton
text: "Cancel"
text: qsTr("Cancel")
enabled: (window.creatingNewEntry || window.editingEntry) && listView.currentIndex != -1
onClicked: {
if (listView.model.get(listView.currentIndex).id === 0) {
@ -162,10 +164,19 @@ Window {
}
}
Button {
text: "Exit"
text: qsTr("Exit")
onClicked: Qt.quit()
}
}
Item {
Layout.fillWidth: true
height: 5
}
Label {
Layout.alignment: Qt.AlignCenter
text: qsTr("Saved activities")
font.pointSize: 15
}
Component {
id: highlightBar
Rectangle {
@ -180,7 +191,8 @@ Window {
Layout.fillHeight: true
model: MyModel {}
delegate: MyDelegate {
onClicked: listView.currentIndex = index
width: listView.width
onClicked: ()=> listView.currentIndex = index
}
// Don't allow changing the currentIndex while the user is creating/editing values.
enabled: !window.creatingNewEntry && !window.editingEntry
@ -188,20 +200,70 @@ Window {
highlight: highlightBar
highlightFollowsCurrentItem: true
focus: true
clip: true
header: Component {
Text {
text: "Saved activities"
RowLayout {
property var headerTitles: [qsTr("Date"), qsTr("Description"), qsTr("Distance")]
width: ListView.view.width
Repeater {
model: headerTitles
delegate: Label {
id: headerTitleDelegate
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredWidth: 1
text: modelData
font.pointSize: 15
font.bold: true
font.underline: true
padding: 12
horizontalAlignment: Label.AlignHCenter
}
}
}
}
}
Label {
id: statustext
color: "red"
Layout.fillWidth: true
font.bold: true
font.pointSize: 20
opacity: 0.0
visible: opacity !== 0 // properly cull item if effectively invisible
Layout.alignment: Layout.Center
function displayWarning(text) {
statustext.text = text
statusAnim.restart()
}
Connections {
target: input
function onStatusMessage(msg) { statustext.displayWarning(msg); }
}
SequentialAnimation {
id: statusAnim
OpacityAnimator {
target: statustext
from: 0.0
to: 1.0
duration: 50
}
PauseAnimation {
duration: 2000
}
OpacityAnimator {
target: statustext
from: 1.0
to: 0.0
duration: 50
}
}
}
}
}