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-10-07 12:14:06 -04:00
self . widget = urwid . AttrMap ( urwid . Text ( " [Enter] Open [C-e] Peer Info [C-x] Delete [C-r] Sync [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-10-12 14:46:05 -04:00
self . widget = urwid . AttrMap ( urwid . Text ( " [C-d] Send [C-k] Clear [C-w] Close [C-t] Title [C-p] Purge [C-x] Clear History [C-o] Sort " ) , " 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-10-07 12:14:06 -04:00
elif key == " ctrl r " :
self . delegate . sync_conversations ( )
2022-07-04 11:34:12 -04:00
elif key == " ctrl g " :
self . delegate . toggle_fullscreen ( )
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
2022-07-04 11:07:54 -04:00
given_list_width = 52
2021-05-04 14:53:03 -04:00
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-10-07 12:14:06 -04:00
self . sync_dialog = None
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 (
[
2022-07-04 11:07:54 -04:00
# ("weight", ConversationsDisplay.list_width, self.listbox),
# ("weight", 1-ConversationsDisplay.list_width, self.make_conversation_widget(None))
( ConversationsDisplay . given_list_width , self . listbox ) ,
( " weight " , 1 , self . make_conversation_widget ( None ) )
2021-05-15 15:08:30 -04:00
] ,
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 "
)
2021-11-04 16:51:11 -04:00
self . listbox = ConversationsArea ( urwid . Filler ( self . ilb , height = ( " relative " , 100 ) ) , title = " Conversations " )
2021-05-13 10:39:31 -04:00
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 )
2022-07-04 11:07:54 -04:00
# options = self.columns_widget.options("weight", ConversationsDisplay.list_width)
options = self . columns_widget . options ( " given " , ConversationsDisplay . given_list_width )
2021-05-13 10:39:31 -04:00
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 )
2022-07-04 10:48:40 -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 send messages to it. You can query the network to obtain the identity. \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 )
2022-07-04 11:07:54 -04:00
# options = self.columns_widget.options("weight", ConversationsDisplay.list_width)
options = self . columns_widget . options ( " given " , ConversationsDisplay . given_list_width )
2021-05-13 10:39:31 -04:00
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 )
2022-07-04 11:07:54 -04:00
# options = self.columns_widget.options("weight", ConversationsDisplay.list_width)
options = self . columns_widget . options ( " given " , ConversationsDisplay . given_list_width )
2021-05-14 08:45:20 -04:00
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 )
2022-07-04 11:34:12 -04:00
def toggle_fullscreen ( self ) :
if ConversationsDisplay . given_list_width != 0 :
self . saved_list_width = ConversationsDisplay . given_list_width
ConversationsDisplay . given_list_width = 0
else :
ConversationsDisplay . given_list_width = self . saved_list_width
self . update_conversation_list ( )
2021-10-07 12:14:06 -04:00
def sync_conversations ( self ) :
2021-10-08 05:58:24 -04:00
g = self . app . ui . glyphs
2021-10-07 12:14:06 -04:00
self . dialog_open = True
def dismiss_dialog ( sender ) :
self . dialog_open = False
self . sync_dialog = None
self . update_conversation_list ( )
2022-06-17 07:43:38 -04:00
if self . app . message_router . propagation_transfer_state > = LXMF . LXMRouter . PR_COMPLETE :
2021-10-07 12:14:06 -04:00
self . app . cancel_lxmf_sync ( )
2021-10-08 05:58:24 -04:00
max_messages_group = [ ]
r_mall = urwid . RadioButton ( max_messages_group , " Download all " , state = True )
r_mlim = urwid . RadioButton ( max_messages_group , " Limit to " , state = False )
ie_lim = urwid . IntEdit ( " " , 5 )
rbs = urwid . GridFlow ( [ r_mlim , ie_lim ] , 12 , 1 , 0 , align = " left " )
2021-10-07 12:14:06 -04:00
def sync_now ( sender ) :
2021-10-08 05:58:24 -04:00
limit = None
if r_mlim . get_state ( ) :
limit = ie_lim . value ( )
self . app . request_lxmf_sync ( limit )
2021-10-07 12:14:06 -04:00
self . update_sync_dialog ( )
def cancel_sync ( sender ) :
self . app . cancel_lxmf_sync ( )
2021-10-12 15:12:32 -04:00
self . update_sync_dialog ( )
2021-10-07 12:14:06 -04:00
cancel_button = urwid . Button ( " Close " , on_press = dismiss_dialog )
sync_progress = SyncProgressBar ( " progress_empty " , " progress_full " , current = self . app . get_sync_progress ( ) , done = 1.0 , satt = None )
real_sync_button = urwid . Button ( " Sync Now " , on_press = sync_now )
hidden_sync_button = urwid . Button ( " Cancel Sync " , on_press = cancel_sync )
2022-06-17 07:43:38 -04:00
if self . app . get_sync_status ( ) == " Idle " or self . app . message_router . propagation_transfer_state > = LXMF . LXMRouter . PR_COMPLETE :
2021-10-07 12:14:06 -04:00
sync_button = real_sync_button
else :
sync_button = hidden_sync_button
button_columns = urwid . Columns ( [ ( " weight " , 0.45 , sync_button ) , ( " weight " , 0.1 , urwid . Text ( " " ) ) , ( " weight " , 0.45 , cancel_button ) ] )
real_sync_button . bc = button_columns
2021-10-08 07:34:04 -04:00
pn_ident = None
2021-10-08 03:12:20 -04:00
if self . app . get_default_propagation_node ( ) != None :
2021-10-08 05:58:24 -04:00
pn_hash = self . app . get_default_propagation_node ( )
pn_ident = RNS . Identity . recall ( pn_hash )
2021-10-08 07:34:04 -04:00
if pn_ident == None :
RNS . log ( " Propagation node identity is unknown, requesting from network... " , RNS . LOG_DEBUG )
RNS . Transport . request_path ( pn_hash )
if pn_ident != None :
2021-10-08 05:58:24 -04:00
node_hash = RNS . Destination . hash_from_name_and_identity ( " nomadnetwork.node " , pn_ident )
pn_entry = self . app . directory . find ( node_hash )
2021-10-08 03:12:20 -04:00
dialog = DialogLineBox (
urwid . Pile ( [
2021-10-08 05:58:24 -04:00
urwid . Text ( " " + g [ " node " ] + " " + str ( pn_entry . display_name ) , align = " center " ) ,
urwid . Divider ( g [ " divider1 " ] ) ,
2021-10-08 03:12:20 -04:00
sync_progress ,
2021-10-08 05:58:24 -04:00
urwid . Divider ( g [ " divider1 " ] ) ,
r_mall ,
rbs ,
2021-10-08 03:12:20 -04:00
urwid . Text ( " " ) ,
button_columns
] ) , title = " Message Sync "
)
else :
button_columns = urwid . Columns ( [ ( " weight " , 0.45 , urwid . Text ( " " ) ) , ( " weight " , 0.1 , urwid . Text ( " " ) ) , ( " weight " , 0.45 , cancel_button ) ] )
dialog = DialogLineBox (
urwid . Pile ( [
urwid . Text ( " " ) ,
2022-07-04 10:38:43 -04:00
urwid . Text ( " No trusted nodes found, cannot sync! \n " , align = " center " ) ,
urwid . Text ( " To syncronise messages from the network, one or more nodes must be marked as trusted in the Known Nodes list. Nomad Network will then automatically sync from the nearest trusted node. " , align = " left " ) ,
2021-10-08 03:12:20 -04:00
urwid . Text ( " " ) ,
button_columns
] ) , title = " Message Sync "
)
2021-10-07 12:14:06 -04:00
dialog . delegate = self
dialog . sync_progress = sync_progress
dialog . cancel_button = cancel_button
dialog . real_sync_button = real_sync_button
dialog . hidden_sync_button = hidden_sync_button
dialog . bc = button_columns
self . sync_dialog = dialog
bottom = self . listbox
overlay = urwid . Overlay ( dialog , bottom , align = " center " , width = ( " relative " , 100 ) , valign = " middle " , height = " pack " , left = 2 , right = 2 )
2022-07-04 11:07:54 -04:00
# options = self.columns_widget.options("weight", ConversationsDisplay.list_width)
options = self . columns_widget . options ( " given " , ConversationsDisplay . given_list_width )
2021-10-07 12:14:06 -04:00
self . columns_widget . contents [ 0 ] = ( overlay , options )
def update_sync_dialog ( self , loop = None , sender = None ) :
if self . dialog_open and self . sync_dialog != None :
self . sync_dialog . sync_progress . set_completion ( self . app . get_sync_progress ( ) )
2022-06-17 07:43:38 -04:00
if self . app . get_sync_status ( ) == " Idle " or self . app . message_router . propagation_transfer_state > = LXMF . LXMRouter . PR_COMPLETE :
2021-10-07 12:14:06 -04:00
self . sync_dialog . bc . contents [ 0 ] = ( self . sync_dialog . real_sync_button , self . sync_dialog . bc . options ( " weight " , 0.45 ) )
else :
self . sync_dialog . bc . contents [ 0 ] = ( self . sync_dialog . hidden_sync_button , self . sync_dialog . bc . options ( " weight " , 0.45 ) )
self . app . ui . loop . set_alarm_in ( 0.2 , self . update_sync_dialog )
2021-05-13 10:39:31 -04:00
def conversation_list_selection ( self , arg1 , arg2 ) :
pass
def update_conversation_list ( self ) :
ilb_position = self . ilb . get_selected_position ( )
self . update_listbox ( )
2022-07-04 11:07:54 -04:00
# options = self.columns_widget.options("weight", ConversationsDisplay.list_width)
options = self . columns_widget . options ( " given " , ConversationsDisplay . given_list_width )
2021-10-07 12:14:06 -04:00
if not ( self . dialog_open and self . sync_dialog != None ) :
self . columns_widget . contents [ 0 ] = ( self . listbox , options )
else :
bottom = self . listbox
overlay = urwid . Overlay ( self . sync_dialog , bottom , align = " center " , width = ( " relative " , 100 ) , valign = " middle " , height = " pack " , left = 2 , right = 2 )
self . columns_widget . contents [ 0 ] = ( overlay , 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
2022-07-04 11:07:54 -04:00
# options = self.widget.options("weight", 1-ConversationsDisplay.list_width)
options = self . widget . options ( " weight " , 1 )
2021-05-04 14:53:03 -04:00
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 = [ ]
2021-10-08 08:46:20 -04:00
self . sort_by_timestamp = False
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
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 :
2022-07-04 10:48:40 -04:00
warning = urwid . AttrMap ( urwid . Padding ( urwid . Text ( " \n " + g [ " info " ] + " \n \n You cannot currently message this peer, since it ' s identity keys are not known. \n \n Wait for an announce to arrive from the peer, or query the network for it. \n \n To query the network, select this conversation in the conversation list, press Ctrl-E, and use the query button. \n " , 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 ( )
2022-07-04 11:34:12 -04:00
elif key == " ctrl g " :
nomadnet . NomadNetworkApp . get_shared_instance ( ) . ui . main_display . sub_displays . conversations_display . toggle_fullscreen ( )
2021-10-08 08:46:20 -04:00
elif key == " ctrl o " :
self . sort_by_timestamp ^ = True
self . conversation_changed ( None )
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-10-08 08:46:20 -04:00
if self . sort_by_timestamp :
self . message_widgets . sort ( key = lambda m : m . timestamp , reverse = False )
else :
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-07 15:04:11 -04:00
elif message . lxm . method == LXMF . LXMessage . PROPAGATED and message . lxm . state == LXMF . LXMessage . SENT :
header_style = " msg_header_propagated "
title_string = g [ " sent " ] + " " + 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 ( " " )
] )
2021-10-07 12:14:06 -04:00
urwid . WidgetWrap . __init__ ( self , display_widget )
class SyncProgressBar ( urwid . ProgressBar ) :
def get_text ( self ) :
status = nomadnet . NomadNetworkApp . get_shared_instance ( ) . get_sync_status ( )
show_percent = nomadnet . NomadNetworkApp . get_shared_instance ( ) . sync_status_show_percent ( )
if show_percent :
return status + " " + super ( ) . get_text ( )
else :
return status