2021-05-04 14:53:03 -04:00
import RNS
2021-09-05 14:38:10 -04:00
import os
2021-05-04 14:53:03 -04:00
import time
import nomadnet
2021-05-13 10:39:31 -04:00
import LXMF
2021-05-04 14:53:03 -04:00
2021-05-12 08:02:44 -04:00
import urwid
2021-05-13 10:39:31 -04:00
from datetime import datetime
from nomadnet . Directory import DirectoryEntry
2021-05-14 11:36:35 -04:00
from nomadnet . vendor . additional_urwid_widgets import IndicativeListBox
2021-05-12 08:02:44 -04:00
class ConversationListDisplayShortcuts ( ) :
def __init__ ( self , app ) :
self . app = app
2021-05-15 15:08:30 -04:00
self . widget = urwid . AttrMap ( urwid . Text ( " [Enter] Open [C-e] Peer Info [C-x] Delete [C-n] New " ) , " shortcutbar " )
2021-05-12 08:02:44 -04:00
class ConversationDisplayShortcuts ( ) :
2021-05-04 05:08:16 -04:00
def __init__ ( self , app ) :
self . app = app
2021-09-11 05:33:20 -04:00
self . widget = urwid . AttrMap ( urwid . Text ( " [C-d] Send [C-k] Clear Editor [C-w] Close [C-t] Editor Type [C-p] Purge [C-x] Clear History " ) , " shortcutbar " )
2021-05-13 10:39:31 -04:00
class ConversationsArea ( urwid . LineBox ) :
def keypress ( self , size , key ) :
2021-05-14 08:45:20 -04:00
if key == " ctrl e " :
self . delegate . edit_selected_in_directory ( )
2021-05-13 10:39:31 -04:00
elif key == " ctrl x " :
self . delegate . delete_selected_conversation ( )
elif key == " ctrl n " :
self . delegate . new_conversation ( )
2021-05-14 11:36:35 -04:00
elif key == " tab " :
self . delegate . app . ui . main_display . frame . set_focus ( " header " )
2021-05-19 03:26:12 -04:00
elif key == " up " and ( self . delegate . ilb . first_item_is_selected ( ) or self . delegate . ilb . body_is_empty ( ) ) :
2021-05-14 11:36:35 -04:00
self . delegate . app . ui . main_display . frame . set_focus ( " header " )
2021-05-13 10:39:31 -04:00
else :
return super ( ConversationsArea , self ) . keypress ( size , key )
2021-05-04 05:08:16 -04:00
2021-05-14 16:12:42 -04:00
class DialogLineBox ( urwid . LineBox ) :
def keypress ( self , size , key ) :
if key == " esc " :
self . delegate . update_conversation_list ( )
else :
return super ( DialogLineBox , self ) . keypress ( size , key )
2021-05-04 05:08:16 -04:00
class ConversationsDisplay ( ) :
2021-05-04 14:53:03 -04:00
list_width = 0.33
cached_conversation_widgets = { }
2021-05-04 05:08:16 -04:00
def __init__ ( self , app ) :
self . app = app
2021-05-13 10:39:31 -04:00
self . dialog_open = False
2021-05-15 15:08:30 -04:00
self . currently_displayed_conversation = None
2021-05-04 09:10:21 -04:00
2021-05-12 08:02:44 -04:00
def disp_list_shortcuts ( sender , arg1 , arg2 ) :
self . shortcuts_display = self . list_shortcuts
self . app . ui . main_display . update_active_shortcuts ( )
2021-05-13 10:39:31 -04:00
self . update_listbox ( )
2021-05-04 09:10:21 -04:00
2021-05-15 15:08:30 -04:00
self . columns_widget = urwid . Columns (
[
( " weight " , ConversationsDisplay . list_width , self . listbox ) ,
( " weight " , 1 - ConversationsDisplay . list_width , self . make_conversation_widget ( None ) )
] ,
dividechars = 0 , focus_column = 0 , box_columns = [ 0 ]
)
2021-05-04 05:08:16 -04:00
2021-05-12 08:02:44 -04:00
self . list_shortcuts = ConversationListDisplayShortcuts ( self . app )
self . editor_shortcuts = ConversationDisplayShortcuts ( self . app )
self . shortcuts_display = self . list_shortcuts
2021-05-13 10:39:31 -04:00
self . widget = self . columns_widget
nomadnet . Conversation . created_callback = self . update_conversation_list
def focus_change_event ( self ) :
# This hack corrects buggy styling behaviour in IndicativeListBox
if not self . dialog_open :
ilb_position = self . ilb . get_selected_position ( )
self . update_conversation_list ( )
2021-05-13 14:25:04 -04:00
if ilb_position != None :
self . ilb . select_item ( ilb_position )
2021-05-13 10:39:31 -04:00
def update_listbox ( self ) :
conversation_list_widgets = [ ]
for conversation in self . app . conversations ( ) :
conversation_list_widgets . append ( self . conversation_list_widget ( conversation ) )
self . list_widgets = conversation_list_widgets
self . ilb = IndicativeListBox (
self . list_widgets ,
on_selection_change = self . conversation_list_selection ,
initialization_is_selection_change = False ,
highlight_offFocus = " list_off_focus "
)
self . listbox = ConversationsArea ( urwid . Filler ( self . ilb , height = ( " relative " , 100 ) ) )
self . listbox . delegate = self
def delete_selected_conversation ( self ) :
self . dialog_open = True
source_hash = self . ilb . get_selected_item ( ) . source_hash
def dismiss_dialog ( sender ) :
self . update_conversation_list ( )
self . dialog_open = False
def confirmed ( sender ) :
self . dialog_open = False
self . delete_conversation ( source_hash )
nomadnet . Conversation . delete_conversation ( source_hash , self . app )
self . update_conversation_list ( )
2021-05-14 16:12:42 -04:00
dialog = DialogLineBox (
2021-05-13 10:39:31 -04:00
urwid . Pile ( [
urwid . Text ( " Delete conversation with \n " + self . app . directory . simplest_display_str ( bytes . fromhex ( source_hash ) ) + " \n " , align = " center " ) ,
urwid . Columns ( [ ( " weight " , 0.45 , urwid . Button ( " Yes " , on_press = confirmed ) ) , ( " weight " , 0.1 , urwid . Text ( " " ) ) , ( " weight " , 0.45 , urwid . Button ( " No " , on_press = dismiss_dialog ) ) ] )
] ) , title = " ? "
)
2021-05-14 16:12:42 -04:00
dialog . delegate = self
2021-05-13 10:39:31 -04:00
bottom = self . listbox
overlay = urwid . Overlay ( dialog , bottom , align = " center " , width = ( " relative " , 100 ) , valign = " middle " , height = " pack " , left = 2 , right = 2 )
options = self . columns_widget . options ( " weight " , ConversationsDisplay . list_width )
self . columns_widget . contents [ 0 ] = ( overlay , options )
2021-05-14 08:45:20 -04:00
def edit_selected_in_directory ( self ) :
2021-07-02 07:35:10 -04:00
g = self . app . ui . glyphs
2021-05-13 10:39:31 -04:00
self . dialog_open = True
2021-05-14 08:45:20 -04:00
source_hash_text = self . ilb . get_selected_item ( ) . source_hash
2021-05-13 10:39:31 -04:00
display_name = self . ilb . get_selected_item ( ) . display_name
2021-05-14 16:12:42 -04:00
if display_name == None :
display_name = " "
2021-05-13 10:39:31 -04:00
2021-05-15 15:08:30 -04:00
e_id = urwid . Edit ( caption = " Addr : " , edit_text = source_hash_text )
t_id = urwid . Text ( " Addr : " + source_hash_text )
2021-05-13 10:39:31 -04:00
e_name = urwid . Edit ( caption = " Name : " , edit_text = display_name )
2021-05-14 08:45:20 -04:00
selected_id_widget = t_id
2021-10-03 12:44:00 -04:00
untrusted_selected = False
unknown_selected = True
trusted_selected = False
direct_selected = True
propagated_selected = False
2021-05-14 08:45:20 -04:00
try :
if self . app . directory . find ( bytes . fromhex ( source_hash_text ) ) :
trust_level = self . app . directory . trust_level ( bytes . fromhex ( source_hash_text ) )
if trust_level == DirectoryEntry . UNTRUSTED :
untrusted_selected = True
unknown_selected = False
trusted_selected = False
elif trust_level == DirectoryEntry . UNKNOWN :
untrusted_selected = False
unknown_selected = True
trusted_selected = False
elif trust_level == DirectoryEntry . TRUSTED :
untrusted_selected = False
unknown_selected = False
trusted_selected = True
2021-10-03 12:44:00 -04:00
if self . app . directory . preferred_delivery ( bytes . fromhex ( source_hash_text ) ) == DirectoryEntry . PROPAGATED :
direct_selected = False
propagated_selected = True
2021-05-14 08:45:20 -04:00
except Exception as e :
2021-05-14 11:36:35 -04:00
pass
2021-05-14 08:45:20 -04:00
2021-05-13 10:39:31 -04:00
trust_button_group = [ ]
2021-05-14 08:45:20 -04:00
r_untrusted = urwid . RadioButton ( trust_button_group , " Untrusted " , state = untrusted_selected )
r_unknown = urwid . RadioButton ( trust_button_group , " Unknown " , state = unknown_selected )
r_trusted = urwid . RadioButton ( trust_button_group , " Trusted " , state = trusted_selected )
2021-05-13 10:39:31 -04:00
2021-10-03 12:44:00 -04:00
method_button_group = [ ]
r_direct = urwid . RadioButton ( method_button_group , " Deliver directly " , state = direct_selected )
r_propagated = urwid . RadioButton ( method_button_group , " Use propagation nodes " , state = propagated_selected )
2021-05-13 10:39:31 -04:00
def dismiss_dialog ( sender ) :
self . update_conversation_list ( )
self . dialog_open = False
def confirmed ( sender ) :
try :
display_name = e_name . get_edit_text ( )
source_hash = bytes . fromhex ( e_id . get_edit_text ( ) )
trust_level = DirectoryEntry . UNTRUSTED
if r_unknown . state == True :
trust_level = DirectoryEntry . UNKNOWN
elif r_trusted . state == True :
trust_level = DirectoryEntry . TRUSTED
2021-10-03 12:44:00 -04:00
delivery = DirectoryEntry . DIRECT
if r_propagated . state == True :
delivery = DirectoryEntry . PROPAGATED
entry = DirectoryEntry ( source_hash , display_name , trust_level , preferred_delivery = delivery )
2021-05-13 10:39:31 -04:00
self . app . directory . remember ( entry )
self . update_conversation_list ( )
self . dialog_open = False
2021-05-15 15:08:30 -04:00
self . app . ui . main_display . sub_displays . network_display . directory_change_callback ( )
2021-05-13 10:39:31 -04:00
except Exception as e :
RNS . log ( " Could not save directory entry. The contained exception was: " + str ( e ) , RNS . LOG_VERBOSE )
if not dialog_pile . error_display :
dialog_pile . error_display = True
options = dialog_pile . options ( height_type = " pack " )
dialog_pile . contents . append ( ( urwid . Text ( " " ) , options ) )
dialog_pile . contents . append ( ( urwid . Text ( ( " error_text " , " Could not save entry. Check your input. " ) , align = " center " ) , options ) )
2021-05-14 16:12:42 -04:00
source_is_known = self . app . directory . is_known ( bytes . fromhex ( source_hash_text ) )
if source_is_known :
2021-07-02 07:35:10 -04:00
known_section = urwid . Divider ( g [ " divider1 " ] )
2021-05-14 16:12:42 -04:00
else :
def query_action ( sender , user_data ) :
2021-05-15 15:08:30 -04:00
self . close_conversation_by_hash ( user_data )
2021-05-14 16:12:42 -04:00
nomadnet . Conversation . query_for_peer ( user_data )
options = dialog_pile . options ( height_type = " pack " )
dialog_pile . contents = [
( urwid . Text ( " Query sent " ) , options ) ,
( urwid . Button ( " OK " , on_press = dismiss_dialog ) , options )
]
query_button = urwid . Button ( " Query network for keys " , on_press = query_action , user_data = source_hash_text )
2021-07-02 07:35:10 -04:00
known_section = urwid . Pile ( [ urwid . Divider ( g [ " divider1 " ] ) , urwid . Text ( g [ " info " ] + " \n " , align = " center " ) , urwid . Text ( " The identity of this peer is not known, and you cannot currently communicate. \n " , align = " center " ) , query_button , urwid . Divider ( g [ " divider1 " ] ) ] )
2021-05-14 16:12:42 -04:00
2021-05-13 10:39:31 -04:00
dialog_pile = urwid . Pile ( [
2021-05-14 08:45:20 -04:00
selected_id_widget ,
2021-05-13 10:39:31 -04:00
e_name ,
2021-07-02 07:35:10 -04:00
urwid . Divider ( g [ " divider1 " ] ) ,
2021-05-13 10:39:31 -04:00
r_untrusted ,
r_unknown ,
r_trusted ,
2021-10-03 12:44:00 -04:00
urwid . Divider ( g [ " divider1 " ] ) ,
r_direct ,
r_propagated ,
2021-05-14 16:12:42 -04:00
known_section ,
2021-05-14 11:36:35 -04:00
urwid . Columns ( [ ( " weight " , 0.45 , urwid . Button ( " Save " , on_press = confirmed ) ) , ( " weight " , 0.1 , urwid . Text ( " " ) ) , ( " weight " , 0.45 , urwid . Button ( " Back " , on_press = dismiss_dialog ) ) ] )
2021-05-13 10:39:31 -04:00
] )
dialog_pile . error_display = False
2021-05-15 15:08:30 -04:00
dialog = DialogLineBox ( dialog_pile , title = " Peer Info " )
2021-05-14 16:12:42 -04:00
dialog . delegate = self
2021-05-13 10:39:31 -04:00
bottom = self . listbox
overlay = urwid . Overlay ( dialog , bottom , align = " center " , width = ( " relative " , 100 ) , valign = " middle " , height = " pack " , left = 2 , right = 2 )
options = self . columns_widget . options ( " weight " , ConversationsDisplay . list_width )
self . columns_widget . contents [ 0 ] = ( overlay , options )
def new_conversation ( self ) :
2021-05-14 08:45:20 -04:00
self . dialog_open = True
source_hash = " "
display_name = " "
2021-05-15 15:08:30 -04:00
e_id = urwid . Edit ( caption = " Addr : " , edit_text = source_hash )
2021-05-14 08:45:20 -04:00
e_name = urwid . Edit ( caption = " Name : " , edit_text = display_name )
trust_button_group = [ ]
r_untrusted = urwid . RadioButton ( trust_button_group , " Untrusted " )
r_unknown = urwid . RadioButton ( trust_button_group , " Unknown " , state = True )
r_trusted = urwid . RadioButton ( trust_button_group , " Trusted " )
def dismiss_dialog ( sender ) :
self . update_conversation_list ( )
self . dialog_open = False
def confirmed ( sender ) :
try :
existing_conversations = nomadnet . Conversation . conversation_list ( self . app )
display_name = e_name . get_edit_text ( )
source_hash_text = e_id . get_edit_text ( )
source_hash = bytes . fromhex ( source_hash_text )
trust_level = DirectoryEntry . UNTRUSTED
if r_unknown . state == True :
trust_level = DirectoryEntry . UNKNOWN
elif r_trusted . state == True :
trust_level = DirectoryEntry . TRUSTED
if not source_hash in [ c [ 0 ] for c in existing_conversations ] :
entry = DirectoryEntry ( source_hash , display_name , trust_level )
self . app . directory . remember ( entry )
new_conversation = nomadnet . Conversation ( source_hash_text , nomadnet . NomadNetworkApp . get_shared_instance ( ) , initiator = True )
self . update_conversation_list ( )
self . display_conversation ( source_hash_text )
self . dialog_open = False
except Exception as e :
RNS . log ( " Could not start conversation. The contained exception was: " + str ( e ) , RNS . LOG_VERBOSE )
if not dialog_pile . error_display :
dialog_pile . error_display = True
options = dialog_pile . options ( height_type = " pack " )
dialog_pile . contents . append ( ( urwid . Text ( " " ) , options ) )
dialog_pile . contents . append ( ( urwid . Text ( ( " error_text " , " Could not start conversation. Check your input. " ) , align = " center " ) , options ) )
dialog_pile = urwid . Pile ( [
e_id ,
e_name ,
urwid . Text ( " " ) ,
r_untrusted ,
r_unknown ,
r_trusted ,
urwid . Text ( " " ) ,
2021-05-15 15:08:30 -04:00
urwid . Columns ( [ ( " weight " , 0.45 , urwid . Button ( " Create " , on_press = confirmed ) ) , ( " weight " , 0.1 , urwid . Text ( " " ) ) , ( " weight " , 0.45 , urwid . Button ( " Back " , on_press = dismiss_dialog ) ) ] )
2021-05-14 08:45:20 -04:00
] )
dialog_pile . error_display = False
2021-05-14 16:12:42 -04:00
dialog = DialogLineBox ( dialog_pile , title = " New Conversation " )
dialog . delegate = self
2021-05-14 08:45:20 -04:00
bottom = self . listbox
overlay = urwid . Overlay ( dialog , bottom , align = " center " , width = ( " relative " , 100 ) , valign = " middle " , height = " pack " , left = 2 , right = 2 )
options = self . columns_widget . options ( " weight " , ConversationsDisplay . list_width )
self . columns_widget . contents [ 0 ] = ( overlay , options )
2021-05-13 10:39:31 -04:00
def delete_conversation ( self , source_hash ) :
if source_hash in ConversationsDisplay . cached_conversation_widgets :
conversation = ConversationsDisplay . cached_conversation_widgets [ source_hash ]
self . close_conversation ( conversation )
def conversation_list_selection ( self , arg1 , arg2 ) :
pass
def update_conversation_list ( self ) :
ilb_position = self . ilb . get_selected_position ( )
self . update_listbox ( )
options = self . columns_widget . options ( " weight " , ConversationsDisplay . list_width )
self . columns_widget . contents [ 0 ] = ( self . listbox , options )
2021-05-13 14:25:04 -04:00
if ilb_position != None :
self . ilb . select_item ( ilb_position )
2021-05-13 10:39:31 -04:00
nomadnet . NomadNetworkApp . get_shared_instance ( ) . ui . loop . draw_screen ( )
2021-09-23 11:20:13 -04:00
if self . app . ui . main_display . sub_displays . active_display == self . app . ui . main_display . sub_displays . conversations_display :
if self . currently_displayed_conversation != None :
if self . app . conversation_is_unread ( self . currently_displayed_conversation ) :
self . app . mark_conversation_read ( self . currently_displayed_conversation )
try :
if os . path . isfile ( self . app . conversationpath + " / " + self . currently_displayed_conversation + " /unread " ) :
os . unlink ( self . app . conversationpath + " / " + self . currently_displayed_conversation + " /unread " )
except Exception as e :
raise e
2021-09-05 14:38:10 -04:00
2021-05-13 10:39:31 -04:00
2021-05-04 05:08:16 -04:00
2021-05-04 14:53:03 -04:00
def display_conversation ( self , sender = None , source_hash = None ) :
2021-09-05 14:38:10 -04:00
if self . currently_displayed_conversation != None :
if self . app . conversation_is_unread ( self . currently_displayed_conversation ) :
self . app . mark_conversation_read ( self . currently_displayed_conversation )
2021-05-13 10:39:31 -04:00
self . currently_displayed_conversation = source_hash
2021-05-04 14:53:03 -04:00
options = self . widget . options ( " weight " , 1 - ConversationsDisplay . list_width )
self . widget . contents [ 1 ] = ( self . make_conversation_widget ( source_hash ) , options )
2021-06-30 08:49:26 -04:00
if source_hash == None :
self . widget . set_focus_column ( 0 )
else :
2021-09-05 14:38:10 -04:00
if self . app . conversation_is_unread ( source_hash ) :
self . app . mark_conversation_read ( source_hash )
self . update_conversation_list ( )
2021-06-30 08:49:26 -04:00
self . widget . set_focus_column ( 1 )
2021-09-05 14:38:10 -04:00
conversation_position = None
index = 0
for widget in self . list_widgets :
if widget . source_hash == source_hash :
conversation_position = index
index + = 1
if conversation_position != None :
self . ilb . select_item ( conversation_position )
2021-05-04 14:53:03 -04:00
def make_conversation_widget ( self , source_hash ) :
2021-05-13 10:39:31 -04:00
if source_hash in ConversationsDisplay . cached_conversation_widgets :
conversation_widget = ConversationsDisplay . cached_conversation_widgets [ source_hash ]
if source_hash != None :
conversation_widget . update_message_widgets ( replace = True )
2021-05-14 16:12:42 -04:00
conversation_widget . check_editor_allowed ( )
2021-05-13 10:39:31 -04:00
return conversation_widget
else :
widget = ConversationWidget ( source_hash )
widget . delegate = self
ConversationsDisplay . cached_conversation_widgets [ source_hash ] = widget
2021-05-14 16:12:42 -04:00
widget . check_editor_allowed ( )
2021-05-13 10:39:31 -04:00
return widget
2021-05-15 15:08:30 -04:00
def close_conversation_by_hash ( self , conversation_hash ) :
if conversation_hash in ConversationsDisplay . cached_conversation_widgets :
ConversationsDisplay . cached_conversation_widgets . pop ( conversation_hash )
if self . currently_displayed_conversation == conversation_hash :
self . display_conversation ( sender = None , source_hash = None )
2021-05-13 10:39:31 -04:00
def close_conversation ( self , conversation ) :
2021-05-15 15:08:30 -04:00
if conversation . source_hash in ConversationsDisplay . cached_conversation_widgets :
ConversationsDisplay . cached_conversation_widgets . pop ( conversation . source_hash )
if self . currently_displayed_conversation == conversation . source_hash :
self . display_conversation ( sender = None , source_hash = None )
2021-05-13 10:39:31 -04:00
def conversation_list_widget ( self , conversation ) :
trust_level = conversation [ 2 ]
display_name = conversation [ 1 ]
source_hash = conversation [ 0 ]
2021-09-05 14:38:10 -04:00
unread = conversation [ 4 ]
2021-05-13 10:39:31 -04:00
2021-07-02 07:35:10 -04:00
g = self . app . ui . glyphs
2021-05-13 10:39:31 -04:00
if trust_level == DirectoryEntry . UNTRUSTED :
2021-07-02 07:35:10 -04:00
symbol = g [ " cross " ]
2021-05-14 08:45:20 -04:00
style = " list_untrusted "
focus_style = " list_focus_untrusted "
2021-05-13 10:39:31 -04:00
elif trust_level == DirectoryEntry . UNKNOWN :
2021-05-14 08:45:20 -04:00
symbol = " ? "
style = " list_unknown "
focus_style = " list_focus "
2021-05-13 10:39:31 -04:00
elif trust_level == DirectoryEntry . TRUSTED :
2021-07-02 07:35:10 -04:00
symbol = g [ " check " ]
2021-05-14 08:45:20 -04:00
style = " list_trusted "
focus_style = " list_focus_trusted "
2021-05-13 10:39:31 -04:00
elif trust_level == DirectoryEntry . WARNING :
2021-07-02 07:35:10 -04:00
symbol = g [ " warning " ]
2021-05-14 08:45:20 -04:00
style = " list_warning "
focus_style = " list_focus "
2021-05-13 10:39:31 -04:00
else :
2021-07-02 07:35:10 -04:00
symbol = g [ " warning " ]
2021-05-14 08:45:20 -04:00
style = " list_untrusted "
focus_style = " list_focus_untrusted "
2021-05-13 10:39:31 -04:00
display_text = symbol
2021-09-05 14:38:10 -04:00
2021-05-14 16:12:42 -04:00
if display_name != None and display_name != " " :
2021-05-13 10:39:31 -04:00
display_text + = " " + display_name
if trust_level != DirectoryEntry . TRUSTED :
display_text + = " < " + source_hash + " > "
2021-09-25 10:57:29 -04:00
if trust_level != DirectoryEntry . UNTRUSTED :
2021-09-05 14:38:10 -04:00
if unread :
if source_hash != self . currently_displayed_conversation :
display_text + = " " + g [ " unread " ]
2021-05-13 10:39:31 -04:00
widget = ListEntry ( display_text )
urwid . connect_signal ( widget , " click " , self . display_conversation , conversation [ 0 ] )
2021-05-14 08:45:20 -04:00
display_widget = urwid . AttrMap ( widget , style , focus_style )
2021-05-13 10:39:31 -04:00
display_widget . source_hash = source_hash
display_widget . display_name = display_name
return display_widget
def shortcuts ( self ) :
focus_path = self . widget . get_focus_path ( )
if focus_path [ 0 ] == 0 :
return self . list_shortcuts
elif focus_path [ 0 ] == 1 :
return self . editor_shortcuts
else :
return self . list_shortcuts
class ListEntry ( urwid . Text ) :
_selectable = True
signals = [ " click " ]
def keypress ( self , size , key ) :
"""
Send ' click ' signal on ' activate ' command .
"""
if self . _command_map [ key ] != urwid . ACTIVATE :
return key
self . _emit ( ' click ' )
def mouse_event ( self , size , event , button , x , y , focus ) :
"""
Send ' click ' signal on button 1 press .
"""
if button != 1 or not urwid . util . is_mouse_press ( event ) :
return False
self . _emit ( ' click ' )
return True
2021-05-04 14:53:03 -04:00
2021-05-13 10:39:31 -04:00
class MessageEdit ( urwid . Edit ) :
def keypress ( self , size , key ) :
if key == " ctrl d " :
self . delegate . send_message ( )
elif key == " ctrl k " :
self . delegate . clear_editor ( )
2021-05-14 11:36:35 -04:00
elif key == " up " :
y = self . get_cursor_coords ( size ) [ 1 ]
if y == 0 :
if self . delegate . full_editor_active and self . name == " title_editor " :
self . delegate . frame . set_focus ( " body " )
elif not self . delegate . full_editor_active and self . name == " content_editor " :
self . delegate . frame . set_focus ( " body " )
else :
return super ( MessageEdit , self ) . keypress ( size , key )
else :
return super ( MessageEdit , self ) . keypress ( size , key )
2021-05-13 10:39:31 -04:00
else :
return super ( MessageEdit , self ) . keypress ( size , key )
2021-05-14 11:36:35 -04:00
class ConversationFrame ( urwid . Frame ) :
def keypress ( self , size , key ) :
if self . get_focus ( ) == " body " :
if key == " up " and self . delegate . messagelist . top_is_visible :
nomadnet . NomadNetworkApp . get_shared_instance ( ) . ui . main_display . frame . set_focus ( " header " )
elif key == " down " and self . delegate . messagelist . bottom_is_visible :
self . set_focus ( " footer " )
else :
return super ( ConversationFrame , self ) . keypress ( size , key )
elif key == " ctrl k " :
self . delegate . clear_editor ( )
else :
return super ( ConversationFrame , self ) . keypress ( size , key )
2021-05-13 10:39:31 -04:00
class ConversationWidget ( urwid . WidgetWrap ) :
def __init__ ( self , source_hash ) :
2021-07-02 07:35:10 -04:00
self . app = nomadnet . NomadNetworkApp . get_shared_instance ( )
g = self . app . ui . glyphs
2021-05-04 14:53:03 -04:00
if source_hash == None :
2021-05-14 16:12:42 -04:00
self . frame = None
2021-05-15 15:08:30 -04:00
display_widget = urwid . LineBox ( urwid . Filler ( urwid . Text ( " \n No conversation selected " ) , " top " ) )
2021-05-13 10:39:31 -04:00
urwid . WidgetWrap . __init__ ( self , display_widget )
2021-05-04 14:53:03 -04:00
else :
if source_hash in ConversationsDisplay . cached_conversation_widgets :
return ConversationsDisplay . cached_conversation_widgets [ source_hash ]
else :
2021-05-13 10:39:31 -04:00
self . source_hash = source_hash
self . conversation = nomadnet . Conversation ( source_hash , nomadnet . NomadNetworkApp . get_shared_instance ( ) )
self . message_widgets = [ ]
self . updating_message_widgets = False
2021-05-04 14:53:03 -04:00
2021-05-13 10:39:31 -04:00
self . update_message_widgets ( )
2021-05-04 14:53:03 -04:00
2021-05-13 10:39:31 -04:00
self . conversation . register_changed_callback ( self . conversation_changed )
2021-05-04 14:53:03 -04:00
2021-05-14 09:13:17 -04:00
#title_editor = MessageEdit(caption="\u270E", edit_text="", multiline=False)
title_editor = MessageEdit ( caption = " " , edit_text = " " , multiline = False )
title_editor . delegate = self
2021-05-14 11:36:35 -04:00
title_editor . name = " title_editor "
2021-05-14 09:13:17 -04:00
#msg_editor = MessageEdit(caption="\u270E", edit_text="", multiline=True)
msg_editor = MessageEdit ( caption = " " , edit_text = " " , multiline = True )
2021-05-13 10:39:31 -04:00
msg_editor . delegate = self
2021-05-14 11:36:35 -04:00
msg_editor . name = " content_editor "
2021-05-12 08:02:44 -04:00
2021-05-13 10:39:31 -04:00
header = None
if self . conversation . trust_level == DirectoryEntry . UNTRUSTED :
2021-07-02 07:35:10 -04:00
header = urwid . AttrMap ( urwid . Padding ( urwid . Text ( g [ " warning " ] + " Warning: Conversation with untrusted peer " + g [ " warning " ] , align = " center " ) ) , " msg_warning_untrusted " )
2021-05-13 10:39:31 -04:00
2021-05-14 09:13:17 -04:00
self . minimal_editor = urwid . AttrMap ( msg_editor , " msg_editor " )
2021-05-14 11:36:35 -04:00
self . minimal_editor . name = " minimal_editor "
2021-05-14 09:13:17 -04:00
title_columns = urwid . Columns ( [
( 8 , urwid . Text ( " Title " ) ) ,
urwid . AttrMap ( title_editor , " msg_editor " ) ,
] )
content_columns = urwid . Columns ( [
( 8 , urwid . Text ( " Content " ) ) ,
urwid . AttrMap ( msg_editor , " msg_editor " )
] )
self . full_editor = urwid . Pile ( [
title_columns ,
content_columns
] )
2021-05-14 11:36:35 -04:00
self . full_editor . name = " full_editor "
2021-05-14 09:13:17 -04:00
self . content_editor = msg_editor
self . title_editor = title_editor
self . full_editor_active = False
2021-05-04 14:53:03 -04:00
2021-05-14 11:36:35 -04:00
self . frame = ConversationFrame (
2021-05-13 10:39:31 -04:00
self . messagelist ,
header = header ,
2021-05-15 15:08:30 -04:00
footer = self . minimal_editor ,
focus_part = " footer "
2021-05-13 10:39:31 -04:00
)
2021-05-14 11:36:35 -04:00
self . frame . delegate = self
2021-05-12 08:02:44 -04:00
2021-05-13 10:39:31 -04:00
self . display_widget = urwid . LineBox (
self . frame
)
2021-05-12 08:02:44 -04:00
2021-05-13 10:39:31 -04:00
urwid . WidgetWrap . __init__ ( self , self . display_widget )
2021-09-11 05:33:20 -04:00
def clear_history_dialog ( self ) :
def dismiss_dialog ( sender ) :
self . dialog_open = False
self . conversation_changed ( None )
def confirmed ( sender ) :
self . dialog_open = False
self . conversation . clear_history ( )
self . conversation_changed ( None )
dialog = DialogLineBox (
urwid . Pile ( [
urwid . Text ( " Clear conversation history \n " , align = " center " ) ,
urwid . Columns ( [ ( " weight " , 0.45 , urwid . Button ( " Yes " , on_press = confirmed ) ) , ( " weight " , 0.1 , urwid . Text ( " " ) ) , ( " weight " , 0.45 , urwid . Button ( " No " , on_press = dismiss_dialog ) ) ] )
] ) , title = " ? "
)
dialog . delegate = self
bottom = self . messagelist
overlay = urwid . Overlay ( dialog , bottom , align = " center " , width = 34 , valign = " middle " , height = " pack " , left = 2 , right = 2 )
self . frame . contents [ " body " ] = ( overlay , self . frame . options ( ) )
self . frame . set_focus ( " body " )
2021-05-14 09:13:17 -04:00
def toggle_editor ( self ) :
if self . full_editor_active :
self . frame . contents [ " footer " ] = ( self . minimal_editor , None )
self . full_editor_active = False
else :
self . frame . contents [ " footer " ] = ( self . full_editor , None )
self . full_editor_active = True
2021-05-14 16:12:42 -04:00
def check_editor_allowed ( self ) :
2021-07-02 07:35:10 -04:00
g = self . app . ui . glyphs
2021-05-14 16:12:42 -04:00
if self . frame :
allowed = nomadnet . NomadNetworkApp . get_shared_instance ( ) . directory . is_known ( bytes . fromhex ( self . source_hash ) )
if allowed :
self . frame . contents [ " footer " ] = ( self . minimal_editor , None )
else :
2021-09-02 12:45:17 -04:00
warning = urwid . AttrMap ( urwid . Padding ( urwid . Text ( g [ " info " ] + " You cannot currently communicate with this peer, since it ' s identity keys are not known " , align = " center " ) ) , " msg_header_caution " )
2021-05-14 16:12:42 -04:00
self . frame . contents [ " footer " ] = ( warning , None )
2021-05-14 11:36:35 -04:00
def toggle_focus_area ( self ) :
name = " "
try :
name = self . frame . get_focus_widgets ( ) [ 0 ] . name
except Exception as e :
pass
if name == " messagelist " :
self . frame . set_focus ( " footer " )
elif name == " minimal_editor " or name == " full_editor " :
self . frame . set_focus ( " body " )
2021-05-14 08:45:20 -04:00
def keypress ( self , size , key ) :
2021-05-14 11:36:35 -04:00
if key == " tab " :
self . toggle_focus_area ( )
elif key == " ctrl w " :
2021-05-14 08:45:20 -04:00
self . close ( )
elif key == " ctrl p " :
self . conversation . purge_failed ( )
self . conversation_changed ( None )
2021-05-14 09:13:17 -04:00
elif key == " ctrl t " :
self . toggle_editor ( )
2021-09-11 05:33:20 -04:00
elif key == " ctrl x " :
self . clear_history_dialog ( )
2021-05-14 08:45:20 -04:00
else :
return super ( ConversationWidget , self ) . keypress ( size , key )
2021-05-13 10:39:31 -04:00
def conversation_changed ( self , conversation ) :
self . update_message_widgets ( replace = True )
def update_message_widgets ( self , replace = False ) :
while self . updating_message_widgets :
time . sleep ( 0.5 )
self . updating_message_widgets = True
self . message_widgets = [ ]
added_hashes = [ ]
for message in self . conversation . messages :
message_hash = message . get_hash ( )
if not message_hash in added_hashes :
added_hashes . append ( message_hash )
message_widget = LXMessageWidget ( message )
self . message_widgets . append ( message_widget )
2021-09-23 11:45:01 -04:00
self . message_widgets . sort ( key = lambda m : m . sort_timestamp , reverse = False )
2021-05-04 14:53:03 -04:00
2021-05-13 10:39:31 -04:00
from nomadnet . vendor . additional_urwid_widgets import IndicativeListBox
self . messagelist = IndicativeListBox ( self . message_widgets , position = len ( self . message_widgets ) - 1 )
2021-05-14 11:36:35 -04:00
self . messagelist . name = " messagelist "
2021-05-13 10:39:31 -04:00
if replace :
self . frame . contents [ " body " ] = ( self . messagelist , None )
nomadnet . NomadNetworkApp . get_shared_instance ( ) . ui . loop . draw_screen ( )
2021-05-04 14:53:03 -04:00
2021-05-13 10:39:31 -04:00
self . updating_message_widgets = False
2021-05-04 14:53:03 -04:00
2021-05-13 10:39:31 -04:00
def clear_editor ( self ) :
2021-05-14 09:13:17 -04:00
self . content_editor . set_edit_text ( " " )
self . title_editor . set_edit_text ( " " )
2021-05-13 10:39:31 -04:00
def send_message ( self ) :
2021-05-14 09:13:17 -04:00
content = self . content_editor . get_edit_text ( )
title = self . title_editor . get_edit_text ( )
2021-05-13 10:39:31 -04:00
if not content == " " :
2021-05-14 16:12:42 -04:00
if self . conversation . send ( content , title ) :
self . clear_editor ( )
else :
pass
2021-05-13 10:39:31 -04:00
def close ( self ) :
self . delegate . close_conversation ( self )
class LXMessageWidget ( urwid . WidgetWrap ) :
def __init__ ( self , message ) :
app = nomadnet . NomadNetworkApp . get_shared_instance ( )
2021-07-02 07:35:10 -04:00
g = app . ui . glyphs
2021-05-13 10:39:31 -04:00
self . timestamp = message . get_timestamp ( )
2021-09-23 11:45:01 -04:00
self . sort_timestamp = message . sort_timestamp
2021-05-13 10:39:31 -04:00
time_format = app . time_format
message_time = datetime . fromtimestamp ( self . timestamp )
2021-05-14 13:38:21 -04:00
encryption_string = " "
if message . get_transport_encrypted ( ) :
2021-09-16 13:54:32 -04:00
encryption_string = " [ " + g [ " encrypted " ] + " " + str ( message . get_transport_encryption ( ) ) + " ] "
2021-05-14 13:38:21 -04:00
else :
2021-09-16 13:54:32 -04:00
encryption_string = " [ " + g [ " plaintext " ] + " " + str ( message . get_transport_encryption ( ) ) + " ] "
2021-05-14 13:38:21 -04:00
title_string = message_time . strftime ( time_format ) + encryption_string
2021-05-13 10:39:31 -04:00
if app . lxmf_destination . hash == message . lxm . source_hash :
if message . lxm . state == LXMF . LXMessage . DELIVERED :
header_style = " msg_header_delivered "
2021-07-02 07:35:10 -04:00
title_string = g [ " check " ] + " " + title_string
2021-05-14 08:45:20 -04:00
elif message . lxm . state == LXMF . LXMessage . FAILED :
header_style = " msg_header_failed "
2021-07-02 07:35:10 -04:00
title_string = g [ " cross " ] + " " + title_string
2021-10-03 12:44:00 -04:00
elif message . lxm . state == LXMF . LXMessage . SENT :
header_style = " msg_header_sent "
title_string = g [ " sent " ] + " " + title_string
2021-05-13 10:39:31 -04:00
else :
header_style = " msg_header_sent "
2021-07-02 07:35:10 -04:00
title_string = g [ " arrow_r " ] + " " + title_string
2021-05-12 08:02:44 -04:00
else :
2021-05-13 10:39:31 -04:00
if message . signature_validated ( ) :
header_style = " msg_header_ok "
2021-07-02 07:35:10 -04:00
title_string = g [ " check " ] + " " + title_string
2021-05-13 10:39:31 -04:00
else :
header_style = " msg_header_caution "
2021-07-02 07:35:10 -04:00
title_string = g [ " warning " ] + " " + message . get_signature_description ( ) + " \n " + title_string
2021-05-13 10:39:31 -04:00
if message . get_title ( ) != " " :
title_string + = " | " + message . get_title ( )
title = urwid . AttrMap ( urwid . Text ( title_string ) , header_style )
display_widget = urwid . Pile ( [
title ,
urwid . Text ( message . get_content ( ) ) ,
urwid . Text ( " " )
] )
urwid . WidgetWrap . __init__ ( self , display_widget )