comparison cagou/plugins/plugin_wid_chat.py @ 325:5868a5575e01

chat: cleaning + some improvments: - code cleaning, removed some dead code - some improvments on the way size is calculated, removed unnecessary sizing methods which were linked to properties - image have now a max size, this avoid gigantic image in the whole screen - in SimpleXHTMLWidget, Label are now splitted when xhtml is set - use a DelayedBoxLayout for messages, as they are really slow to be resized - use of RecycleView has been investigated, but it is not currently usable as dynamic contents are not propertly handled (see https://github.com/kivy/kivy/issues/6580 and https://github.com/kivy/kivy/issues/6582). Furthermore, some tests with RecycleView on Android don't give the expected speed boost, so BoxLayout still seems like the way to go for the moment. To be re-investigated at a later point if necessary.
author Goffi <goffi@goffi.org>
date Fri, 06 Dec 2019 13:25:31 +0100
parents e2b51663d8b8
children d9d2b56f46db
comparison
equal deleted inserted replaced
324:4374cb741eb5 325:5868a5575e01
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3 2
4 # Cagou: desktop/mobile frontend for Salut à Toi XMPP client 3 # Cagou: desktop/mobile frontend for Salut à Toi XMPP client
5 # Copyright (C) 2016-2019 Jérôme Poisson (goffi@goffi.org) 4 # Copyright (C) 2016-2019 Jérôme Poisson (goffi@goffi.org)
6 5
7 # This program is free software: you can redistribute it and/or modify 6 # This program is free software: you can redistribute it and/or modify
19 18
20 19
21 from functools import partial 20 from functools import partial
22 import mimetypes 21 import mimetypes
23 import sys 22 import sys
24 from sat.core import log as logging
25 from sat.core.i18n import _
26 from sat.core import exceptions
27 from cagou.core.constants import Const as C
28 from kivy.uix.boxlayout import BoxLayout 23 from kivy.uix.boxlayout import BoxLayout
29 from kivy.uix.gridlayout import GridLayout
30 from kivy.uix.textinput import TextInput 24 from kivy.uix.textinput import TextInput
31 from kivy.metrics import sp, dp 25 from kivy.metrics import sp, dp
32 from kivy.clock import Clock 26 from kivy.clock import Clock
33 from kivy import properties 27 from kivy import properties
28 from kivy.uix.dropdown import DropDown
29 from kivy.core.window import Window
30 from sat.core import log as logging
31 from sat.core.i18n import _
32 from sat.core import exceptions
34 from sat_frontends.quick_frontend import quick_widgets 33 from sat_frontends.quick_frontend import quick_widgets
35 from sat_frontends.quick_frontend import quick_chat 34 from sat_frontends.quick_frontend import quick_chat
36 from sat_frontends.tools import jid 35 from sat_frontends.tools import jid
36 from cagou import G
37 from cagou.core.constants import Const as C
37 from cagou.core import cagou_widget 38 from cagou.core import cagou_widget
38 from cagou.core import xmlui 39 from cagou.core import xmlui
39 from cagou.core.image import Image 40 from cagou.core.image import Image
40 from cagou.core.common import SymbolButton, JidButton 41 from cagou.core.common import SymbolButton, JidButton
41 from kivy.uix.dropdown import DropDown
42 from kivy.core.window import Window
43 from cagou import G
44 from cagou.core import menu 42 from cagou.core import menu
43 # from random import randrange
45 44
46 log = logging.getLogger(__name__) 45 log = logging.getLogger(__name__)
47 46
48 PLUGIN_INFO = { 47 PLUGIN_INFO = {
49 "name": _("chat"), 48 "name": _("chat"),
71 70
72 class MessAvatar(Image): 71 class MessAvatar(Image):
73 pass 72 pass
74 73
75 74
76 class MessageWidget(BoxLayout, quick_chat.MessageWidget): 75 class MessageWidget(quick_chat.MessageWidget, BoxLayout):
77 mess_data = properties.ObjectProperty() 76 mess_data = properties.ObjectProperty()
78 mess_xhtml = properties.ObjectProperty() 77 mess_xhtml = properties.ObjectProperty()
79 mess_padding = (dp(5), dp(5)) 78 mess_padding = (dp(5), dp(5))
80 avatar = properties.ObjectProperty() 79 avatar = properties.ObjectProperty()
81 delivery = properties.ObjectProperty() 80 delivery = properties.ObjectProperty()
82 font_size = properties.NumericProperty(sp(12)) 81 font_size = properties.NumericProperty(sp(12))
83 82 right_part = properties.ObjectProperty()
84 def __init__(self, **kwargs): 83 header_box = properties.ObjectProperty()
85 # self must be registered in widgets before kv is parsed 84
86 kwargs['mess_data'].widgets.add(self) 85 def on_mess_data(self, wid, mess_data):
87 super(MessageWidget, self).__init__(**kwargs) 86 mess_data.widgets.add(self)
88 avatar_path = self.mess_data.avatar
89 if avatar_path is not None:
90 self.avatar.source = avatar_path
91 87
92 @property 88 @property
93 def chat(self): 89 def chat(self):
94 """return parent Chat instance""" 90 """return parent Chat instance"""
95 return self.mess_data.parent 91 return self.mess_data.parent
96 92
93 def _get_from_mess_data(self, name, default):
94 if self.mess_data is None:
95 return default
96 return getattr(self.mess_data, name)
97
97 def _get_message(self): 98 def _get_message(self):
98 """Return currently displayed message""" 99 """Return currently displayed message"""
100 if self.mess_data is None:
101 return ""
99 return self.mess_data.main_message 102 return self.mess_data.main_message
100 103
101 def _set_message(self, message): 104 def _set_message(self, message):
105 if self.mess_data is None:
106 return False
102 if message == self.mess_data.message.get(""): 107 if message == self.mess_data.message.get(""):
103 return False 108 return False
104 self.mess_data.message = {"": message} 109 self.mess_data.message = {"": message}
105 return True 110 return True
106 111
107 message = properties.AliasProperty(_get_message, _set_message) 112 message = properties.AliasProperty(
108 113 partial(_get_from_mess_data, name="main_message", default=""),
109 @property 114 _set_message,
110 def message_xhtml(self): 115 bind=['mess_data'],
111 """Return currently displayed message""" 116 )
112 return self.mess_data.main_message_xhtml 117 message_xhtml = properties.AliasProperty(
118 partial(_get_from_mess_data, name="main_message_xhtml", default=""),
119 bind=['mess_data'])
120 mess_type = properties.AliasProperty(
121 partial(_get_from_mess_data, name="type", default=""), bind=['mess_data'])
122 own_mess = properties.AliasProperty(
123 partial(_get_from_mess_data, name="own_mess", default=False), bind=['mess_data'])
124 nick = properties.AliasProperty(
125 partial(_get_from_mess_data, name="nick", default=""), bind=['mess_data'])
126 time_text = properties.AliasProperty(
127 partial(_get_from_mess_data, name="time_text", default=""), bind=['mess_data'])
113 128
114 @property 129 @property
115 def info_type(self): 130 def info_type(self):
116 return self.mess_data.info_type 131 return self.mess_data.info_type
117
118 def widthAdjust(self):
119 """this widget grows up with its children"""
120 pass
121 # parent = self.mess_xhtml.parent
122 # padding_x = self.mess_padding[0]
123 # text_width, text_height = self.mess_xhtml.texture_size
124 # if text_width > parent.width:
125 # self.mess_xhtml.text_size = (parent.width - padding_x, None)
126 # self.text_max = text_width
127 # elif self.mess_xhtml.text_size[0] is not None and text_width < parent.width - padding_x:
128 # if text_width < self.text_max:
129 # self.mess_xhtml.text_size = (None, None)
130 # else:
131 # self.mess_xhtml.text_size = (parent.width - padding_x, None)
132 132
133 def update(self, update_dict): 133 def update(self, update_dict):
134 if 'avatar' in update_dict: 134 if 'avatar' in update_dict:
135 self.avatar.source = update_dict['avatar'] 135 self.avatar.source = update_dict['avatar']
136 if 'status' in update_dict: 136 if 'status' in update_dict:
171 return super(MessageInputWidget, self).keyboard_on_key_down( 171 return super(MessageInputWidget, self).keyboard_on_key_down(
172 window, keycode, text, modifiers) 172 window, keycode, text, modifiers)
173 173
174 def send_text(self): 174 def send_text(self):
175 self.dispatch('on_text_validate') 175 self.dispatch('on_text_validate')
176
177
178 class MessagesWidget(GridLayout):
179 pass
180 176
181 177
182 class TransferButton(SymbolButton): 178 class TransferButton(SymbolButton):
183 chat = properties.ObjectProperty() 179 chat = properties.ObjectProperty()
184 180
424 self.encryption_btn = EncryptionMainButton(self) 420 self.encryption_btn = EncryptionMainButton(self)
425 self.headerInputAddExtra(self.encryption_btn) 421 self.headerInputAddExtra(self.encryption_btn)
426 self.extra_menu = ExtraMenu(chat=self) 422 self.extra_menu = ExtraMenu(chat=self)
427 extra_btn = ExtraButton(chat=self) 423 extra_btn = ExtraButton(chat=self)
428 self.headerInputAddExtra(extra_btn) 424 self.headerInputAddExtra(extra_btn)
429 self.header_input.hint_text = "{}".format(target) 425 self.header_input.hint_text = target
430 self.postInit() 426 Clock.schedule_once(lambda dt: self.postInit(), 0)
431 427
432 def __str__(self): 428 def __str__(self):
433 return "Chat({})".format(self.target) 429 return "Chat({})".format(self.target)
434 430
435 def __repr__(self): 431 def __repr__(self):