Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vmj-qt
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kulya
vmj-qt
Commits
389725c5
Commit
389725c5
authored
May 24, 2022
by
Tijmen de Mes
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Load messages from history in chat/messages
parent
e10d8fc8
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
93 additions
and
5 deletions
+93
-5
chatwindow.py
blink/chatwindow.py
+93
-5
No files found.
blink/chatwindow.py
View file @
389725c5
...
@@ -21,7 +21,7 @@ from application.python.types import MarkerType
...
@@ -21,7 +21,7 @@ from application.python.types import MarkerType
from
application.system
import
makedirs
from
application.system
import
makedirs
from
collections.abc
import
MutableSet
from
collections.abc
import
MutableSet
from
collections
import
deque
from
collections
import
deque
from
datetime
import
datetime
,
timedelta
from
datetime
import
datetime
,
timedelta
,
timezone
from
itertools
import
count
from
itertools
import
count
from
lxml
import
etree
,
html
from
lxml
import
etree
,
html
from
lxml.html.clean
import
autolink
from
lxml.html.clean
import
autolink
...
@@ -34,11 +34,13 @@ from sipsimple.audio import WavePlayer
...
@@ -34,11 +34,13 @@ from sipsimple.audio import WavePlayer
from
sipsimple.configuration.settings
import
SIPSimpleSettings
from
sipsimple.configuration.settings
import
SIPSimpleSettings
from
sipsimple.streams.msrp.chat
import
OTRState
from
sipsimple.streams.msrp.chat
import
OTRState
from
sipsimple.threading
import
run_in_thread
from
sipsimple.threading
import
run_in_thread
from
sipsimple.util
import
ISOTimestamp
from
blink.configuration.datatypes
import
FileURL
,
GraphTimeScale
from
blink.configuration.datatypes
import
FileURL
,
GraphTimeScale
from
blink.configuration.settings
import
BlinkSettings
from
blink.configuration.settings
import
BlinkSettings
from
blink.contacts
import
URIUtils
from
blink.contacts
import
URIUtils
from
blink.messages
import
MessageManager
from
blink.history
import
HistoryManager
from
blink.messages
import
MessageManager
,
BlinkMessage
from
blink.resources
import
IconManager
,
Resources
from
blink.resources
import
IconManager
,
Resources
from
blink.sessions
import
ChatSessionModel
,
ChatSessionListView
,
SessionManager
,
StreamDescription
from
blink.sessions
import
ChatSessionModel
,
ChatSessionListView
,
SessionManager
,
StreamDescription
from
blink.util
import
run_in_gui_thread
from
blink.util
import
run_in_gui_thread
...
@@ -307,12 +309,13 @@ class ChatMessage(ChatContent):
...
@@ -307,12 +309,13 @@ class ChatMessage(ChatContent):
direction
=
ChatContentStringAttribute
(
'direction'
,
allowed_values
=
(
'incoming'
,
'outgoing'
))
direction
=
ChatContentStringAttribute
(
'direction'
,
allowed_values
=
(
'incoming'
,
'outgoing'
))
autoreply
=
ChatContentBooleanOption
(
'autoreply'
)
autoreply
=
ChatContentBooleanOption
(
'autoreply'
)
def
__init__
(
self
,
message
,
sender
,
direction
,
history
=
False
,
focus
=
False
,
id
=
None
):
def
__init__
(
self
,
message
,
sender
,
direction
,
history
=
False
,
focus
=
False
,
id
=
None
,
timestamp
=
None
):
super
(
ChatMessage
,
self
)
.
__init__
(
message
,
history
,
focus
)
super
(
ChatMessage
,
self
)
.
__init__
(
message
,
history
,
focus
)
self
.
sender
=
sender
self
.
sender
=
sender
self
.
direction
=
direction
self
.
direction
=
direction
self
.
id
=
str
(
uuid
.
uuid4
())
if
id
is
None
else
id
self
.
id
=
str
(
uuid
.
uuid4
())
if
id
is
None
else
id
self
.
status
=
''
self
.
status
=
''
self
.
timestamp
=
timestamp
if
timestamp
is
not
None
else
datetime
.
now
()
def
is_related_to
(
self
,
other
):
def
is_related_to
(
self
,
other
):
return
super
(
ChatMessage
,
self
)
.
is_related_to
(
other
)
and
self
.
sender
==
other
.
sender
and
self
.
direction
==
other
.
direction
return
super
(
ChatMessage
,
self
)
.
is_related_to
(
other
)
and
self
.
sender
==
other
.
sender
and
self
.
direction
==
other
.
direction
...
@@ -664,9 +667,12 @@ class ChatWidget(base_class, ui_class):
...
@@ -664,9 +667,12 @@ class ChatWidget(base_class, ui_class):
self
.
composing_timer
=
QTimer
()
self
.
composing_timer
=
QTimer
()
self
.
last_message
=
None
self
.
last_message
=
None
self
.
session
=
session
self
.
session
=
session
self
.
history_loaded
=
False
self
.
show_loading_screen
(
True
)
if
session
is
not
None
:
if
session
is
not
None
:
notification_center
=
NotificationCenter
()
notification_center
=
NotificationCenter
()
notification_center
.
add_observer
(
ObserverWeakrefProxy
(
self
),
sender
=
session
.
blink_session
)
notification_center
.
add_observer
(
ObserverWeakrefProxy
(
self
),
sender
=
session
.
blink_session
)
# connect to signals
# connect to signals
self
.
chat_input
.
textChanged
.
connect
(
self
.
_SH_ChatInputTextChanged
)
self
.
chat_input
.
textChanged
.
connect
(
self
.
_SH_ChatInputTextChanged
)
self
.
chat_input
.
textEntered
.
connect
(
self
.
_SH_ChatInputTextEntered
)
self
.
chat_input
.
textEntered
.
connect
(
self
.
_SH_ChatInputTextEntered
)
...
@@ -701,6 +707,12 @@ class ChatWidget(base_class, ui_class):
...
@@ -701,6 +707,12 @@ class ChatWidget(base_class, ui_class):
insertion_point
=
self
.
chat_element
.
findFirst
(
f
'span#status-{id}'
)
insertion_point
=
self
.
chat_element
.
findFirst
(
f
'span#status-{id}'
)
insertion_point
.
replace
(
ChatMessageStatus
(
status
,
icon
.
filename
,
id
)
.
to_html
(
self
.
style
))
insertion_point
.
replace
(
ChatMessageStatus
(
status
,
icon
.
filename
,
id
)
.
to_html
(
self
.
style
))
def
show_loading_screen
(
self
,
visible
):
if
visible
:
self
.
loading_element
.
appendInside
(
self
.
loading_template
)
else
:
self
.
loading_element
.
removeAllChildren
()
def
send_sip_message
(
self
,
content
,
content_type
=
'text/plain'
,
recipients
=
None
,
courtesy_recipients
=
None
,
subject
=
None
,
timestamp
=
None
,
required
=
None
,
additional_headers
=
None
,
id
=
None
):
def
send_sip_message
(
self
,
content
,
content_type
=
'text/plain'
,
recipients
=
None
,
courtesy_recipients
=
None
,
subject
=
None
,
timestamp
=
None
,
required
=
None
,
additional_headers
=
None
,
id
=
None
):
account
=
self
.
session
.
blink_session
.
account
account
=
self
.
session
.
blink_session
.
account
contact
=
self
.
session
.
blink_session
.
contact
contact
=
self
.
session
.
blink_session
.
contact
...
@@ -726,6 +738,10 @@ class ChatWidget(base_class, ui_class):
...
@@ -726,6 +738,10 @@ class ChatWidget(base_class, ui_class):
raise
RuntimeError
(
"Cannot send messages in the '
%
s' state"
%
blink_session
.
state
)
raise
RuntimeError
(
"Cannot send messages in the '
%
s' state"
%
blink_session
.
state
)
message_id
=
self
.
session
.
chat_stream
.
send_message
(
content
,
content_type
,
recipients
,
courtesy_recipients
,
subject
,
timestamp
,
required
,
additional_headers
)
message_id
=
self
.
session
.
chat_stream
.
send_message
(
content
,
content_type
,
recipients
,
courtesy_recipients
,
subject
,
timestamp
,
required
,
additional_headers
)
notification_center
=
NotificationCenter
()
timestamp
=
timestamp
if
timestamp
is
not
None
else
ISOTimestamp
.
now
()
notification_center
.
post_notification
(
'ChatStreamWillSendMessage'
,
blink_session
,
data
=
BlinkMessage
(
content
,
content_type
,
blink_session
.
account
,
recipients
,
timestamp
=
timestamp
,
id
=
message_id
))
return
message_id
return
message_id
def
_align_chat
(
self
,
scroll
=
False
):
def
_align_chat
(
self
,
scroll
=
False
):
...
@@ -932,6 +948,7 @@ class ChatWidget(base_class, ui_class):
...
@@ -932,6 +948,7 @@ class ChatWidget(base_class, ui_class):
self
.
composing_timer
.
stop
()
self
.
composing_timer
.
stop
()
self
.
chat_input
.
reset_locks
()
self
.
chat_input
.
reset_locks
()
del
ui_class
,
base_class
del
ui_class
,
base_class
...
@@ -1552,6 +1569,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
...
@@ -1552,6 +1569,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
self
.
restoreGeometry
(
geometry
)
self
.
restoreGeometry
(
geometry
)
self
.
pending_displayed_notifications
=
{}
self
.
pending_displayed_notifications
=
{}
self
.
render_after_load
=
[]
notification_center
=
NotificationCenter
()
notification_center
=
NotificationCenter
()
notification_center
.
add_observer
(
self
,
name
=
'SIPApplicationDidStart'
)
notification_center
.
add_observer
(
self
,
name
=
'SIPApplicationDidStart'
)
...
@@ -1577,6 +1595,8 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
...
@@ -1577,6 +1595,8 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
notification_center
.
add_observer
(
self
,
name
=
'BlinkGotDispositionNotification'
)
notification_center
.
add_observer
(
self
,
name
=
'BlinkGotDispositionNotification'
)
notification_center
.
add_observer
(
self
,
name
=
'BlinkMessageDidSucceed'
)
notification_center
.
add_observer
(
self
,
name
=
'BlinkMessageDidSucceed'
)
notification_center
.
add_observer
(
self
,
name
=
'BlinkMessageDidFail'
)
notification_center
.
add_observer
(
self
,
name
=
'BlinkMessageDidFail'
)
notification_center
.
add_observer
(
self
,
name
=
'BlinkMessageHistoryLoadDidSucceed'
)
notification_center
.
add_observer
(
self
,
name
=
'BlinkMessageHistoryLoadDidFail'
)
# self.splitter.splitterMoved.connect(self._SH_SplitterMoved) # check this and decide on what size to have in the window (see Notes) -Dan
# self.splitter.splitterMoved.connect(self._SH_SplitterMoved) # check this and decide on what size to have in the window (see Notes) -Dan
...
@@ -2227,10 +2247,14 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
...
@@ -2227,10 +2247,14 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
def
_NH_BlinkSessionNewIncoming
(
self
,
notification
):
def
_NH_BlinkSessionNewIncoming
(
self
,
notification
):
if
notification
.
sender
.
streams
.
types
.
intersection
(
self
.
__streamtypes__
):
if
notification
.
sender
.
streams
.
types
.
intersection
(
self
.
__streamtypes__
):
self
.
show
()
self
.
show
()
history
=
HistoryManager
()
history
.
load
(
notification
.
sender
.
contact
.
uri
.
uri
,
notification
.
sender
)
def
_NH_BlinkSessionNewOutgoing
(
self
,
notification
):
def
_NH_BlinkSessionNewOutgoing
(
self
,
notification
):
if
notification
.
sender
.
stream_descriptions
.
types
.
intersection
(
self
.
__streamtypes__
):
if
notification
.
sender
.
stream_descriptions
.
types
.
intersection
(
self
.
__streamtypes__
):
self
.
show
()
self
.
show
()
history
=
HistoryManager
()
history
.
load
(
notification
.
sender
.
contact
.
uri
.
uri
,
notification
.
sender
)
def
_NH_BlinkSessionDidReinitializeForIncoming
(
self
,
notification
):
def
_NH_BlinkSessionDidReinitializeForIncoming
(
self
,
notification
):
model
=
self
.
session_model
model
=
self
.
session_model
...
@@ -2319,8 +2343,10 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
...
@@ -2319,8 +2343,10 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
sender
=
ChatSender
(
message
.
sender
.
display_name
or
account
.
display_name
,
uri
,
session
.
chat_widget
.
user_icon
.
filename
)
sender
=
ChatSender
(
message
.
sender
.
display_name
or
account
.
display_name
,
uri
,
session
.
chat_widget
.
user_icon
.
filename
)
else
:
else
:
sender
=
ChatSender
(
message
.
sender
.
display_name
or
session
.
name
,
uri
,
session
.
icon
.
filename
)
sender
=
ChatSender
(
message
.
sender
.
display_name
or
session
.
name
,
uri
,
session
.
icon
.
filename
)
if
session
.
chat_widget
.
history_loaded
:
session
.
chat_widget
.
add_message
(
ChatMessage
(
content
,
sender
,
'incoming'
,
id
=
message
.
id
))
session
.
chat_widget
.
add_message
(
ChatMessage
(
content
,
sender
,
'incoming'
,
id
=
message
.
id
))
else
:
self
.
render_after_load
.
append
(
ChatMessage
(
content
,
sender
,
'incoming'
,
id
=
message
.
id
))
if
message
.
disposition
is
not
None
and
'display'
in
message
.
disposition
:
if
message
.
disposition
is
not
None
and
'display'
in
message
.
disposition
:
if
self
.
selected_session
.
blink_session
is
blink_session
and
not
self
.
isMinimized
()
and
self
.
isActiveWindow
():
if
self
.
selected_session
.
blink_session
is
blink_session
and
not
self
.
isMinimized
()
and
self
.
isActiveWindow
():
...
@@ -2364,6 +2390,68 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
...
@@ -2364,6 +2390,68 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
session
.
chat_widget
.
add_message
(
ChatStatus
(
f
'Delivery failed: {notification.data.data.code} - {notification.data.data.reason}'
))
session
.
chat_widget
.
add_message
(
ChatStatus
(
f
'Delivery failed: {notification.data.data.code} - {notification.data.data.reason}'
))
session
.
chat_widget
.
update_message_status
(
id
=
notification
.
data
.
id
,
status
=
'failed'
)
session
.
chat_widget
.
update_message_status
(
id
=
notification
.
data
.
id
,
status
=
'failed'
)
def
_NH_BlinkMessageHistoryLoadDidSucceed
(
self
,
notification
):
blink_session
=
notification
.
sender
session
=
blink_session
.
items
.
chat
messages
=
notification
.
data
.
messages
if
session
is
None
:
return
for
message
in
messages
:
if
message
.
content_type
.
startswith
(
'image/'
):
content
=
'''<img src="data:{};base64,{}" class="scaled-to-fit" />'''
.
format
(
message
.
content_type
,
message
.
content
.
decode
(
'base64'
)
.
rstrip
())
elif
message
.
content_type
.
startswith
(
'text/'
):
content
=
message
.
content
content
=
HtmlProcessor
.
autolink
(
content
if
message
.
content_type
==
'text/html'
else
QTextDocument
(
content
)
.
toHtml
())
else
:
return
# message.sender = SIPURI.parse(f'sip:{message.remote_uri}')
if
message
.
direction
==
'outgoing'
:
message
.
sender
=
blink_session
.
account
try
:
uri
=
'
%
s@
%
s'
%
(
message
.
sender
.
uri
.
user
.
decode
(),
message
.
sender
.
uri
.
host
.
decode
())
except
AttributeError
:
uri
=
'
%
s@
%
s'
%
(
message
.
sender
.
uri
.
user
,
message
.
sender
.
uri
.
host
)
else
:
uri
=
message
.
remote_uri
timestamp
=
message
.
timestamp
.
replace
(
tzinfo
=
timezone
.
utc
)
.
astimezone
()
.
replace
(
tzinfo
=
None
)
# print(f"t: {timestamp}")
account_manager
=
AccountManager
()
if
account_manager
.
has_account
(
uri
):
account
=
account_manager
.
get_account
(
uri
)
sender
=
ChatSender
(
message
.
display_name
or
account
.
display_name
,
uri
,
session
.
chat_widget
.
user_icon
.
filename
)
else
:
sender
=
ChatSender
(
message
.
display_name
or
session
.
name
,
uri
,
session
.
icon
.
filename
)
session
.
chat_widget
.
add_message
(
ChatMessage
(
content
,
sender
,
message
.
direction
,
id
=
message
.
message_id
,
timestamp
=
timestamp
,
history
=
True
))
# session.chat_widget.add_message(ChatMessage(content, sender, message.direction, id=message.id, timestamp=timestamp))
if
message
.
direction
==
"outgoing"
:
session
.
chat_widget
.
update_message_status
(
id
=
message
.
message_id
,
status
=
message
.
state
)
elif
message
.
state
!=
'displayed'
and
'display'
in
message
.
disposition
:
if
message
.
state
!=
'delivered'
and
'positive-delivery'
in
message
.
disposition
:
MessageManager
()
.
send_imdn_message
(
blink_session
,
message
.
message_id
,
message
.
timestamp
,
'delivered'
)
if
self
.
selected_session
.
blink_session
is
blink_session
and
not
self
.
isMinimized
()
and
self
.
isActiveWindow
():
MessageManager
()
.
send_imdn_message
(
blink_session
,
message
.
message_id
,
message
.
timestamp
,
'displayed'
)
else
:
self
.
pending_displayed_notifications
.
setdefault
(
blink_session
,
[])
.
append
((
message
.
message_id
,
message
.
timestamp
))
session
.
chat_widget
.
history_loaded
=
True
while
len
(
self
.
render_after_load
)
>
0
:
session
.
chat_widget
.
add_message
(
self
.
render_after_load
.
pop
())
session
.
chat_widget
.
show_loading_screen
(
False
)
def
_NH_BlinkMessageHistoryLoadDidFail
(
self
,
notification
):
blink_session
=
notification
.
sender
session
=
blink_session
.
items
.
chat
# TODO Should we attempt to reload history if it fails? -- Tijmen
session
.
chat_widget
.
history_loaded
=
True
session
.
chat_widget
.
show_loading_screen
(
False
)
def
_NH_ChatStreamGotMessage
(
self
,
notification
):
def
_NH_ChatStreamGotMessage
(
self
,
notification
):
blink_session
=
notification
.
sender
.
blink_session
blink_session
=
notification
.
sender
.
blink_session
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment