comparison libervia/web/pages/calls/_browser/__init__.py @ 1563:e3449beac8d8

browser (calls): Add clear search + formatting
author Goffi <goffi@goffi.org>
date Thu, 17 Aug 2023 16:23:01 +0200
parents 4afafce0c4c9
children bd3c880f4a47
comparison
equal deleted inserted replaced
1562:4afafce0c4c9 1563:e3449beac8d8
12 12
13 log.warning = log.warn 13 log.warning = log.warn
14 profile = window.profile or "" 14 profile = window.profile or ""
15 bridge = Bridge() 15 bridge = Bridge()
16 GATHER_TIMEOUT = 10000 16 GATHER_TIMEOUT = 10000
17 ALLOWED_STATUSES = (None, "dialing", "ringing", "in-call", "on-hold", "connecting", "connection-lost", "reconnecting") 17 ALLOWED_STATUSES = (
18 None,
19 "dialing",
20 "ringing",
21 "in-call",
22 "on-hold",
23 "connecting",
24 "connection-lost",
25 "reconnecting",
26 )
18 AUDIO = "audio" 27 AUDIO = "audio"
19 VIDEO = "video" 28 VIDEO = "video"
20 ALLOWED_CALL_MODES = {AUDIO, VIDEO} 29 ALLOWED_CALL_MODES = {AUDIO, VIDEO}
21 INACTIVE_CLASS = "inactive" 30 INACTIVE_CLASS = "inactive"
22 MUTED_CLASS = "muted" 31 MUTED_CLASS = "muted"
47 bridge.register_signal("call_setup", self._on_call_setup) 56 bridge.register_signal("call_setup", self._on_call_setup)
48 bridge.register_signal("call_ended", self._on_call_ended) 57 bridge.register_signal("call_ended", self._on_call_ended)
49 58
50 # call/hang up buttons 59 # call/hang up buttons
51 self._call_mode = VIDEO 60 self._call_mode = VIDEO
52 document["video_call_btn"].bind( 61 document["video_call_btn"].bind("click", lambda __: aio.run(self.make_call()))
53 "click",
54 lambda __: aio.run(self.make_call())
55
56 )
57 document["audio_call_btn"].bind( 62 document["audio_call_btn"].bind(
58 "click", 63 "click", lambda __: aio.run(self.make_call(video=False))
59 lambda __: aio.run(self.make_call(video=False))
60
61 ) 64 )
62 document["hangup_btn"].bind("click", lambda __: aio.run(self.hang_up())) 65 document["hangup_btn"].bind("click", lambda __: aio.run(self.hang_up()))
63 66
64 # other buttons 67 # other buttons
65 document["full_screen_btn"].bind("click", lambda __: self.toggle_fullscreen()) 68 document["full_screen_btn"].bind("click", lambda __: self.toggle_fullscreen())
75 self.share_desktop_btn_elt.bind("click", self.toggle_screen_sharing) 78 self.share_desktop_btn_elt.bind("click", self.toggle_screen_sharing)
76 else: 79 else:
77 self.share_desktop_btn_elt.classList.add("is-hidden") 80 self.share_desktop_btn_elt.classList.add("is-hidden")
78 81
79 # search 82 # search
83 self.search_elt = document["search"]
80 self.jid_search = JidSearch( 84 self.jid_search = JidSearch(
81 document["search"], 85 self.search_elt,
82 document["contacts"], 86 document["contacts"],
83 click_cb=self._on_entity_click, 87 click_cb=self._on_entity_click,
84 template="call/search_item.html", 88 template="call/search_item.html",
85 options={ 89 options={
86 "no_group": True, 90 "no_group": True,
92 self.on_entity_action(evt, VIDEO, item) 96 self.on_entity_action(evt, VIDEO, item)
93 ), 97 ),
94 ".click-to-audio": lambda evt, item: aio.run( 98 ".click-to-audio": lambda evt, item: aio.run(
95 self.on_entity_action(evt, AUDIO, item) 99 self.on_entity_action(evt, AUDIO, item)
96 ), 100 ),
97 } 101 },
98 } 102 },
99 ) 103 )
104 document["clear_search_btn"].bind("click", self.on_clear_search)
100 105
101 # incoming call dialog 106 # incoming call dialog
102 self.incoming_call_dialog_elt = None 107 self.incoming_call_dialog_elt = None
103 108
104 @property 109 @property
149 else: 154 else:
150 elt.classList.add("is-hidden") 155 elt.classList.add("is-hidden")
151 else: 156 else:
152 raise ValueError("Invalid call mode") 157 raise ValueError("Invalid call mode")
153 158
154 def set_avatar(self, entity_jid: JID|str) -> None: 159 def set_avatar(self, entity_jid: JID | str) -> None:
155 """Set the avatar element from entity_jid 160 """Set the avatar element from entity_jid
156 161
157 @param entity_jid: bare jid of the entity 162 @param entity_jid: bare jid of the entity
158 """ 163 """
159 call_avatar_elt = self.call_avatar_tpl.get_elt( 164 call_avatar_elt = self.call_avatar_tpl.get_elt(
310 @param audio: True if an audio flux is required 315 @param audio: True if an audio flux is required
311 @param video: True if a video flux is required 316 @param video: True if a video flux is required
312 """ 317 """
313 self.call_mode = VIDEO if video else AUDIO 318 self.call_mode = VIDEO if video else AUDIO
314 try: 319 try:
315 callee_jid = JID(document["search"].value.strip()) 320 callee_jid = JID(self.search_elt.value.strip())
316 if not callee_jid.is_valid: 321 if not callee_jid.is_valid:
317 raise ValueError 322 raise ValueError
318 except ValueError: 323 except ValueError:
319 dialog.notification.show( 324 dialog.notification.show(
320 "Invalid identifier, please use a valid callee identifier", level="error" 325 "Invalid identifier, please use a valid callee identifier", level="error"
429 ) 434 )
430 self.mode = mode 435 self.mode = mode
431 else: 436 else:
432 log.error(f"Internal Error: Unknown call mode: {mode}") 437 log.error(f"Internal Error: Unknown call mode: {mode}")
433 438
439 def on_clear_search(self, ev) -> None:
440 """Clear the search input and trigger its 'input' event.
441
442 @param ev: the event object from the button click.
443 """
444 if not self.search_elt.value:
445 return
446 # clear the search field
447 self.search_elt.value = ''
448 # and dispatch the input event so items are updated
449 self.search_elt.dispatchEvent(window.Event.new("input"))
450
434 def toggle_fullscreen(self, fullscreen: bool | None = None): 451 def toggle_fullscreen(self, fullscreen: bool | None = None):
435 """Toggle fullscreen mode for video elements. 452 """Toggle fullscreen mode for video elements.
436 453
437 @param fullscreen: if set, determine the fullscreen state; otherwise, 454 @param fullscreen: if set, determine the fullscreen state; otherwise,
438 the fullscreen mode will be toggled. 455 the fullscreen mode will be toggled.
439 """ 456 """
440 do_fullscreen = ( 457 do_fullscreen = (
441 document.fullscreenElement is None if fullscreen is None else fullscreen 458 document.fullscreenElement is None if fullscreen is None else fullscreen
442 ) 459 )
443 460
504 def _on_entity_click(self, item: dict) -> None: 521 def _on_entity_click(self, item: dict) -> None:
505 aio.run(self.on_entity_click(item)) 522 aio.run(self.on_entity_click(item))
506 523
507 async def on_entity_click(self, item: dict) -> None: 524 async def on_entity_click(self, item: dict) -> None:
508 """Set entity JID to search bar, and start the call""" 525 """Set entity JID to search bar, and start the call"""
509 document["search"].value = item["entity"] 526 self.search_elt.value = item["entity"]
510 527
511 await self.make_call() 528 await self.make_call()
512 529
513 async def on_entity_action(self, evt, action: str, item: dict) -> None: 530 async def on_entity_action(self, evt, action: str, item: dict) -> None:
514 """Handle extra actions on search items""" 531 """Handle extra actions on search items"""
515 evt.stopPropagation() 532 evt.stopPropagation()
516 if action == "menu": 533 if action == "menu":
517 evt.currentTarget.parent.classList.toggle("is-active") 534 evt.currentTarget.parent.classList.toggle("is-active")
518 elif action in (VIDEO, AUDIO): 535 elif action in (VIDEO, AUDIO):
519 document["search"].value = item["entity"] 536 self.search_elt.value = item["entity"]
520 # we want the dropdown to be inactive 537 # we want the dropdown to be inactive
521 evt.currentTarget.closest(".dropdown").classList.remove("is-active") 538 evt.currentTarget.closest(".dropdown").classList.remove("is-active")
522 await self.make_call(video=action==VIDEO) 539 await self.make_call(video=action == VIDEO)
523 540
524 541
525 CallUI() 542 CallUI()
526 loading.remove_loading_screen() 543 loading.remove_loading_screen()