From: Claudio Cambra Date: Wed, 23 Nov 2022 14:25:09 +0000 (+0100) Subject: Add copy share link button to share details page footer, remove unneeded columnlayout... X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~12^2~11^2~79^2~1 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=6ae41c07591c47a0529097ac53a6a2f526b7298b;p=nextcloud-desktop.git Add copy share link button to share details page footer, remove unneeded columnlayout in contentitem Signed-off-by: Claudio Cambra --- diff --git a/src/gui/filedetails/ShareDetailsPage.qml b/src/gui/filedetails/ShareDetailsPage.qml index 8f66615fa..e0149da3b 100644 --- a/src/gui/filedetails/ShareDetailsPage.qml +++ b/src/gui/filedetails/ShareDetailsPage.qml @@ -250,517 +250,538 @@ Page { } } - contentItem: ColumnLayout { - ScrollView { - Layout.fillWidth: true - Layout.fillHeight: true + contentItem: ScrollView { + contentWidth: availableWidth + clip: true - contentWidth: availableWidth + ColumnLayout { + id: moreMenu - clip: true + property int rowIconWidth: 16 + property int indicatorItemWidth: 20 + property int indicatorSpacing: Style.standardSpacing + property int itemPadding: Style.smallSpacing - ColumnLayout { - id: moreMenu + width: parent.width - property int rowIconWidth: 16 - property int indicatorItemWidth: 20 - property int indicatorSpacing: Style.standardSpacing - property int itemPadding: Style.smallSpacing - - width: parent.width - - RowLayout { - Layout.fillWidth: true - height: visible ? implicitHeight : 0 - spacing: moreMenu.indicatorSpacing - - visible: root.isLinkShare - - Image { - Layout.preferredWidth: moreMenu.indicatorItemWidth - Layout.fillHeight: true - - verticalAlignment: Image.AlignVCenter - horizontalAlignment: Image.AlignHCenter - fillMode: Image.Pad - - source: "image://svgimage-custom-color/edit.svg/" + Style.menuBorder - sourceSize.width: moreMenu.rowIconWidth - sourceSize.height: moreMenu.rowIconWidth - } - - NCInputTextField { - id: linkShareLabelTextField + RowLayout { + Layout.fillWidth: true + height: visible ? implicitHeight : 0 + spacing: moreMenu.indicatorSpacing - Layout.fillWidth: true - height: visible ? implicitHeight : 0 + visible: root.isLinkShare - text: root.linkShareLabel - placeholderText: qsTr("Share label") + Image { + Layout.preferredWidth: moreMenu.indicatorItemWidth + Layout.fillHeight: true - enabled: root.isLinkShare && - !root.waitingForLinkShareLabelChange + verticalAlignment: Image.AlignVCenter + horizontalAlignment: Image.AlignHCenter + fillMode: Image.Pad - onAccepted: if(text !== root.linkShareLabel) { - root.setLinkShareLabel(text); - root.waitingForLinkShareLabelChange = true; - } - - NCBusyIndicator { - anchors.fill: parent - visible: root.waitingForLinkShareLabelChange - running: visible - z: 1 - } - } + source: "image://svgimage-custom-color/edit.svg/" + Style.menuBorder + sourceSize.width: moreMenu.rowIconWidth + sourceSize.height: moreMenu.rowIconWidth } - // On these checkables, the clicked() signal is called after - // the check state changes. - CheckBox { - id: editingAllowedMenuItem + NCInputTextField { + id: linkShareLabelTextField Layout.fillWidth: true + height: visible ? implicitHeight : 0 - spacing: moreMenu.indicatorSpacing - padding: moreMenu.itemPadding - indicator.width: moreMenu.indicatorItemWidth - indicator.height: moreMenu.indicatorItemWidth + text: root.linkShareLabel + placeholderText: qsTr("Share label") - checkable: true - checked: root.editingAllowed - text: qsTr("Allow editing") - enabled: !root.waitingForEditingAllowedChange + enabled: root.isLinkShare && + !root.waitingForLinkShareLabelChange - onClicked: { - root.toggleAllowEditing(checked); - root.waitingForEditingAllowedChange = true; + onAccepted: if(text !== root.linkShareLabel) { + root.setLinkShareLabel(text); + root.waitingForLinkShareLabelChange = true; } NCBusyIndicator { anchors.fill: parent - visible: root.waitingForEditingAllowedChange + visible: root.waitingForLinkShareLabelChange running: visible z: 1 } } + } - CheckBox { - id: passwordProtectEnabledMenuItem + // On these checkables, the clicked() signal is called after + // the check state changes. + CheckBox { + id: editingAllowedMenuItem - Layout.fillWidth: true + Layout.fillWidth: true - spacing: moreMenu.indicatorSpacing - padding: moreMenu.itemPadding - indicator.width: moreMenu.indicatorItemWidth - indicator.height: moreMenu.indicatorItemWidth + spacing: moreMenu.indicatorSpacing + padding: moreMenu.itemPadding + indicator.width: moreMenu.indicatorItemWidth + indicator.height: moreMenu.indicatorItemWidth - checkable: true - checked: root.passwordProtectEnabled - text: qsTr("Password protect") - enabled: !root.waitingForPasswordProtectEnabledChange && !root.passwordEnforced + checkable: true + checked: root.editingAllowed + text: qsTr("Allow editing") + enabled: !root.waitingForEditingAllowedChange - onClicked: { - root.togglePasswordProtect(checked); - root.waitingForPasswordProtectEnabledChange = true; - } + onClicked: { + root.toggleAllowEditing(checked); + root.waitingForEditingAllowedChange = true; + } - NCBusyIndicator { - anchors.fill: parent - visible: root.waitingForPasswordProtectEnabledChange - running: visible - z: 1 - } + NCBusyIndicator { + anchors.fill: parent + visible: root.waitingForEditingAllowedChange + running: visible + z: 1 } + } - RowLayout { - Layout.fillWidth: true + CheckBox { + id: passwordProtectEnabledMenuItem - height: visible ? implicitHeight : 0 - spacing: moreMenu.indicatorSpacing + Layout.fillWidth: true - visible: root.passwordProtectEnabled + spacing: moreMenu.indicatorSpacing + padding: moreMenu.itemPadding + indicator.width: moreMenu.indicatorItemWidth + indicator.height: moreMenu.indicatorItemWidth - Image { - Layout.preferredWidth: moreMenu.indicatorItemWidth - Layout.fillHeight: true + checkable: true + checked: root.passwordProtectEnabled + text: qsTr("Password protect") + enabled: !root.waitingForPasswordProtectEnabledChange && !root.passwordEnforced - verticalAlignment: Image.AlignVCenter - horizontalAlignment: Image.AlignHCenter - fillMode: Image.Pad + onClicked: { + root.togglePasswordProtect(checked); + root.waitingForPasswordProtectEnabledChange = true; + } - source: "image://svgimage-custom-color/lock-https.svg/" + Style.menuBorder - sourceSize.width: moreMenu.rowIconWidth - sourceSize.height: moreMenu.rowIconWidth - } + NCBusyIndicator { + anchors.fill: parent + visible: root.waitingForPasswordProtectEnabledChange + running: visible + z: 1 + } + } - NCInputTextField { - id: passwordTextField + RowLayout { + Layout.fillWidth: true - Layout.fillWidth: true - height: visible ? implicitHeight : 0 + height: visible ? implicitHeight : 0 + spacing: moreMenu.indicatorSpacing - text: root.password !== "" ? root.password : root.passwordPlaceholder - enabled: root.passwordProtectEnabled && - !root.waitingForPasswordChange && - !root.waitingForPasswordProtectEnabledChange + visible: root.passwordProtectEnabled - onAccepted: if(text !== root.password && text !== root.passwordPlaceholder) { - passwordErrorBoxLoader.message = ""; - root.setPassword(text); - root.waitingForPasswordChange = true; - } + Image { + Layout.preferredWidth: moreMenu.indicatorItemWidth + Layout.fillHeight: true - NCBusyIndicator { - anchors.fill: parent - visible: root.waitingForPasswordChange || - root.waitingForPasswordProtectEnabledChange - running: visible - z: 1 - } + verticalAlignment: Image.AlignVCenter + horizontalAlignment: Image.AlignHCenter + fillMode: Image.Pad + + source: "image://svgimage-custom-color/lock-https.svg/" + Style.menuBorder + sourceSize.width: moreMenu.rowIconWidth + sourceSize.height: moreMenu.rowIconWidth + } + + NCInputTextField { + id: passwordTextField + + Layout.fillWidth: true + height: visible ? implicitHeight : 0 + + text: root.password !== "" ? root.password : root.passwordPlaceholder + enabled: root.passwordProtectEnabled && + !root.waitingForPasswordChange && + !root.waitingForPasswordProtectEnabledChange + + onAccepted: if(text !== root.password && text !== root.passwordPlaceholder) { + passwordErrorBoxLoader.message = ""; + root.setPassword(text); + root.waitingForPasswordChange = true; + } + + NCBusyIndicator { + anchors.fill: parent + visible: root.waitingForPasswordChange || + root.waitingForPasswordProtectEnabledChange + running: visible + z: 1 } } + } - Loader { - id: passwordErrorBoxLoader + Loader { + id: passwordErrorBoxLoader - property string message: "" + property string message: "" - Layout.fillWidth: true - height: message !== "" ? implicitHeight : 0 + Layout.fillWidth: true + height: message !== "" ? implicitHeight : 0 + + active: message !== "" + visible: active - active: message !== "" - visible: active + sourceComponent: Item { + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + // Artificially add vertical padding + implicitHeight: passwordErrorBox.implicitHeight + (Style.smallSpacing * 2) - sourceComponent: Item { - anchors.top: parent.top + ErrorBox { + id: passwordErrorBox anchors.left: parent.left anchors.right: parent.right - // Artificially add vertical padding - implicitHeight: passwordErrorBox.implicitHeight + (Style.smallSpacing * 2) + anchors.verticalCenter: parent.verticalCenter - ErrorBox { - id: passwordErrorBox - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - - text: passwordErrorBoxLoader.message - } + text: passwordErrorBoxLoader.message } } + } - CheckBox { - id: expireDateEnabledMenuItem + CheckBox { + id: expireDateEnabledMenuItem - Layout.fillWidth: true + Layout.fillWidth: true - spacing: moreMenu.indicatorSpacing - padding: moreMenu.itemPadding - indicator.width: moreMenu.indicatorItemWidth - indicator.height: moreMenu.indicatorItemWidth + spacing: moreMenu.indicatorSpacing + padding: moreMenu.itemPadding + indicator.width: moreMenu.indicatorItemWidth + indicator.height: moreMenu.indicatorItemWidth - checkable: true - checked: root.expireDateEnabled - text: qsTr("Set expiration date") - enabled: !root.waitingForExpireDateEnabledChange && !root.expireDateEnforced + checkable: true + checked: root.expireDateEnabled + text: qsTr("Set expiration date") + enabled: !root.waitingForExpireDateEnabledChange && !root.expireDateEnforced - onClicked: { - root.toggleExpirationDate(checked); - root.waitingForExpireDateEnabledChange = true; - } + onClicked: { + root.toggleExpirationDate(checked); + root.waitingForExpireDateEnabledChange = true; + } - NCBusyIndicator { - anchors.fill: parent - visible: root.waitingForExpireDateEnabledChange - running: visible - z: 1 - } + NCBusyIndicator { + anchors.fill: parent + visible: root.waitingForExpireDateEnabledChange + running: visible + z: 1 } + } - RowLayout { - Layout.fillWidth: true - height: visible ? implicitHeight : 0 - spacing: moreMenu.indicatorSpacing + RowLayout { + Layout.fillWidth: true + height: visible ? implicitHeight : 0 + spacing: moreMenu.indicatorSpacing - visible: root.expireDateEnabled + visible: root.expireDateEnabled - Image { - Layout.preferredWidth: moreMenu.indicatorItemWidth - Layout.fillHeight: true + Image { + Layout.preferredWidth: moreMenu.indicatorItemWidth + Layout.fillHeight: true - verticalAlignment: Image.AlignVCenter - horizontalAlignment: Image.AlignHCenter - fillMode: Image.Pad + verticalAlignment: Image.AlignVCenter + horizontalAlignment: Image.AlignHCenter + fillMode: Image.Pad - source: "image://svgimage-custom-color/calendar.svg/" + Style.menuBorder - sourceSize.width: moreMenu.rowIconWidth - sourceSize.height: moreMenu.rowIconWidth + source: "image://svgimage-custom-color/calendar.svg/" + Style.menuBorder + sourceSize.width: moreMenu.rowIconWidth + sourceSize.height: moreMenu.rowIconWidth + } + + // QML dates are essentially JavaScript dates, which makes them very finicky and unreliable. + // Instead, we exclusively deal with msecs from epoch time to make things less painful when editing. + // We only use the QML Date when showing the nice string to the user. + SpinBox { + id: expireDateSpinBox + + // 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 + + // 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 + readonly property IntValidator intValidator: IntValidator {} + readonly property int maximumExpireDateReduced: root.expireDateEnforced ? + Math.floor(root.maximumExpireDate / dayInMSecs) : + intValidator.top + readonly property int minimumExpireDateReduced: { + const currentDate = new Date(); + const minDateUTC = new Date(Date.UTC(currentDate.getFullYear(), + currentDate.getMonth(), + currentDate.getDate() + 1)); + return Math.floor(minDateUTC / dayInMSecs) // Start of day at 00:00:0000 UTC } - // QML dates are essentially JavaScript dates, which makes them very finicky and unreliable. - // Instead, we exclusively deal with msecs from epoch time to make things less painful when editing. - // We only use the QML Date when showing the nice string to the user. - SpinBox { - id: expireDateSpinBox - - // 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 - - // 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 - readonly property IntValidator intValidator: IntValidator {} - readonly property int maximumExpireDateReduced: root.expireDateEnforced ? - Math.floor(root.maximumExpireDate / dayInMSecs) : - intValidator.top - readonly property int minimumExpireDateReduced: { - const currentDate = new Date(); - const minDateUTC = new Date(Date.UTC(currentDate.getFullYear(), - currentDate.getMonth(), - currentDate.getDate() + 1)); - return Math.floor(minDateUTC / dayInMSecs) // Start of day at 00:00:0000 UTC + // Taken from Kalendar 22.08 + // https://invent.kde.org/pim/kalendar/-/blob/release/22.08/src/contents/ui/KalendarUtils/dateutils.js + function parseDateString(dateString) { + function defaultParse() { + const defaultParsedDate = Date.fromLocaleDateString(Qt.locale(), dateString, Locale.NarrowFormat); + // JS always generates date in system locale, eliminate timezone difference to UTC + const msecsSinceEpoch = defaultParsedDate.getTime() - (defaultParsedDate.getTimezoneOffset() * 60 * 1000); + return new Date(msecsSinceEpoch); } - // Taken from Kalendar 22.08 - // https://invent.kde.org/pim/kalendar/-/blob/release/22.08/src/contents/ui/KalendarUtils/dateutils.js - function parseDateString(dateString) { - function defaultParse() { - const defaultParsedDate = Date.fromLocaleDateString(Qt.locale(), dateString, Locale.NarrowFormat); - // JS always generates date in system locale, eliminate timezone difference to UTC - const msecsSinceEpoch = defaultParsedDate.getTime() - (defaultParsedDate.getTimezoneOffset() * 60 * 1000); - return new Date(msecsSinceEpoch); - } - - const dateStringDelimiterMatches = dateString.match(/\D/); - if(dateStringDelimiterMatches.length === 0) { - // Let the date method figure out this weirdness - return defaultParse(); - } - - const dateStringDelimiter = dateStringDelimiterMatches[0]; - - const localisedDateFormatSplit = Qt.locale().dateFormat(Locale.NarrowFormat).split(dateStringDelimiter); - const localisedDateDayPosition = localisedDateFormatSplit.findIndex((x) => /d/gi.test(x)); - const localisedDateMonthPosition = localisedDateFormatSplit.findIndex((x) => /m/gi.test(x)); - const localisedDateYearPosition = localisedDateFormatSplit.findIndex((x) => /y/gi.test(x)); - - let splitDateString = dateString.split(dateStringDelimiter); - let userProvidedYear = splitDateString[localisedDateYearPosition] - - const dateNow = new Date(); - const stringifiedCurrentYear = dateNow.getFullYear().toString(); - - // If we have any input weirdness, or if we have a fully-written year - // (e.g. 2022 instead of 22) then use default parse - if(splitDateString.length === 0 || - splitDateString.length > 3 || - userProvidedYear.length >= stringifiedCurrentYear.length) { - - return defaultParse(); - } - - let fullyWrittenYear = userProvidedYear.split(""); - const digitsToAdd = stringifiedCurrentYear.length - fullyWrittenYear.length; - for(let i = 0; i < digitsToAdd; i++) { - fullyWrittenYear.splice(i, 0, stringifiedCurrentYear[i]) - } - fullyWrittenYear = fullyWrittenYear.join(""); - - const fixedYearNum = Number(fullyWrittenYear); - const monthIndexNum = Number(splitDateString[localisedDateMonthPosition]) - 1; - const dayNum = Number(splitDateString[localisedDateDayPosition]); - - console.log(dayNum, monthIndexNum, fixedYearNum); - - // Modification: return date in UTC - return new Date(Date.UTC(fixedYearNum, monthIndexNum, dayNum)); + const dateStringDelimiterMatches = dateString.match(/\D/); + if(dateStringDelimiterMatches.length === 0) { + // Let the date method figure out this weirdness + return defaultParse(); } - 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 {} - down.indicator: Item {} - - padding: 0 - background: null - contentItem: NCInputTextField { - text: expireDateSpinBox.textFromValue(expireDateSpinBox.value, expireDateSpinBox.locale) - readOnly: !expireDateSpinBox.editable - validator: expireDateSpinBox.validator - inputMethodHints: Qt.ImhFormattedNumbersOnly - onAccepted: { - expireDateSpinBox.value = expireDateSpinBox.valueFromText(text, expireDateSpinBox.locale); - expireDateSpinBox.valueModified(); - } - } + const dateStringDelimiter = dateStringDelimiterMatches[0]; + + const localisedDateFormatSplit = Qt.locale().dateFormat(Locale.NarrowFormat).split(dateStringDelimiter); + const localisedDateDayPosition = localisedDateFormatSplit.findIndex((x) => /d/gi.test(x)); + const localisedDateMonthPosition = localisedDateFormatSplit.findIndex((x) => /m/gi.test(x)); + const localisedDateYearPosition = localisedDateFormatSplit.findIndex((x) => /y/gi.test(x)); - value: expireDateReduced - from: minimumExpireDateReduced - to: maximumExpireDateReduced + let splitDateString = dateString.split(dateStringDelimiter); + let userProvidedYear = splitDateString[localisedDateYearPosition] - textFromValue: (value, locale) => { - const dateFromValue = new Date(value * dayInMSecs); - return dateFromValue.toLocaleDateString(Qt.locale(), Locale.NarrowFormat); + const dateNow = new Date(); + const stringifiedCurrentYear = dateNow.getFullYear().toString(); + + // If we have any input weirdness, or if we have a fully-written year + // (e.g. 2022 instead of 22) then use default parse + if(splitDateString.length === 0 || + splitDateString.length > 3 || + userProvidedYear.length >= stringifiedCurrentYear.length) { + + return defaultParse(); } - valueFromText: (text, locale) => { - const dateFromText = parseDateString(text); - return Math.floor(dateFromText.getTime() / dayInMSecs); + + let fullyWrittenYear = userProvidedYear.split(""); + const digitsToAdd = stringifiedCurrentYear.length - fullyWrittenYear.length; + for(let i = 0; i < digitsToAdd; i++) { + fullyWrittenYear.splice(i, 0, stringifiedCurrentYear[i]) } + fullyWrittenYear = fullyWrittenYear.join(""); + + const fixedYearNum = Number(fullyWrittenYear); + const monthIndexNum = Number(splitDateString[localisedDateMonthPosition]) - 1; + const dayNum = Number(splitDateString[localisedDateDayPosition]); - editable: true - inputMethodHints: Qt.ImhDate | Qt.ImhFormattedNumbersOnly + console.log(dayNum, monthIndexNum, fixedYearNum); - enabled: root.expireDateEnabled && - !root.waitingForExpireDateChange && - !root.waitingForExpireDateEnabledChange + // Modification: return date in UTC + return new Date(Date.UTC(fixedYearNum, monthIndexNum, dayNum)); + } - onValueModified: { - if (!enabled || !activeFocus) { - return; - } + Layout.fillWidth: true + height: visible ? implicitHeight : 0 - root.setExpireDate(value * dayInMSecs); - root.waitingForExpireDateChange = true; - } - NCBusyIndicator { - anchors.fill: parent - visible: root.waitingForExpireDateEnabledChange || - root.waitingForExpireDateChange - running: visible - z: 1 + // 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 {} + down.indicator: Item {} + + padding: 0 + background: null + contentItem: NCInputTextField { + text: expireDateSpinBox.textFromValue(expireDateSpinBox.value, expireDateSpinBox.locale) + readOnly: !expireDateSpinBox.editable + validator: expireDateSpinBox.validator + inputMethodHints: Qt.ImhFormattedNumbersOnly + onAccepted: { + expireDateSpinBox.value = expireDateSpinBox.valueFromText(text, expireDateSpinBox.locale); + expireDateSpinBox.valueModified(); } } - } - CheckBox { - id: noteEnabledMenuItem + value: expireDateReduced + from: minimumExpireDateReduced + to: maximumExpireDateReduced - Layout.fillWidth: true + textFromValue: (value, locale) => { + const dateFromValue = new Date(value * dayInMSecs); + return dateFromValue.toLocaleDateString(Qt.locale(), Locale.NarrowFormat); + } + valueFromText: (text, locale) => { + const dateFromText = parseDateString(text); + return Math.floor(dateFromText.getTime() / dayInMSecs); + } - spacing: moreMenu.indicatorSpacing - padding: moreMenu.itemPadding - indicator.width: moreMenu.indicatorItemWidth - indicator.height: moreMenu.indicatorItemWidth + editable: true + inputMethodHints: Qt.ImhDate | Qt.ImhFormattedNumbersOnly - checkable: true - checked: root.noteEnabled - text: qsTr("Note to recipient") - enabled: !root.waitingForNoteEnabledChange + enabled: root.expireDateEnabled && + !root.waitingForExpireDateChange && + !root.waitingForExpireDateEnabledChange - onClicked: { - root.toggleNoteToRecipient(checked); - root.waitingForNoteEnabledChange = true; + onValueModified: { + if (!enabled || !activeFocus) { + return; + } + + root.setExpireDate(value * dayInMSecs); + root.waitingForExpireDateChange = true; } NCBusyIndicator { anchors.fill: parent - visible: root.waitingForNoteEnabledChange + visible: root.waitingForExpireDateEnabledChange || + root.waitingForExpireDateChange running: visible z: 1 } } + } - RowLayout { - Layout.fillWidth: true - height: visible ? implicitHeight : 0 - spacing: moreMenu.indicatorSpacing + CheckBox { + id: noteEnabledMenuItem - visible: root.noteEnabled + Layout.fillWidth: true - Image { - Layout.preferredWidth: moreMenu.indicatorItemWidth - Layout.fillHeight: true + spacing: moreMenu.indicatorSpacing + padding: moreMenu.itemPadding + indicator.width: moreMenu.indicatorItemWidth + indicator.height: moreMenu.indicatorItemWidth - verticalAlignment: Image.AlignVCenter - horizontalAlignment: Image.AlignHCenter - fillMode: Image.Pad + checkable: true + checked: root.noteEnabled + text: qsTr("Note to recipient") + enabled: !root.waitingForNoteEnabledChange - source: "image://svgimage-custom-color/edit.svg/" + Style.menuBorder - sourceSize.width: moreMenu.rowIconWidth - sourceSize.height: moreMenu.rowIconWidth - } + onClicked: { + root.toggleNoteToRecipient(checked); + root.waitingForNoteEnabledChange = true; + } - NCInputTextEdit { - id: noteTextEdit + NCBusyIndicator { + anchors.fill: parent + visible: root.waitingForNoteEnabledChange + running: visible + z: 1 + } + } - Layout.fillWidth: true - height: visible ? Math.max(Style.talkReplyTextFieldPreferredHeight, contentHeight) : 0 - submitButton.height: Math.min(Style.talkReplyTextFieldPreferredHeight, height - 2) + RowLayout { + Layout.fillWidth: true + height: visible ? implicitHeight : 0 + spacing: moreMenu.indicatorSpacing - text: root.note - enabled: root.noteEnabled && - !root.waitingForNoteChange && - !root.waitingForNoteEnabledChange + visible: root.noteEnabled - onEditingFinished: if(text !== root.note) { - root.setNote(text); - root.waitingForNoteChange = true; - } + Image { + Layout.preferredWidth: moreMenu.indicatorItemWidth + Layout.fillHeight: true - NCBusyIndicator { - anchors.fill: parent - visible: root.waitingForNoteChange || - root.waitingForNoteEnabledChange - running: visible - z: 1 - } - } - } + verticalAlignment: Image.AlignVCenter + horizontalAlignment: Image.AlignHCenter + fillMode: Image.Pad - CustomButton { - height: Style.standardPrimaryButtonHeight - - imageSource: "image://svgimage-custom-color/close.svg/" + Style.errorBoxBackgroundColor - imageSourceHover: "image://svgimage-custom-color/close.svg/" + Style.ncHeaderTextColor - text: qsTr("Unshare") - textColor: Style.errorBoxBackgroundColor - textColorHovered: "white" - contentsFont.bold: true - bgNormalColor: Style.buttonBackgroundColor - bgHoverColor: Style.errorBoxBackgroundColor - bgNormalOpacity: 1.0 - bgHoverOpacity: 1.0 - - onClicked: root.deleteShare() + source: "image://svgimage-custom-color/edit.svg/" + Style.menuBorder + sourceSize.width: moreMenu.rowIconWidth + sourceSize.height: moreMenu.rowIconWidth } - CustomButton { - height: Style.standardPrimaryButtonHeight + NCInputTextEdit { + id: noteTextEdit - imageSource: "image://svgimage-custom-color/add.svg/" + Style.ncBlue - imageSourceHover: "image://svgimage-custom-color/add.svg/" + Style.ncHeaderTextColor - text: qsTr("Add another link") - textColor: Style.ncBlue - textColorHovered: Style.ncHeaderTextColor - contentsFont.bold: true - bgNormalColor: Style.buttonBackgroundColor - bgHoverColor: Style.ncBlue - bgNormalOpacity: 1.0 - bgHoverOpacity: 1.0 + Layout.fillWidth: true + height: visible ? Math.max(Style.talkReplyTextFieldPreferredHeight, contentHeight) : 0 + submitButton.height: Math.min(Style.talkReplyTextFieldPreferredHeight, height - 2) + + text: root.note + enabled: root.noteEnabled && + !root.waitingForNoteChange && + !root.waitingForNoteEnabledChange - visible: root.isLinkShare && root.canCreateLinkShares - enabled: visible + onEditingFinished: if(text !== root.note) { + root.setNote(text); + root.waitingForNoteChange = true; + } - onClicked: root.createNewLinkShare() + NCBusyIndicator { + anchors.fill: parent + visible: root.waitingForNoteChange || + root.waitingForNoteEnabledChange + running: visible + z: 1 + } } } - } - - RowLayout { - Layout.fillWidth: true + CustomButton { + height: Style.standardPrimaryButtonHeight + + imageSource: "image://svgimage-custom-color/close.svg/" + Style.errorBoxBackgroundColor + imageSourceHover: "image://svgimage-custom-color/close.svg/" + Style.ncHeaderTextColor + text: qsTr("Unshare") + textColor: Style.errorBoxBackgroundColor + textColorHovered: "white" + contentsFont.bold: true + bgNormalColor: Style.buttonBackgroundColor + bgHoverColor: Style.errorBoxBackgroundColor + bgNormalOpacity: 1.0 + bgHoverOpacity: 1.0 + + onClicked: root.deleteShare() + } + CustomButton { + height: Style.standardPrimaryButtonHeight + + imageSource: "image://svgimage-custom-color/add.svg/" + Style.ncBlue + imageSourceHover: "image://svgimage-custom-color/add.svg/" + Style.ncHeaderTextColor + text: qsTr("Add another link") + textColor: Style.ncBlue + textColorHovered: Style.ncHeaderTextColor + contentsFont.bold: true + bgNormalColor: Style.buttonBackgroundColor + bgHoverColor: Style.ncBlue + bgNormalOpacity: 1.0 + bgHoverOpacity: 1.0 + + visible: root.isLinkShare && root.canCreateLinkShares + enabled: visible + + onClicked: root.createNewLinkShare() + } + } + } + footer: DialogButtonBox { + topPadding: 0 + bottomPadding: root.padding + rightPadding: root.padding + leftPadding: root.padding + alignment: Qt.AlignRight | Qt.AlignVCenter + visible: copyShareLinkButton.visible + + CustomButton { + id: copyShareLinkButton + + height: Style.standardPrimaryButtonHeight + + imageSource: "image://svgimage-custom-color/copy.svg/" + Style.ncHeaderTextColor + text: qsTr("Copy share link") + textColor: Style.ncHeaderTextColor + contentsFont.bold: true + bgColor: Style.ncBlue + bgNormalOpacity: 1.0 + bgHoverOpacity: Style.hoverOpacity + + visible: root.isLinkShare + enabled: visible + + onClicked: { + clipboardHelper.text = root.link; + clipboardHelper.selectAll(); + clipboardHelper.copy(); + clipboardHelper.clear(); + } + TextEdit { id: clipboardHelper; visible: false } } } }