diff --git a/src/gui/filedetails/NCInputTextField.qml b/src/gui/filedetails/NCInputTextField.qml index 37a7d23dc8..fa4bef0bfc 100644 --- a/src/gui/filedetails/NCInputTextField.qml +++ b/src/gui/filedetails/NCInputTextField.qml @@ -25,6 +25,7 @@ TextField { readonly property color accentColor: Style.ncBlue readonly property color secondaryColor: palette.dark readonly property alias submitButton: submitButton + property bool validInput: true implicitHeight: Style.talkReplyTextFieldPreferredHeight @@ -36,7 +37,7 @@ TextField { id: textFieldBorder radius: Style.slightlyRoundedButtonRadius border.width: Style.normalBorderWidth - border.color: root.activeFocus ? root.accentColor : root.secondaryColor + border.color: root.activeFocus ? root.validInput ? root.accentColor : Style.errorBoxBackgroundColor : root.secondaryColor color: palette.base } @@ -55,7 +56,7 @@ TextField { icon.source: "image://svgimage-custom-color/confirm.svg" + "/" + root.secondaryColor icon.color: hovered && enabled ? UserModel.currentUser.accentColor : root.secondaryColor - enabled: root.text !== "" + enabled: root.text !== "" && root.validInput onClicked: root.accepted() } diff --git a/src/gui/filedetails/ShareDetailsPage.qml b/src/gui/filedetails/ShareDetailsPage.qml index e8281f03af..a8755526f5 100644 --- a/src/gui/filedetails/ShareDetailsPage.qml +++ b/src/gui/filedetails/ShareDetailsPage.qml @@ -111,7 +111,18 @@ Page { } function resetExpireDateField() { - // Expire date changing is handled by the expireDateSpinBox + // Expire date changing is handled through expireDateChanged listening in the expireDateSpinBox. + // + // When the user edits the expire date field they are changing the text, but the expire date + // value is only changed according to updates from the server. + // + // Sometimes the new expire date is the same -- say, because we were on the maximum allowed + // expire date already and we tried to push it beyond this, leading the server to just return + // the maximum allowed expire date. + // + // So to ensure that the text of the spin box is correctly updated, force an update of the + // contents of the expire date text field. + expireDateSpinBox.updateText(); waitingForExpireDateChange = false; } @@ -131,7 +142,6 @@ Page { } function resetMenu() { - moreMenu.close(); resetNoteField(); resetPasswordField(); @@ -240,7 +250,7 @@ Page { clip: true ColumnLayout { - id: moreMenu + id: scrollContentsColumn readonly property int rowIconWidth: Style.smallIconSize readonly property int indicatorItemWidth: 20 @@ -252,12 +262,12 @@ Page { RowLayout { Layout.fillWidth: true height: visible ? implicitHeight : 0 - spacing: moreMenu.indicatorSpacing + spacing: scrollContentsColumn.indicatorSpacing visible: root.isLinkShare Image { - Layout.preferredWidth: moreMenu.indicatorItemWidth + Layout.preferredWidth: scrollContentsColumn.indicatorItemWidth Layout.fillHeight: true verticalAlignment: Image.AlignVCenter @@ -265,8 +275,8 @@ Page { fillMode: Image.Pad source: "image://svgimage-custom-color/edit.svg/" + palette.dark - sourceSize.width: moreMenu.rowIconWidth - sourceSize.height: moreMenu.rowIconWidth + sourceSize.width: scrollContentsColumn.rowIconWidth + sourceSize.height: scrollContentsColumn.rowIconWidth } NCInputTextField { @@ -323,10 +333,11 @@ Page { toolTipBase: Style.backgroundColor toolTipText: Style.ncTextColor } - spacing: moreMenu.indicatorSpacing - padding: moreMenu.itemPadding - indicator.width: moreMenu.indicatorItemWidth - indicator.height: moreMenu.indicatorItemWidth + + spacing: scrollContentsColumn.indicatorSpacing + padding: scrollContentsColumn.itemPadding + indicator.width: scrollContentsColumn.indicatorItemWidth + indicator.height: scrollContentsColumn.indicatorItemWidth checkable: true checked: root.editingAllowed @@ -364,10 +375,10 @@ Page { enabled: !root.isSharePermissionChangeInProgress checked: root.currentPermissionMode === permissionMode text: qsTr("View only") - indicatorItemWidth: moreMenu.indicatorItemWidth - indicatorItemHeight: moreMenu.indicatorItemWidth - spacing: moreMenu.indicatorSpacing - padding: moreMenu.itemPadding + indicatorItemWidth: scrollContentsColumn.indicatorItemWidth + indicatorItemHeight: scrollContentsColumn.indicatorItemWidth + spacing: scrollContentsColumn.indicatorSpacing + padding: scrollContentsColumn.itemPadding onClicked: root.permissionModeChanged(permissionMode) } @@ -378,10 +389,10 @@ Page { enabled: !root.isSharePermissionChangeInProgress checked: root.currentPermissionMode === permissionMode text: qsTr("Allow upload and editing") - indicatorItemWidth: moreMenu.indicatorItemWidth - indicatorItemHeight: moreMenu.indicatorItemWidth - spacing: moreMenu.indicatorSpacing - padding: moreMenu.itemPadding + indicatorItemWidth: scrollContentsColumn.indicatorItemWidth + indicatorItemHeight: scrollContentsColumn.indicatorItemWidth + spacing: scrollContentsColumn.indicatorSpacing + padding: scrollContentsColumn.itemPadding onClicked: root.permissionModeChanged(permissionMode) NCBusyIndicator { @@ -399,10 +410,10 @@ Page { enabled: !root.isSharePermissionChangeInProgress checked: root.currentPermissionMode === permissionMode text: qsTr("File drop (upload only)") - indicatorItemWidth: moreMenu.indicatorItemWidth - indicatorItemHeight: moreMenu.indicatorItemWidth - spacing: moreMenu.indicatorSpacing - padding: moreMenu.itemPadding + indicatorItemWidth: scrollContentsColumn.indicatorItemWidth + indicatorItemHeight: scrollContentsColumn.indicatorItemWidth + spacing: scrollContentsColumn.indicatorSpacing + padding: scrollContentsColumn.itemPadding onClicked: root.permissionModeChanged(permissionMode) } } @@ -444,10 +455,11 @@ Page { toolTipText: Style.ncTextColor } - spacing: moreMenu.indicatorSpacing - padding: moreMenu.itemPadding - indicator.width: moreMenu.indicatorItemWidth - indicator.height: moreMenu.indicatorItemWidth + spacing: scrollContentsColumn.indicatorSpacing + padding: scrollContentsColumn.itemPadding + indicator.width: scrollContentsColumn.indicatorItemWidth + indicator.height: scrollContentsColumn.indicatorItemWidth + checked: root.hideDownload text: qsTr("Hide download") enabled: !root.isHideDownloadInProgress @@ -492,10 +504,10 @@ Page { toolTipText: Style.ncTextColor } - spacing: moreMenu.indicatorSpacing - padding: moreMenu.itemPadding - indicator.width: moreMenu.indicatorItemWidth - indicator.height: moreMenu.indicatorItemWidth + spacing: scrollContentsColumn.indicatorSpacing + padding: scrollContentsColumn.itemPadding + indicator.width: scrollContentsColumn.indicatorItemWidth + indicator.height: scrollContentsColumn.indicatorItemWidth checkable: true checked: root.passwordProtectEnabled @@ -519,12 +531,12 @@ Page { Layout.fillWidth: true height: visible ? implicitHeight : 0 - spacing: moreMenu.indicatorSpacing + spacing: scrollContentsColumn.indicatorSpacing visible: root.passwordProtectEnabled Image { - Layout.preferredWidth: moreMenu.indicatorItemWidth + Layout.preferredWidth: scrollContentsColumn.indicatorItemWidth Layout.fillHeight: true verticalAlignment: Image.AlignVCenter @@ -532,8 +544,8 @@ Page { fillMode: Image.Pad source: "image://svgimage-custom-color/lock-https.svg/" + palette.dark - sourceSize.width: moreMenu.rowIconWidth - sourceSize.height: moreMenu.rowIconWidth + sourceSize.width: scrollContentsColumn.rowIconWidth + sourceSize.height: scrollContentsColumn.rowIconWidth } NCInputTextField { @@ -621,10 +633,10 @@ Page { toolTipText: Style.ncTextColor } - spacing: moreMenu.indicatorSpacing - padding: moreMenu.itemPadding - indicator.width: moreMenu.indicatorItemWidth - indicator.height: moreMenu.indicatorItemWidth + spacing: scrollContentsColumn.indicatorSpacing + padding: scrollContentsColumn.itemPadding + indicator.width: scrollContentsColumn.indicatorItemWidth + indicator.height: scrollContentsColumn.indicatorItemWidth checkable: true checked: root.expireDateEnabled @@ -647,12 +659,12 @@ Page { RowLayout { Layout.fillWidth: true height: visible ? implicitHeight : 0 - spacing: moreMenu.indicatorSpacing + spacing: scrollContentsColumn.indicatorSpacing visible: root.expireDateEnabled Image { - Layout.preferredWidth: moreMenu.indicatorItemWidth + Layout.preferredWidth: scrollContentsColumn.indicatorItemWidth Layout.fillHeight: true verticalAlignment: Image.AlignVCenter @@ -660,8 +672,8 @@ Page { fillMode: Image.Pad source: "image://svgimage-custom-color/calendar.svg/" + palette.dark - sourceSize.width: moreMenu.rowIconWidth - sourceSize.height: moreMenu.rowIconWidth + sourceSize.width: scrollContentsColumn.rowIconWidth + sourceSize.height: scrollContentsColumn.rowIconWidth } // QML dates are essentially JavaScript dates, which makes them very finicky and unreliable. @@ -670,12 +682,19 @@ Page { SpinBox { id: expireDateSpinBox + function updateText() { + expireDateSpinBoxTextField.text = textFromValue(value, locale); + } + // Work arounds the limitations of QML's 32 bit integer when handling msecs from epoch // Instead, we handle everything as days since epoch readonly property int dayInMSecs: 24 * 60 * 60 * 1000 readonly property int expireDateReduced: Math.floor(root.expireDate / dayInMSecs) // Reset the model data after binding broken on user interact - onExpireDateReducedChanged: value = expireDateReduced + onExpireDateReducedChanged: { + value = expireDateReduced; + updateText(); + } // We can't use JS's convenient Infinity or Number.MAX_VALUE as // JS Number type is 64 bits, whereas QML's int type is only 32 bits @@ -749,7 +768,6 @@ Page { Layout.fillWidth: true height: visible ? implicitHeight : 0 - // We want all the internal benefits of the spinbox but don't actually want the // buttons, so set an empty item as a dummy up.indicator: Item {} @@ -758,6 +776,13 @@ Page { padding: 0 background: null contentItem: NCInputTextField { + id: expireDateSpinBoxTextField + + validInput: { + const value = expireDateSpinBox.valueFromText(text); + return value >= expireDateSpinBox.from && value <= expireDateSpinBox.to; + } + text: expireDateSpinBox.textFromValue(expireDateSpinBox.value, expireDateSpinBox.locale) readOnly: !expireDateSpinBox.editable validator: expireDateSpinBox.validator @@ -836,10 +861,10 @@ Page { toolTipText: Style.ncTextColor } - spacing: moreMenu.indicatorSpacing - padding: moreMenu.itemPadding - indicator.width: moreMenu.indicatorItemWidth - indicator.height: moreMenu.indicatorItemWidth + spacing: scrollContentsColumn.indicatorSpacing + padding: scrollContentsColumn.itemPadding + indicator.width: scrollContentsColumn.indicatorItemWidth + indicator.height: scrollContentsColumn.indicatorItemWidth checkable: true checked: root.noteEnabled @@ -862,12 +887,12 @@ Page { RowLayout { Layout.fillWidth: true height: visible ? implicitHeight : 0 - spacing: moreMenu.indicatorSpacing + spacing: scrollContentsColumn.indicatorSpacing visible: root.noteEnabled Image { - Layout.preferredWidth: moreMenu.indicatorItemWidth + Layout.preferredWidth: scrollContentsColumn.indicatorItemWidth Layout.fillHeight: true verticalAlignment: Image.AlignVCenter @@ -875,8 +900,8 @@ Page { fillMode: Image.Pad source: "image://svgimage-custom-color/edit.svg/" + palette.dark - sourceSize.width: moreMenu.rowIconWidth - sourceSize.height: moreMenu.rowIconWidth + sourceSize.width: scrollContentsColumn.rowIconWidth + sourceSize.height: scrollContentsColumn.rowIconWidth } NCInputTextEdit {