2121-->
2222
2323<template >
24- <div class =" wrapper" >
24+ <div class =" wrapper" :class =" {'wrapper--has-typing-indicator': showTypingStatus}" >
25+ <NewMessageFormTypingIndicator v-if =" showTypingStatus"
26+ :token =" token" />
27+
2528 <!-- native file picker, hidden -->
2629 <input id =" file-upload"
2730 ref =" fileUploadInput"
@@ -245,11 +248,12 @@ import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
245248
246249import Quote from ' ../Quote.vue'
247250import AudioRecorder from ' ./AudioRecorder/AudioRecorder.vue'
251+ import NewMessageFormTypingIndicator from ' ./NewMessageFormTypingIndicator.vue'
248252import SimplePollsEditor from ' ./SimplePollsEditor/SimplePollsEditor.vue'
249253import TemplatePreview from ' ./TemplatePreview.vue'
250254
251255import { useViewer } from ' ../../composables/useViewer.js'
252- import { CONVERSATION , PARTICIPANT } from ' ../../constants.js'
256+ import { CONVERSATION , PARTICIPANT , PRIVACY } from ' ../../constants.js'
253257import { EventBus } from ' ../../services/EventBus.js'
254258import { shareFile , createTextFile } from ' ../../services/filesSharingServices.js'
255259import { searchPossibleMentions } from ' ../../services/mentionsService.js'
@@ -267,31 +271,34 @@ const margin = 8
267271const width = margin * 20
268272
269273const disableKeyboardShortcuts = OCP .Accessibility .disableKeyboardShortcuts ()
274+ const supportTypingStatus = getCapabilities ()? .spreed ? .config ? .chat ? .[' typing-privacy' ] !== undefined
270275
271276export default {
272277 name: ' NewMessageForm' ,
273278
274279 disableKeyboardShortcuts,
275280
276281 components: {
277- Quote,
278- NcActions,
282+ AudioRecorder,
279283 NcActionButton,
284+ NcActions,
280285 NcButton,
281- Paperclip,
282286 NcEmojiPicker,
287+ NcModal,
283288 NcRichContenteditable,
284- EmoticonOutline,
285- Send,
286- AudioRecorder,
287- BellOff,
289+ NcTextField,
290+ NewMessageFormTypingIndicator,
291+ Quote,
288292 SimplePollsEditor,
289- Poll,
290- NcModal,
293+ TemplatePreview,
294+ // Icons
295+ BellOff,
296+ EmoticonOutline,
291297 Folder,
298+ Paperclip,
299+ Poll,
300+ Send,
292301 Upload,
293- TemplatePreview,
294- NcTextField,
295302 },
296303
297304 props: {
@@ -328,6 +335,14 @@ export default {
328335 type: Boolean ,
329336 default: false ,
330337 },
338+
339+ /**
340+ * Show an indicator if someone is currently typing a message.
341+ */
342+ hasTypingIndicator: {
343+ type: Boolean ,
344+ default: false ,
345+ },
331346 },
332347
333348 emits: [' sent' , ' failure' ],
@@ -336,7 +351,10 @@ export default {
336351
337352 setup () {
338353 const { openViewer } = useViewer ()
339- return { openViewer }
354+ return {
355+ openViewer,
356+ supportTypingStatus,
357+ }
340358 },
341359
342360 data () {
@@ -354,6 +372,7 @@ export default {
354372 checked: - 1 ,
355373 userData: {},
356374 clipboardTimeStamp: null ,
375+ typingTimeout: null ,
357376 }
358377 },
359378
@@ -483,6 +502,10 @@ export default {
483502 showAudioRecorder () {
484503 return ! this .hasText && this .canUploadFiles && ! this .broadcast
485504 },
505+ showTypingStatus () {
506+ return this .hasTypingIndicator && this .supportTypingStatus
507+ && this .$store .getters .getTypingStatusPrivacy () === PRIVACY .PUBLIC
508+ },
486509 },
487510
488511 watch: {
@@ -492,6 +515,21 @@ export default {
492515
493516 text (newValue ) {
494517 this .$store .dispatch (' setCurrentMessageInput' , { token: this .token , text: newValue })
518+
519+ // Enable signal sending, only if indicator for this input is on
520+ if (this .showTypingStatus ) {
521+ clearTimeout (this .typingTimeout )
522+
523+ if (! newValue) {
524+ this .$store .dispatch (' setTyping' , { typing: false })
525+ return
526+ }
527+
528+ this .typingTimeout = setTimeout (() => {
529+ this .$store .dispatch (' setTyping' , { typing: false })
530+ }, 5000 )
531+ this .$store .dispatch (' setTyping' , { typing: true })
532+ }
495533 },
496534
497535 token (token ) {
@@ -500,6 +538,7 @@ export default {
500538 } else {
501539 this .text = ' '
502540 }
541+ this .$store .dispatch (' setTyping' , { typing: false })
503542 },
504543
505544 showTextFileDialog (newValue ) {
@@ -929,22 +968,29 @@ export default {
929968@import ' ../../assets/variables' ;
930969
931970.wrapper {
971+ position: relative;
932972 display: flex;
933973 justify- content: center;
934- padding: 12px 0 ;
974+ padding: 12px 0 12px ;
935975 min- height: 69px ;
976+
977+ & -- has- typing- indicator {
978+ padding: 30px 0 12px ;
979+ }
936980}
937981
938982.new - message {
939983 width: 100 % ;
940984 display: flex;
941985 justify- content: center;
986+
942987 & - form {
943988 align- items: flex- end;
944989 display: flex;
945- position: relative;
990+ position: relative;
946991 flex: 0 1 700px ;
947992 margin: 0 4px ;
993+
948994 & __emoji- picker {
949995 position: absolute;
950996 bottom: 1px ;
@@ -963,6 +1009,7 @@ export default {
9631009 border- radius: calc (var (-- default- clickable- area) / 2 );
9641010 padding: 8px 16px 8px 44px ;
9651011 max- height: 180px ;
1012+
9661013 & : hover,
9671014 & : focus,
9681015 & : active {
@@ -994,10 +1041,12 @@ export default {
9941041// Targeting two classess for specificity
9951042: deep (.action - item__menutoggle .action - item__menutoggle -- with - icon - slot ) {
9961043 opacity: 1 ! important;
1044+
9971045 & : hover,
9981046 & : focus {
9991047 background- color: var (-- color- background- hover) ! important;
10001048 }
1049+
10011050 & : disabled {
10021051 opacity: .5 ! important;
10031052 }
0 commit comments