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
@@ -162,22 +161,51 @@ def mount_sidebar(self, executor):
162161 urwid .connect_signal (self .sidebar , 'go_to_channel' , self .go_to_channel )
163162 loop .create_task (self .get_channels_info (executor , channels ))
164163 loop .create_task (self .get_presences (executor , dms ))
164+ loop .create_task (self .get_dms_unread (executor , dms ))
165165
166166 @asyncio .coroutine
167167 def get_presences (self , executor , dm_widgets ):
168+ """
169+ Compute and return presence because updating UI from another thread is unsafe
170+ :param executor:
171+ :param dm_widgets:
172+ :return:
173+ """
168174 def get_presence (dm_widget ):
169- # Compute and return presence because updating UI from another thread is unsafe
170175 presence = self .store .get_presence (dm_widget .user )
171176 return [dm_widget , presence ]
172177 presences = yield from asyncio .gather (* [
173178 loop .run_in_executor (executor , get_presence , dm_widget )
174179 for dm_widget in dm_widgets
175180 ])
181+
176182 for presence in presences :
177183 [widget , response ] = presence
178184 if response ['ok' ]:
179185 widget .set_presence (response ['presence' ])
180186
187+ @asyncio .coroutine
188+ def get_dms_unread (self , executor , dm_widgets ):
189+ """
190+ Compute and return unread_count_display because updating UI from another thread is unsafe
191+ :param executor:
192+ :param dm_widgets:
193+ :return:
194+ """
195+ def get_presence (dm_widget ):
196+ profile_response = self .store .get_channel_info (dm_widget .id )
197+ return [dm_widget , profile_response ]
198+
199+ responses = yield from asyncio .gather (* [
200+ loop .run_in_executor (executor , get_presence , dm_widget )
201+ for dm_widget in dm_widgets
202+ ])
203+
204+ for profile_response in responses :
205+ [widget , response ] = profile_response
206+ if response is not None :
207+ widget .set_unread (response ['unread_count_display' ])
208+
181209 @asyncio .coroutine
182210 def get_channels_info (self , executor , channels ):
183211 def get_info (channel ):
@@ -187,10 +215,20 @@ def get_info(channel):
187215 loop .run_in_executor (executor , get_info , channel )
188216 for channel in channels
189217 ])
218+
190219 for channel_info in channels_info :
191220 [widget , response ] = channel_info
192221 widget .set_unread (response .get ('unread_count_display' , 0 ))
193222
223+ @asyncio .coroutine
224+ def update_chat (self , event ):
225+ """
226+ Update channel/DM message count badge
227+ :param event:
228+ :return:
229+ """
230+ self .sidebar .update_items (event )
231+
194232 @asyncio .coroutine
195233 def mount_chatbox (self , executor , channel ):
196234 yield from asyncio .gather (
@@ -406,7 +444,7 @@ def lazy_load_images(self, files, widget):
406444 if not self .config ['features' ]['pictures' ]:
407445 return
408446
409- allowed_file_types = ('bmp' , 'gif' , 'jpeg' , 'jpg' , 'png' )
447+ allowed_file_types = ('bmp' , 'gif' , 'jpeg' , 'jpg' , 'png' )
410448
411449 for file in files :
412450 if file .get ('filetype' ) in allowed_file_types :
@@ -417,7 +455,6 @@ def lazy_load_images(self, files, widget):
417455 not file .get ('is_external' , True )
418456 ))
419457
420-
421458 def render_messages (self , messages ):
422459 _messages = []
423460 previous_date = self .store .state .last_date
@@ -435,6 +472,7 @@ def render_messages(self, messages):
435472 date_text = 'Today'
436473 else :
437474 date_text = message_date .strftime ('%A, %B %d' )
475+
438476 # New messages badge
439477 if (message_datetime > last_read_datetime and not self .store .state .did_render_new_messages
440478 and (self .store .state .channel .get ('unread_count_display' , 0 ) > 0 )):
@@ -527,7 +565,10 @@ def start_real_time(self):
527565 self .store .slack .rtm_connect (auto_reconnect = True )
528566
529567 def stop_typing (* args ):
530- self .chatbox .message_box .typing = None
568+ # Prevent error while switching workspace
569+ if self .chatbox is not None :
570+ self .chatbox .message_box .typing = None
571+
531572 alarm = None
532573 while self .store .slack .server .connected is True :
533574 events = self .store .slack .rtm_read ()
@@ -539,9 +580,12 @@ def stop_typing(*args):
539580 for channel in self .sidebar .channels :
540581 if channel .id == event ['channel' ]:
541582 channel .set_unread (unread )
542- elif event .get ('channel' ) == self .store .state .channel ['id' ]:
543- if event ['type' ] == 'message' :
544- # Delete message
583+ elif event ['type' ] == 'message' :
584+ loop .create_task (
585+ self .update_chat (event )
586+ )
587+
588+ if event .get ('channel' ) == self .store .state .channel ['id' ]:
545589 if event .get ('subtype' ) == 'message_deleted' :
546590 for widget in self .chatbox .body .body :
547591 if hasattr (widget , 'ts' ) and getattr (widget , 'ts' ) == event ['deleted_ts' ]:
0 commit comments