Changeset View
Changeset View
Standalone View
Standalone View
src/contents/ui/SendMessageBox.qml
| Show All 14 Lines | |||||
| import '.' as Kazv | import '.' as Kazv | ||||
| ColumnLayout { | ColumnLayout { | ||||
| id: sendMessageBox | id: sendMessageBox | ||||
| property var room | property var room | ||||
| property var draftRelType: '' | property var draftRelType: '' | ||||
| property var draftRelatedTo: '' | property var draftRelatedTo: '' | ||||
| property var timeline: room.timeline() | property var timeline: room.timeline() | ||||
| property var members: room.members() | |||||
| function getRelationPrompt(draftRelType) { | function getRelationPrompt(draftRelType) { | ||||
| if (draftRelType === 'm.in_reply_to') { | if (draftRelType === 'm.in_reply_to') { | ||||
| return l10n.get('send-message-box-reply-to'); | return l10n.get('send-message-box-reply-to'); | ||||
| } else if (draftRelType === 'm.replace') { | } else if (draftRelType === 'm.replace') { | ||||
| return l10n.get('send-message-box-edit'); | return l10n.get('send-message-box-edit'); | ||||
| } | } | ||||
| } | } | ||||
| Show All 9 Lines | ColumnLayout { | ||||
| function replaceDraft(newDraft) { | function replaceDraft(newDraft) { | ||||
| textArea.changeText(newDraft, /* inhibitTyping = */ true); | textArea.changeText(newDraft, /* inhibitTyping = */ true); | ||||
| } | } | ||||
| onRoomChanged: { | onRoomChanged: { | ||||
| textArea.changeText(room.localDraft, true); | textArea.changeText(room.localDraft, true); | ||||
| } | } | ||||
| Popup { | |||||
| id: completionPopup | |||||
| objectName: 'completionPopup' | |||||
| x: 1 | |||||
| y: -height | |||||
| width: parent.width - 1 | |||||
| contentItem: Kazv.Completion { | |||||
| id: completion | |||||
| members: sendMessageBox.members | |||||
| onMentionUserRequested: (userId) => { | |||||
| textArea.removePartialMention(); | |||||
| sendMessageBox.mentionUser(userId); | |||||
| } | |||||
| } | |||||
| } | |||||
| ColumnLayout { | ColumnLayout { | ||||
| visible: !!sendMessageBox.draftRelatedTo | visible: !!sendMessageBox.draftRelatedTo | ||||
| RowLayout { | RowLayout { | ||||
| Label { | Label { | ||||
| Layout.fillWidth: true | Layout.fillWidth: true | ||||
| text: getRelationPrompt(sendMessageBox.draftRelType) | text: getRelationPrompt(sendMessageBox.draftRelType) | ||||
| } | } | ||||
| Show All 25 Lines | ColumnLayout { | ||||
| RowLayout { | RowLayout { | ||||
| TextArea { | TextArea { | ||||
| id: textArea | id: textArea | ||||
| objectName: 'draftMessage' | objectName: 'draftMessage' | ||||
| property var shortcutList: ["Ctrl+Return", "Ctrl+Enter"] | property var shortcutList: ["Ctrl+Return", "Ctrl+Enter"] | ||||
| property var inhibitTyping: false | property var inhibitTyping: false | ||||
| placeholderText: l10n.get('send-message-box-input-placeholder') | placeholderText: l10n.get('send-message-box-input-placeholder') | ||||
| property string filter: getFilter() | |||||
| Layout.fillWidth: true | Layout.fillWidth: true | ||||
| wrapMode: TextEdit.Wrap | wrapMode: TextEdit.Wrap | ||||
| onTextChanged: { | onTextChanged: { | ||||
| room.setLocalDraft(text); | room.setLocalDraft(text); | ||||
| if (!inhibitTyping) { | if (!inhibitTyping) { | ||||
| room.setTyping(true); | room.setTyping(true); | ||||
| } | } | ||||
| inhibitTyping = false; | inhibitTyping = false; | ||||
| } | } | ||||
| function changeText(newText, inhibitTyping) { | function changeText(newText, inhibitTyping) { | ||||
| textArea.inhibitTyping = inhibitTyping; | textArea.inhibitTyping = inhibitTyping; | ||||
| textArea.text = newText; | textArea.text = newText; | ||||
| } | } | ||||
| onVisibleChanged: { | onVisibleChanged: { | ||||
| if (!visible) { | if (!visible) { | ||||
| room.updateLocalDraftNow(); | room.updateLocalDraftNow(); | ||||
| } | } | ||||
| } | } | ||||
| function getFilter() { | |||||
| const atPos = text.lastIndexOf('@', cursorPosition); | |||||
| if (atPos < 0) { | |||||
| return ''; | |||||
| } | |||||
| const textInBetween = text.slice(atPos, cursorPosition); | |||||
| const hasSpaces = /\s/.test(textInBetween); | |||||
| return hasSpaces ? '' : textInBetween; | |||||
| } | |||||
| function removePartialMention() { | |||||
| const atPos = text.lastIndexOf('@', cursorPosition); | |||||
| text = text.slice(0, atPos) + text.slice(cursorPosition); | |||||
| cursorPosition = atPos; | |||||
| } | |||||
| onFilterChanged: { | |||||
| sendMessageBox.members.filter = filter.slice(1); | |||||
| if (filter && sendMessageBox.members.count > 0) { | |||||
| completionPopup.open(); | |||||
| } else { | |||||
| completionPopup.close(); | |||||
| } | |||||
| } | |||||
| // Shortcut keys for sending messages (TODO: Shortcut keys customized by the user) | // Shortcut keys for sending messages (TODO: Shortcut keys customized by the user) | ||||
| Shortcut { | Shortcut { | ||||
| sequences: textArea.shortcutList | sequences: textArea.shortcutList | ||||
| onActivated: { | onActivated: { | ||||
| sendAction.trigger() | sendAction.trigger() | ||||
| } | } | ||||
| } | } | ||||
| Show All 27 Lines | function mentionUser(userId) { | ||||
| const prefix = textArea.text.slice(0, textArea.cursorPosition); | const prefix = textArea.text.slice(0, textArea.cursorPosition); | ||||
| const suffix = textArea.text.slice(textArea.cursorPosition); | const suffix = textArea.text.slice(textArea.cursorPosition); | ||||
| let insertion = userId; | let insertion = userId; | ||||
| // If we are not at the beginning and the prev char is not a space, | // If we are not at the beginning and the prev char is not a space, | ||||
| // insert a space there. | // insert a space there. | ||||
| if (prefix && prefix.slice(prefix.length - 1).trim() !== '') { | if (prefix && prefix.slice(prefix.length - 1).trim() !== '') { | ||||
| insertion = ' ' + insertion; | insertion = ' ' + insertion; | ||||
| } | } | ||||
| let postPadding = 0; | |||||
| // If we are at the end or the next char is not a space, | // If we are at the end or the next char is not a space, | ||||
| // insert a space there. | // insert a space there. | ||||
| if (!suffix || suffix.slice(0, 1).trim() !== '') { | if (!suffix || suffix.slice(0, 1).trim() !== '') { | ||||
| insertion = insertion + ' '; | insertion = insertion + ' '; | ||||
| } else if (suffix) { | |||||
| // If there is a suffix, and space is not inserted | |||||
| // this means the next character is a space, | |||||
| // move the cursor to that space. | |||||
| postPadding = 1; | |||||
| } | } | ||||
| textArea.text = prefix + insertion + suffix; | textArea.text = prefix + insertion + suffix; | ||||
| textArea.cursorPosition = prefix.length + insertion.length; | textArea.cursorPosition = prefix.length + insertion.length + postPadding; | ||||
| } | } | ||||
| function focusInput() { | function focusInput() { | ||||
| textArea.forceActiveFocus(); | textArea.forceActiveFocus(); | ||||
| } | } | ||||
| Kirigami.Action { | Kirigami.Action { | ||||
| id: removeRelatedToAction | id: removeRelatedToAction | ||||
| ▲ Show 20 Lines • Show All 75 Lines • Show Last 20 Lines | |||||