diff --git a/app/qml/CMakeLists.txt b/app/qml/CMakeLists.txt index c985034e4..a027c7f72 100644 --- a/app/qml/CMakeLists.txt +++ b/app/qml/CMakeLists.txt @@ -64,13 +64,13 @@ set(MM_QML filters/MMFiltersPanel.qml filters/components/MMFilterBanner.qml filters/components/MMFilterBoolInput.qml - filters/components/MMFilterDateRange.qml + filters/components/MMFilterDateRangeInput.qml filters/components/MMFilterDropdownValueMapInput.qml filters/components/MMFilterDropdownValueRelationInput.qml filters/components/MMFilterDropdownUniqueValuesInput.qml - filters/components/MMFilterRangeInput.qml - filters/components/MMFilterTextEditor.qml + filters/components/MMFilterNumberRangeInput.qml filters/components/MMFilterTextInput.qml + filters/components/private/MMFilterBaseInput.qml dialogs/MMCloseAccountDialog.qml dialogs/MMDownloadProjectDialog.qml dialogs/MMMigrateToMerginDialog.qml diff --git a/app/qml/filters/MMFiltersPanel.qml b/app/qml/filters/MMFiltersPanel.qml index 7093a78da..a35decf00 100644 --- a/app/qml/filters/MMFiltersPanel.qml +++ b/app/qml/filters/MMFiltersPanel.qml @@ -128,16 +128,16 @@ MMComponents.MMDrawer { if ( filterType === FieldFilter.TextFilter ) { - setSource( "components/MMFilterTextEditor.qml", props ) + setSource( "components/MMFilterTextInput.qml", props ) } else if ( filterType === FieldFilter.NumberFilter ) { - setSource( "components/MMFilterRangeInput.qml", props ) + setSource( "components/MMFilterNumberRangeInput.qml", props ) } else if ( filterType === FieldFilter.DateFilter ) { props['hasTime'] = __activeProject.filterController.isDateFilterDateTime(modelData.filterId) - setSource( "components/MMFilterDateRange.qml", props ) + setSource( "components/MMFilterDateRangeInput.qml", props ) } else if ( filterType === FieldFilter.CheckboxFilter ) { diff --git a/app/qml/filters/components/MMFilterBoolInput.qml b/app/qml/filters/components/MMFilterBoolInput.qml index d931044fb..234a8cde1 100644 --- a/app/qml/filters/components/MMFilterBoolInput.qml +++ b/app/qml/filters/components/MMFilterBoolInput.qml @@ -43,8 +43,8 @@ Column { width: parent.width backgroundColor: __style.lightGreenColor - trueText: customLabelForTrue ? customLabelForTrue : qsTr( "True" ) - falseText: customLabelForFalse ? customLabelForFalse : qsTr( "False" ) + trueText: root.customLabelForTrue ? root.customLabelForTrue : qsTr( "True" ) + falseText: root.customLabelForFalse ? root.customLabelForFalse : qsTr( "False" ) Component.onCompleted: { if ( root.currentValue && root.currentValue.length === 1 ) diff --git a/app/qml/filters/components/MMFilterDateRange.qml b/app/qml/filters/components/MMFilterDateRange.qml deleted file mode 100644 index d42cae48d..000000000 --- a/app/qml/filters/components/MMFilterDateRange.qml +++ /dev/null @@ -1,213 +0,0 @@ -/*************************************************************************** - * * - * 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. * - * * - ***************************************************************************/ -pragma ComponentBehavior: Bound - -import QtQuick - -import "../../components" -import "../../form/components" as MMFormComponents - -Column { - id: root - - width: parent.width - spacing: __style.margin8 - - required property string filterName - required property var currentValue - required property bool hasTime - - property bool rangeInvalid: { - if ( !currentValue || !currentValue[0] || !currentValue[1] ){ - return false - } - return currentValue[0] > currentValue[1] - } - - MMText { - width: parent.width - text: root.filterName - font: __style.p6 - color: __style.nightColor - } - - Row { - width: parent.width - spacing: __style.margin12 - - Item { - width: ( parent.width - __style.margin12 ) / 2 - height: fromDateInput.height - - MMFilterTextInput { - id: fromDateInput - - width: parent.width - type: MMFilterTextInput.InputType.Date - placeholderText: qsTr( "From" ) - errorMsg: root.rangeInvalid ? qsTr( "\"From\" must be sooner than \"To\"" ) : "" - text: { - if ( !root.currentValue || !root.currentValue[0] ) return "" - if ( root.hasTime ) return Qt.formatDateTime( root.currentValue[0] ) - return Qt.formatDate( root.currentValue[0] ) - } - - onTextClicked: fromCalendarLoader.active = true - onRightContentClicked: { - if (checked) { - textField.clear() - checked = false - if ( root.currentValue[1] ){ - root.currentValue = [undefined, root.currentValue[1]] - } else { - root.currentValue = undefined - } - root.currentValueChanged() - } else { - let currentTimestamp = new Date() - - if (root.hasTime) { - text = Qt.formatDateTime(currentTimestamp) - } else { - text = Qt.formatDate(currentTimestamp) - } - - if (!root.hasTime) { - currentTimestamp.setHours(0, 0, 0, 0) - } - if (!root.currentValue) { - root.currentValue = [currentTimestamp, undefined] - } else { - root.currentValue[0] = currentTimestamp - } - root.currentValueChanged() - } - } - } - - Loader { - id: fromCalendarLoader - active: false - sourceComponent: fromCalendarComponent - } - - Component { - id: fromCalendarComponent - - MMFormComponents.MMCalendarDrawer { - hasDatePicker: true - hasTimePicker: root.hasTime - dateTime: root.currentValue && root.currentValue[0] ? root.currentValue[0] : new Date() - - onPrimaryButtonClicked: { - let currentTimestamp = dateTime - if (!root.hasTime) { - currentTimestamp.setHours(0, 0, 0, 0) - } - if (!root.currentValue){ - root.currentValue = [currentTimestamp, undefined] - } else { - root.currentValue[0] = currentTimestamp - root.currentValueChanged() - } - - fromDateInput.text = root.hasTime ? Qt.formatDateTime(dateTime) : Qt.formatDate(dateTime) - } - onClosed: fromCalendarLoader.active = false - Component.onCompleted: open() - } - } - } - - Item { - width: ( parent.width - __style.margin12 ) / 2 - height: toDateInput.height - - MMFilterTextInput { - id: toDateInput - - width: parent.width - type: MMFilterTextInput.InputType.Date - placeholderText: qsTr( "To" ) - errorMsg: root.rangeInvalid ? qsTr( "\"From\" must be sooner than \"To\"" ) : "" - text: { - if ( !root.currentValue || !root.currentValue[1] ) return "" - if ( root.hasTime ) return Qt.formatDateTime( root.currentValue[1] ) - return Qt.formatDate( root.currentValue[1] ) - } - - onTextClicked: toCalendarLoader.active = true - onRightContentClicked: { - if (checked) { - textField.clear() - checked = false - if ( root.currentValue[0] ){ - root.currentValue = [root.currentValue[0], undefined] - } else { - root.currentValue = undefined - } - root.currentValueChanged() - - } else { - let currentTimestamp = new Date() - - if (root.hasTime) { - text = Qt.formatDateTime(currentTimestamp) - } else { - text = Qt.formatDate(currentTimestamp) - } - - if (!root.hasTime) { - currentTimestamp.setHours(0, 0, 0, 0) - } - if (!root.currentValue) { - root.currentValue = [undefined, currentTimestamp] - } else { - root.currentValue[1] = currentTimestamp - root.currentValueChanged() - } - } - } - } - - Loader { - id: toCalendarLoader - active: false - sourceComponent: toCalendarComponent - } - - Component { - id: toCalendarComponent - - MMFormComponents.MMCalendarDrawer { - hasDatePicker: true - hasTimePicker: root.hasTime - dateTime: root.currentValue && root.currentValue[1] ? root.currentValue[1] : new Date() - - onPrimaryButtonClicked: { - let currentTimestamp = dateTime - if (!root.hasTime) { - currentTimestamp.setHours(0, 0, 0, 0) - } - if (!root.currentValue){ - root.currentValue = [undefined, currentTimestamp] - } else { - root.currentValue[1] = currentTimestamp - } - root.currentValueChanged() - - toDateInput.text = root.hasTime ? Qt.formatDateTime(dateTime) : Qt.formatDate(dateTime) - } - onClosed: toCalendarLoader.active = false - Component.onCompleted: open() - } - } - } - } -} diff --git a/app/qml/filters/components/MMFilterDateRangeInput.qml b/app/qml/filters/components/MMFilterDateRangeInput.qml new file mode 100644 index 000000000..89bab3fe7 --- /dev/null +++ b/app/qml/filters/components/MMFilterDateRangeInput.qml @@ -0,0 +1,168 @@ +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ +pragma ComponentBehavior: Bound + +import QtQuick + +import "../../components" +import "../../form/components" as MMFormComponents +import "./private" + +Column { + id: root + + width: parent.width + spacing: __style.margin8 + + required property string filterName + required property var currentValue + required property bool hasTime + + MMText { + width: parent.width + text: root.filterName + font: __style.p6 + color: __style.nightColor + } + + MMFilterBaseInput { + id: filterInput + + width: root.width + + doubleInput: true + primaryPlaceholderText: qsTr( "From" ) + secondaryPlaceholderText: qsTr( "To" ) + errorMsg: rangeInvalid ? qsTr( "\"From\" must be sooner than \"To\"" ) : "" + primaryText: { + if ( !root.currentValue || !root.currentValue[0] ) return "" + if ( root.hasTime ) return Qt.formatDateTime( root.currentValue[0] ) + return Qt.formatDate( root.currentValue[0] ) + } + secondaryText: { + if ( !root.currentValue || !root.currentValue[1] ) return "" + if ( root.hasTime ) return Qt.formatDateTime( root.currentValue[1] ) + return Qt.formatDate( root.currentValue[1] ) + } + + onPrimaryTextClicked: { + calendarLoader.callerIndex = 0 + calendarLoader.active = true + } + onSecondaryTextClicked: { + calendarLoader.callerIndex = 1 + calendarLoader.active = true + } + + onPrimaryRightContentClicked: (isChecked) => { + if (isChecked) { + if ( root.currentValue[1] ){ + root.currentValue = [undefined, root.currentValue[1]] + } else { + root.currentValue = undefined + } + root.currentValueChanged() + } else { + let currentTimestamp = new Date() + + if (root.hasTime) { + filterInput.primaryText = Qt.formatDateTime(currentTimestamp) + } else { + filterInput.primaryText = Qt.formatDate(currentTimestamp) + } + + if (!root.hasTime) { + currentTimestamp.setHours(0, 0, 0, 0) + } + if (!root.currentValue) { + root.currentValue = [currentTimestamp, undefined] + } else { + root.currentValue[0] = currentTimestamp + } + root.currentValueChanged() + } + } + + onSecondaryRightContentClicked: (isChecked) => { + if (isChecked) { + if ( root.currentValue[0] ){ + root.currentValue = [root.currentValue[0], undefined] + } else { + root.currentValue = undefined + } + root.currentValueChanged() + + } else { + let currentTimestamp = new Date() + + if (root.hasTime) { + filterInput.secondaryText = Qt.formatDateTime(currentTimestamp) + } else { + filterInput.secondaryText = Qt.formatDate(currentTimestamp) + } + + if (!root.hasTime) { + currentTimestamp.setHours(0, 0, 0, 0) + } + if (!root.currentValue) { + root.currentValue = [undefined, currentTimestamp] + } else { + root.currentValue[1] = currentTimestamp + root.currentValueChanged() + } + } + } + + property bool rangeInvalid: { + if ( !root.currentValue || !root.currentValue[0] || !root.currentValue[1] ){ + return false + } + return root.currentValue[0] > root.currentValue[1] + } + } + + Loader { + id: calendarLoader + + property int callerIndex + active: false + sourceComponent: calendarComponent + } + + Component { + id: calendarComponent + + MMFormComponents.MMCalendarDrawer { + hasDatePicker: true + hasTimePicker: root.hasTime + dateTime: root.currentValue && root.currentValue[calendarLoader.callerIndex] ? root.currentValue[calendarLoader.callerIndex] : new Date() + + onPrimaryButtonClicked: { + let currentTimestamp = dateTime + if (!root.hasTime) { + currentTimestamp.setHours(0, 0, 0, 0) + } + if (!root.currentValue){ + root.currentValue = calendarLoader.callerIndex ? [undefined, currentTimestamp] : [currentTimestamp, undefined] + } else { + root.currentValue[calendarLoader.callerIndex] = currentTimestamp + root.currentValueChanged() + } + + if ( calendarLoader.callerIndex ){ + filterInput.secondaryText = root.hasTime ? Qt.formatDateTime(dateTime) : Qt.formatDate(dateTime) + } else { + filterInput.primaryText = root.hasTime ? Qt.formatDateTime(dateTime) : Qt.formatDate(dateTime) + } + } + onClosed: calendarLoader.active = false + Component.onCompleted: open() + } + } +} diff --git a/app/qml/filters/components/MMFilterRangeInput.qml b/app/qml/filters/components/MMFilterNumberRangeInput.qml similarity index 59% rename from app/qml/filters/components/MMFilterRangeInput.qml rename to app/qml/filters/components/MMFilterNumberRangeInput.qml index 38774a6dd..438014d4c 100644 --- a/app/qml/filters/components/MMFilterRangeInput.qml +++ b/app/qml/filters/components/MMFilterNumberRangeInput.qml @@ -8,8 +8,10 @@ ***************************************************************************/ import QtQuick +import QtQml import "../../components" +import "./private" Column { id: root @@ -27,44 +29,30 @@ Column { color: __style.nightColor } - Row { - id: rangeRow + MMFilterBaseInput { + id: filterInput - width: parent.width - spacing: __style.margin12 - - property bool rangeInvalid: { - let fromVal = parseFloat( fromInput.text ) - let toVal = parseFloat( toInput.text ) - return !isNaN( fromVal ) && !isNaN( toVal ) && fromVal > toVal - } - - MMFilterTextInput { - id: fromInput + width: root.width - width: ( parent.width - __style.margin12 ) / 2 - type: MMFilterTextInput.InputType.Number - placeholderText: qsTr( "Min" ) - text: root.currentValue && root.currentValue[0] ? root.currentValue[0] : "" - errorMsg: rangeRow.rangeInvalid ? qsTr( "\"Min\" must be less than \"Max\"" ) : "" + doubleInput: true + primaryPlaceholderText: qsTr( "Min" ) + secondaryPlaceholderText: qsTr( "Max" ) + primaryText: root.currentValue && root.currentValue[0] ? root.currentValue[0] : "" + secondaryText: root.currentValue && root.currentValue[1] ? root.currentValue[1] : "" + errorMsg: rangeRow.rangeInvalid ? qsTr( "\"Min\" must be less than \"Max\"" ) : "" - onTextChanged: { - debounceTimer.restart() - } + onPrimaryTextChanged: { + debounceTimer.restart() } - MMFilterTextInput { - id: toInput - - width: ( parent.width - __style.margin12 ) / 2 - type: MMFilterTextInput.InputType.Number - placeholderText: qsTr( "Max" ) - text: root.currentValue && root.currentValue[1] ? root.currentValue[1] : "" - errorMsg: rangeRow.rangeInvalid ? qsTr( "\"Min\" must be less than \"Max\"" ) : "" + onSecondaryTextChanged: { + debounceTimer.restart() + } - onTextChanged: { - debounceTimer.restart() - } + property bool rangeInvalid: { + let fromVal = parseFloat( filterInput.primaryText ) + let toVal = parseFloat( filterInput.secondaryText ) + return !isNaN( fromVal ) && !isNaN( toVal ) && fromVal > toVal } } @@ -74,14 +62,14 @@ Column { repeat: false onTriggered: { let newValues = [] - const valueFrom = parseFloat(fromInput.text) + const valueFrom = parseFloat( filterInput.primaryText ) if ( !isNaN(valueFrom) ) { newValues[0] = valueFrom } else { newValues[0] = undefined } - const valueTo = parseFloat(toInput.text) + const valueTo = parseFloat( filterInput.secondaryText ) if ( !isNaN(valueTo) ) { newValues[1] = valueTo } else { diff --git a/app/qml/filters/components/MMFilterTextEditor.qml b/app/qml/filters/components/MMFilterTextEditor.qml deleted file mode 100644 index 68f072d88..000000000 --- a/app/qml/filters/components/MMFilterTextEditor.qml +++ /dev/null @@ -1,55 +0,0 @@ -/*************************************************************************** - * * - * 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. * - * * - ***************************************************************************/ - -import QtQuick - -import "../../components" - -Column { - id: root - - width: parent.width - spacing: __style.margin8 - - required property string filterName - required property var currentValue - - MMText { - width: parent.width - - text: root.filterName - - font: __style.p6 - color: __style.nightColor - } - - MMFilterTextInput { - id: filterInput - - width: parent.width - type: MMFilterTextInput.InputType.Text - placeholderText: qsTr( "Type to filter..." ) - text: root.currentValue && root.currentValue[0] ? root.currentValue[0] : "" - - onTextChanged: debounceTimer.restart() - } - - Timer { - id: debounceTimer - interval: 300 - repeat: false - onTriggered: { - if (filterInput.text) { - root.currentValue = [filterInput.text] - } else { - root.currentValue = undefined - } - } - } -} diff --git a/app/qml/filters/components/MMFilterTextInput.qml b/app/qml/filters/components/MMFilterTextInput.qml index 360f3cec0..03248416f 100644 --- a/app/qml/filters/components/MMFilterTextInput.qml +++ b/app/qml/filters/components/MMFilterTextInput.qml @@ -8,86 +8,49 @@ ***************************************************************************/ import QtQuick +import QtQml -import "../../components" as MMComponents -import "../../components/private" as MMPrivateComponents +import "../../components" +import "./private" -/** - * Single-line input for the filters panel. - * See MMBaseSingleLineInput for additional properties. - */ -MMPrivateComponents.MMBaseSingleLineInput { +Column { id: root - enum InputType { Text, Number, Date, Dropdown } + width: parent.width + spacing: __style.margin8 - property bool checked: false - property int type: MMFilterTextInput.InputType.Text + required property string filterName + required property var currentValue - // date and dropdown types open pickers instead of accepting keyboard input - textField.readOnly: root.type === MMFilterTextInput.InputType.Date || root.type === MMFilterTextInput.InputType.Dropdown - textField.color: { - if ( root.editState === "readOnly" ) return __style.nightColor - if ( root.editState === "enabled" ) return __style.nightColor - if ( root.editState === "disabled" ) return __style.mediumGreyColor - return __style.forestColor - } + MMText { + width: parent.width - // error state takes priority over checked, checked over default - textFieldBackground.color: { - if ( root.validationState === "error" ) return __style.negativeUltraLightColor - if ( root.checked ) return __style.positiveColor - return __style.lightGreenColor - } + text: root.filterName - textFieldBackground.border.color: { - if ( root.validationState === "error" ) return __style.negativeColor - if ( root.checked ) return __style.darkGreenColor - return __style.polarColor + font: __style.p6 + color: __style.nightColor } - textFieldBackground.border.width: { - if ( root.validationState === "error" ) return __style.width2 - if ( root.checked ) return 1 * __dp - return 0 - } + MMFilterBaseInput { + id: filterInput - // close icon when checked, type-specific icon otherwise - rightContent: MMComponents.MMIcon { - size: __style.icon24 - source: { - if ( root.checked ) return __style.closeIcon - if ( root.type === MMFilterTextInput.InputType.Date ) return __style.calendarIcon - if ( root.type === MMFilterTextInput.InputType.Dropdown ) return __style.arrowDownIcon - return __style.closeIcon - } - color: __style.forestColor - } + width: root.width + primaryPlaceholderText: qsTr( "Type to filter..." ) + primaryText: root.currentValue && root.currentValue[0] ? root.currentValue[0] : "" - // picker types always show the icon, editable types only when there is a value - rightContentVisible: { - if ( root.type === MMFilterTextInput.InputType.Text || root.type === MMFilterTextInput.InputType.Number ) return root.checked - return true - } - - // keep checked in sync with whether the field has a value - onTextChanged: { - if ( root.type === MMFilterTextInput.InputType.Text || root.type === MMFilterTextInput.InputType.Number ) { - root.checked = false - } - } - - // clear the field when tapping the close icon - onRightContentClicked: { - if ( ( root.type === MMFilterTextInput.InputType.Text || root.type === MMFilterTextInput.InputType.Number ) && root.checked ) { - textField.clear() - root.checked = false - } + onPrimaryTextChanged: debounceTimer.restart() } - Component.onCompleted: { - if ( root.text ) { - root.checked = true + Timer { + id: debounceTimer + interval: 300 + repeat: false + onTriggered: { + if (filterInput.text) { + root.currentValue = [filterInput.text] + } else { + root.currentValue = undefined + } } } } diff --git a/app/qml/filters/components/private/MMFilterBaseInput.qml b/app/qml/filters/components/private/MMFilterBaseInput.qml new file mode 100644 index 000000000..8b5c89bd7 --- /dev/null +++ b/app/qml/filters/components/private/MMFilterBaseInput.qml @@ -0,0 +1,227 @@ +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +import QtQuick +import QtQuick.Layouts + +import "../../../components" as MMComponents +import "../../../components/private" as MMPrivateComponents + +/** + * Single-line input for the filters panel. Encapsulates either one or two inputs in one Row. + */ +Row { + id: root + + property bool doubleInput: false + property bool disabledKeyboardInput: false + property url iconSource + property string errorMsg + + property alias primaryPlaceholderText: primaryInput.placeholderText + property alias secondaryPlaceholderText: secondaryInput.placeholderText + property alias primaryText: primaryInput.text + property alias secondaryText: secondaryInput.text + + signal primaryTextClicked() + signal secondaryTextClicked() + signal primaryRightContentClicked( bool isChecked ) + signal secondaryRightContentClicked( bool isChecked ) + + spacing: __style.margin12 + + MMPrivateComponents.MMBaseSingleLineInput { + id: primaryInput + + property bool checked: false + + textField.readOnly: root.disabledKeyboardInput + + shouldShowValidation: !root.doubleInput + + textField.color: { + if (primaryInput.editState === "readOnly") return __style.nightColor + if (primaryInput.editState === "enabled") return __style.nightColor + if (primaryInput.editState === "disabled") return __style.mediumGreyColor + return __style.forestColor + } + + // error state takes priority over checked, checked over default + textFieldBackground.color: { + if (primaryInput.validationState === "error") return __style.negativeUltraLightColor + if (primaryInput.checked) return __style.positiveColor + return __style.lightGreenColor + } + + textFieldBackground.border.color: { + if (primaryInput.validationState === "error") return __style.negativeColor + if (primaryInput.checked) return __style.darkGreenColor + return __style.polarColor + } + + textFieldBackground.border.width: { + if (primaryInput.validationState === "error") return __style.width2 + if (primaryInput.checked) return 1 * __dp + return 0 + } + + // close icon when checked, type-specific icon otherwise + rightContent: MMComponents.MMIcon + { + size: __style.icon24 + source: { + if (primaryInput.checked) return __style.closeIcon + return root.iconSource + } + color: __style.forestColor + } + + rightContentVisible: { + if (root.iconSource) return primaryInput.checked + return true + } + + // keep checked in sync with whether the field has a value + onTextEdited: (newText) => { + primaryInput.checked = newText.length + } + + onTextClicked: { + root.primaryTextClicked() + } + + // clear the field when tapping the close icon + onRightContentClicked: { + if ( primaryInput.checked ) { + textField.clear() + root.primaryRightContentClicked( true ) + primaryInput.checked = false + } else { + root.primaryRightContentClicked( false ) + } + } + + Component.onCompleted: { + if (primaryInput.text) { + primaryInput.checked = true + } + } + } + + MMPrivateComponents.MMBaseSingleLineInput { + id: secondaryInput + + property bool checked: false + + visible: root.doubleInput + + shouldShowValidation: false + textField.readOnly: root.disabledKeyboardInput + + textField.color: { + if (secondaryInput.editState === "readOnly") return __style.nightColor + if (secondaryInput.editState === "enabled") return __style.nightColor + if (secondaryInput.editState === "disabled") return __style.mediumGreyColor + return __style.forestColor + } + + // error state takes priority over checked, checked over default + textFieldBackground.color: { + if (secondaryInput.validationState === "error") return __style.negativeUltraLightColor + if (secondaryInput.checked) return __style.positiveColor + return __style.lightGreenColor + } + + textFieldBackground.border.color: { + if (secondaryInput.validationState === "error") return __style.negativeColor + if (secondaryInput.checked) return __style.darkGreenColor + return __style.polarColor + } + + textFieldBackground.border.width: { + if (secondaryInput.validationState === "error") return __style.width2 + if (secondaryInput.checked) return 1 * __dp + return 0 + } + + // close icon when checked, type-specific icon otherwise + rightContent: MMComponents.MMIcon + { + size: __style.icon24 + source: { + if (secondaryInput.checked) return __style.closeIcon + return root.iconSource + } + color: __style.forestColor + } + + rightContentVisible: { + if (root.iconSource) return secondaryInput.checked + return true + } + + // keep checked in sync with whether the field has a value + onTextEdited: (newText) => { + secondaryInput.checked = newText.length + } + + onTextClicked: { + root.secondaryTextClicked() + } + + // clear the field when tapping the close icon + onRightContentClicked: { + if ( secondaryInput.checked ) { + textField.clear() + root.secondaryRightContentClicked( true ) + secondaryInput.checked = false + } else { + root.secondaryRightContentClicked( false ) + } + } + + Component.onCompleted: { + if (secondaryInput.text) { + secondaryInput.checked = true + } + } + } + + Item { + // light version of validation message from MMBaseInput + + width: root.width + height: validationMessagegroup.implicitHeight + + visible: root.errorMsg && root.doubleInput + + RowLayout { + id: validationMessagegroup + + width: root.width + + MMComponents.MMIcon { + source: __style.errorCircleIcon + size: __style.icon16 + color: __style.negativeColor + } + + MMComponents.MMText { + Layout.fillWidth: true + + text: root.errorMsg + color: __style.grapeColor + font: __style.t4 + + wrapMode: Text.Wrap + maximumLineCount: 10 + } + } + } +}