55import json
66import os
77import requests
8- import subprocess
98import sys
109import traceback
1110import tempfile
1211import urwid
1312from datetime import datetime
14- from slackclient import SlackClient
1513from sclack .components import Attachment , Channel , ChannelHeader , ChatBox , Dm
1614from sclack .components import Indicators , MarkdownText , Message , MessageBox
1715from sclack .components import NewMessagesDivider , Profile , ProfileSideBar
@@ -36,6 +34,7 @@ def run(self):
3634 def set_exception_handler (self , handler ):
3735 self ._custom_exception_handler = handler
3836
37+
3938class App :
4039 message_box = None
4140
@@ -165,22 +164,51 @@ def mount_sidebar(self, executor):
165164 urwid .connect_signal (self .sidebar , 'go_to_channel' , self .go_to_channel )
166165 loop .create_task (self .get_channels_info (executor , channels ))
167166 loop .create_task (self .get_presences (executor , dms ))
167+ loop .create_task (self .get_dms_unread (executor , dms ))
168168
169169 @asyncio .coroutine
170170 def get_presences (self , executor , dm_widgets ):
171+ """
172+ Compute and return presence because updating UI from another thread is unsafe
173+ :param executor:
174+ :param dm_widgets:
175+ :return:
176+ """
171177 def get_presence (dm_widget ):
172- # Compute and return presence because updating UI from another thread is unsafe
173178 presence = self .store .get_presence (dm_widget .user )
174179 return [dm_widget , presence ]
175180 presences = yield from asyncio .gather (* [
176181 loop .run_in_executor (executor , get_presence , dm_widget )
177182 for dm_widget in dm_widgets
178183 ])
184+
179185 for presence in presences :
180186 [widget , response ] = presence
181187 if response ['ok' ]:
182188 widget .set_presence (response ['presence' ])
183189
190+ @asyncio .coroutine
191+ def get_dms_unread (self , executor , dm_widgets ):
192+ """
193+ Compute and return unread_count_display because updating UI from another thread is unsafe
194+ :param executor:
195+ :param dm_widgets:
196+ :return:
197+ """
198+ def get_presence (dm_widget ):
199+ profile_response = self .store .get_channel_info (dm_widget .id )
200+ return [dm_widget , profile_response ]
201+
202+ responses = yield from asyncio .gather (* [
203+ loop .run_in_executor (executor , get_presence , dm_widget )
204+ for dm_widget in dm_widgets
205+ ])
206+
207+ for profile_response in responses :
208+ [widget , response ] = profile_response
209+ if response is not None :
210+ widget .set_unread (response ['unread_count_display' ])
211+
184212 @asyncio .coroutine
185213 def get_channels_info (self , executor , channels ):
186214 def get_info (channel ):
@@ -190,10 +218,20 @@ def get_info(channel):
190218 loop .run_in_executor (executor , get_info , channel )
191219 for channel in channels
192220 ])
221+
193222 for channel_info in channels_info :
194223 [widget , response ] = channel_info
195224 widget .set_unread (response .get ('unread_count_display' , 0 ))
196225
226+ @asyncio .coroutine
227+ def update_chat (self , event ):
228+ """
229+ Update channel/DM message count badge
230+ :param event:
231+ :return:
232+ """
233+ self .sidebar .update_items (event )
234+
197235 @asyncio .coroutine
198236 def mount_chatbox (self , executor , channel ):
199237 yield from asyncio .gather (
@@ -409,7 +447,7 @@ def lazy_load_images(self, files, widget):
409447 if not self .config ['features' ]['pictures' ]:
410448 return
411449
412- allowed_file_types = ('bmp' , 'gif' , 'jpeg' , 'jpg' , 'png' )
450+ allowed_file_types = ('bmp' , 'gif' , 'jpeg' , 'jpg' , 'png' )
413451
414452 for file in files :
415453 if file .get ('filetype' ) in allowed_file_types :
@@ -420,7 +458,6 @@ def lazy_load_images(self, files, widget):
420458 not file .get ('is_external' , True )
421459 ))
422460
423-
424461 def render_messages (self , messages ):
425462 _messages = []
426463 previous_date = self .store .state .last_date
@@ -438,6 +475,7 @@ def render_messages(self, messages):
438475 date_text = 'Today'
439476 else :
440477 date_text = message_date .strftime ('%A, %B %d' )
478+
441479 # New messages badge
442480 if (message_datetime > last_read_datetime and not self .store .state .did_render_new_messages
443481 and (self .store .state .channel .get ('unread_count_display' , 0 ) > 0 )):
@@ -530,7 +568,10 @@ def start_real_time(self):
530568 self .store .slack .rtm_connect (auto_reconnect = True )
531569
532570 def stop_typing (* args ):
533- self .chatbox .message_box .typing = None
571+ # Prevent error while switching workspace
572+ if self .chatbox is not None :
573+ self .chatbox .message_box .typing = None
574+
534575 alarm = None
535576 while self .store .slack .server .connected is True :
536577 events = self .store .slack .rtm_read ()
@@ -542,9 +583,12 @@ def stop_typing(*args):
542583 for channel in self .sidebar .channels :
543584 if channel .id == event ['channel' ]:
544585 channel .set_unread (unread )
545- elif event .get ('channel' ) == self .store .state .channel ['id' ]:
546- if event ['type' ] == 'message' :
547- # Delete message
586+ elif event ['type' ] == 'message' :
587+ loop .create_task (
588+ self .update_chat (event )
589+ )
590+
591+ if event .get ('channel' ) == self .store .state .channel ['id' ]:
548592 if event .get ('subtype' ) == 'message_deleted' :
549593 for widget in self .chatbox .body .body :
550594 if hasattr (widget , 'ts' ) and getattr (widget , 'ts' ) == event ['deleted_ts' ]:
0 commit comments