working changes

This commit is contained in:
Ben Lipsey
2025-04-13 14:58:31 -07:00
parent f7b2645dcb
commit 613eeb4fab
5 changed files with 127 additions and 126 deletions
+123 -124
View File
@@ -15,8 +15,7 @@ from contact.utilities.control_utils import parse_ini_file, transform_menu_path
from contact.ui.user_config import json_editor
from contact.ui.ui_state import MenuState
state = MenuState()
menu_state = MenuState()
# Constants
width = 80
@@ -42,10 +41,10 @@ field_mapping, help_text = parse_ini_file(translation_file)
Segment = tuple[str, str, bool, bool]
WrappedLine = list[Segment]
def display_menu(state: MenuState) -> tuple[object, object]: # curses.window or pad types
def display_menu(menu_state: MenuState) -> tuple[object, object]: # curses.window or pad types
min_help_window_height = 6
num_items = len(state.current_menu) + (1 if state.show_save_option else 0)
num_items = len(menu_state.current_menu) + (1 if menu_state.show_save_option else 0)
# Determine the available height for the menu
max_menu_height = curses.LINES
@@ -65,18 +64,18 @@ def display_menu(state: MenuState) -> tuple[object, object]: # curses.window or
menu_win.border()
menu_win.keypad(True)
menu_pad = curses.newpad(len(state.current_menu) + 1, width - 8)
menu_pad = curses.newpad(len(menu_state.current_menu) + 1, width - 8)
menu_pad.bkgd(get_color("background"))
header = " > ".join(word.title() for word in state.menu_path)
header = " > ".join(word.title() for word in menu_state.menu_path)
if len(header) > width - 4:
header = header[:width - 7] + "..."
menu_win.addstr(1, 2, header, get_color("settings_breadcrumbs", bold=True))
transformed_path = transform_menu_path(state.menu_path)
transformed_path = transform_menu_path(menu_state.menu_path)
for idx, option in enumerate(state.current_menu):
field_info = state.current_menu[option]
for idx, option in enumerate(menu_state.current_menu):
field_info = menu_state.current_menu[option]
current_value = field_info[1] if isinstance(field_info, tuple) else ""
full_key = '.'.join(transformed_path + [option])
display_name = field_mapping.get(full_key, option)
@@ -85,30 +84,30 @@ def display_menu(state: MenuState) -> tuple[object, object]: # curses.window or
display_value = f"{current_value}"[:width // 2 - 4]
try:
color = get_color("settings_sensitive" if option in sensitive_settings else "settings_default", reverse=(idx == state.selected_index))
color = get_color("settings_sensitive" if option in sensitive_settings else "settings_default", reverse=(idx == menu_state.selected_index))
menu_pad.addstr(idx, 0, f"{display_option:<{width // 2 - 2}} {display_value}".ljust(width - 8), color)
except curses.error:
pass
if state.show_save_option:
if menu_state.show_save_option:
save_position = menu_height - 2
menu_win.addstr(save_position, (width - len(save_option)) // 2, save_option, get_color("settings_save", reverse=(state.selected_index == len(state.current_menu))))
menu_win.addstr(save_position, (width - len(save_option)) // 2, save_option, get_color("settings_save", reverse=(menu_state.selected_index == len(menu_state.current_menu))))
# Draw help window with dynamically updated max_help_lines
draw_help_window(start_y, start_x, menu_height, max_help_lines, transformed_path, state)
draw_help_window(start_y, start_x, menu_height, max_help_lines, transformed_path, menu_state)
menu_win.refresh()
menu_pad.refresh(
state.start_index[-1], 0,
menu_state.start_index[-1], 0,
menu_win.getbegyx()[0] + 3, menu_win.getbegyx()[1] + 4,
menu_win.getbegyx()[0] + 3 + menu_win.getmaxyx()[0] - 5 - (2 if state.show_save_option else 0),
menu_win.getbegyx()[0] + 3 + menu_win.getmaxyx()[0] - 5 - (2 if menu_state.show_save_option else 0),
menu_win.getbegyx()[1] + menu_win.getmaxyx()[1] - 4
)
max_index = num_items + (1 if state.show_save_option else 0) - 1
visible_height = menu_win.getmaxyx()[0] - 5 - (2 if state.show_save_option else 0)
max_index = num_items + (1 if menu_state.show_save_option else 0) - 1
visible_height = menu_win.getmaxyx()[0] - 5 - (2 if menu_state.show_save_option else 0)
draw_arrows(menu_win, visible_height, max_index, state)
draw_arrows(menu_win, visible_height, max_index, menu_state)
return menu_win, menu_pad
@@ -119,7 +118,7 @@ def draw_help_window(
menu_height: int,
max_help_lines: int,
transformed_path: list[str],
state: MenuState
menu_state: MenuState
) -> None:
global help_win
@@ -127,7 +126,7 @@ def draw_help_window(
if 'help_win' not in globals():
help_win = None # Initialize if it does not exist
selected_option = list(state.current_menu.keys())[state.selected_index] if state.current_menu else None
selected_option = list(menu_state.current_menu.keys())[menu_state.selected_index] if menu_state.current_menu else None
help_y = menu_start_y + menu_height
help_win = update_help_window(help_win, help_text, transformed_path, selected_option, max_help_lines, width, help_y, menu_start_x)
@@ -286,73 +285,73 @@ def move_highlight(
help_win: object,
help_text: dict[str, str],
max_help_lines: int,
state: MenuState
menu_state: MenuState
) -> None:
if old_idx == state.selected_index: # No-op
if old_idx == menu_state.selected_index: # No-op
return
max_index = len(options) + (1 if state.show_save_option else 0) - 1
visible_height = menu_win.getmaxyx()[0] - 5 - (2 if state.show_save_option else 0)
max_index = len(options) + (1 if menu_state.show_save_option else 0) - 1
visible_height = menu_win.getmaxyx()[0] - 5 - (2 if menu_state.show_save_option else 0)
# Adjust state.start_index only when moving out of visible range
if state.selected_index == max_index and state.show_save_option:
# Adjust menu_state.start_index only when moving out of visible range
if menu_state.selected_index == max_index and menu_state.show_save_option:
pass
elif state.selected_index < state.start_index[-1]: # Moving above the visible area
state.start_index[-1] = state.selected_index
elif state.selected_index >= state.start_index[-1] + visible_height: # Moving below the visible area
state.start_index[-1] = state.selected_index - visible_height
elif menu_state.selected_index < menu_state.start_index[-1]: # Moving above the visible area
menu_state.start_index[-1] = menu_state.selected_index
elif menu_state.selected_index >= menu_state.start_index[-1] + visible_height: # Moving below the visible area
menu_state.start_index[-1] = menu_state.selected_index - visible_height
pass
# Ensure state.start_index is within bounds
state.start_index[-1] = max(0, min(state.start_index[-1], max_index - visible_height + 1))
# Ensure menu_state.start_index is within bounds
menu_state.start_index[-1] = max(0, min(menu_state.start_index[-1], max_index - visible_height + 1))
# Clear old selection
if state.show_save_option and old_idx == max_index:
if menu_state.show_save_option and old_idx == max_index:
menu_win.chgat(menu_win.getmaxyx()[0] - 2, (width - len(save_option)) // 2, len(save_option), get_color("settings_save"))
else:
menu_pad.chgat(old_idx, 0, menu_pad.getmaxyx()[1], get_color("settings_sensitive") if options[old_idx] in sensitive_settings else get_color("settings_default"))
# Highlight new selection
if state.show_save_option and state.selected_index == max_index:
if menu_state.show_save_option and menu_state.selected_index == max_index:
menu_win.chgat(menu_win.getmaxyx()[0] - 2, (width - len(save_option)) // 2, len(save_option), get_color("settings_save", reverse=True))
else:
menu_pad.chgat(state.selected_index, 0, menu_pad.getmaxyx()[1], get_color("settings_sensitive", reverse=True) if options[state.selected_index] in sensitive_settings else get_color("settings_default", reverse=True))
menu_pad.chgat(menu_state.selected_index, 0, menu_pad.getmaxyx()[1], get_color("settings_sensitive", reverse=True) if options[menu_state.selected_index] in sensitive_settings else get_color("settings_default", reverse=True))
menu_win.refresh()
# Refresh pad only if scrolling is needed
menu_pad.refresh(state.start_index[-1], 0,
menu_pad.refresh(menu_state.start_index[-1], 0,
menu_win.getbegyx()[0] + 3, menu_win.getbegyx()[1] + 4,
menu_win.getbegyx()[0] + 3 + visible_height,
menu_win.getbegyx()[1] + menu_win.getmaxyx()[1] - 4)
# Update help window
transformed_path = transform_menu_path(state.menu_path)
selected_option = options[state.selected_index] if state.selected_index < len(options) else None
transformed_path = transform_menu_path(menu_state.menu_path)
selected_option = options[menu_state.selected_index] if menu_state.selected_index < len(options) else None
help_y = menu_win.getbegyx()[0] + menu_win.getmaxyx()[0]
help_win = update_help_window(help_win, help_text, transformed_path, selected_option, max_help_lines, width, help_y, menu_win.getbegyx()[1])
draw_arrows(menu_win, visible_height, max_index, state)
draw_arrows(menu_win, visible_height, max_index, menu_state)
def draw_arrows(
win: object,
visible_height: int,
max_index: int,
state: MenuState
menu_state: MenuState
) -> None:
# vh = visible_height + (1 if show_save_option else 0)
mi = max_index - (2 if state.show_save_option else 0)
mi = max_index - (2 if menu_state.show_save_option else 0)
if visible_height < mi:
if state.start_index[-1] > 0:
if menu_state.start_index[-1] > 0:
win.addstr(3, 2, "", get_color("settings_default"))
else:
win.addstr(3, 2, " ", get_color("settings_default"))
if mi - state.start_index[-1] >= visible_height + (0 if state.show_save_option else 1) :
if mi - menu_state.start_index[-1] >= visible_height + (0 if menu_state.show_save_option else 1) :
win.addstr(visible_height + 3, 2, "", get_color("settings_default"))
else:
win.addstr(visible_height + 3, 2, " ", get_color("settings_default"))
@@ -362,47 +361,47 @@ def settings_menu(stdscr: object, interface: object) -> None:
curses.update_lines_cols()
menu = generate_menu_from_protobuf(interface)
state.current_menu = menu["Main Menu"]
state.menu_path = ["Main Menu"]
menu_state.current_menu = menu["Main Menu"]
menu_state.menu_path = ["Main Menu"]
modified_settings = {}
need_redraw = True
state.show_save_option = False
menu_state.show_save_option = False
while True:
if(need_redraw):
options = list(state.current_menu.keys())
options = list(menu_state.current_menu.keys())
state.show_save_option = (
len(state.menu_path) > 2 and ("Radio Settings" in state.menu_path or "Module Settings" in state.menu_path)
menu_state.show_save_option = (
len(menu_state.menu_path) > 2 and ("Radio Settings" in menu_state.menu_path or "Module Settings" in menu_state.menu_path)
) or (
len(state.menu_path) == 2 and "User Settings" in state.menu_path
len(menu_state.menu_path) == 2 and "User Settings" in menu_state.menu_path
) or (
len(state.menu_path) == 3 and "Channels" in state.menu_path
len(menu_state.menu_path) == 3 and "Channels" in menu_state.menu_path
)
# Display the menu
menu_win, menu_pad = display_menu(state)
menu_win, menu_pad = display_menu(menu_state)
need_redraw = False
# Capture user input
key = menu_win.getch()
max_index = len(options) + (1 if state.show_save_option else 0) - 1
max_index = len(options) + (1 if menu_state.show_save_option else 0) - 1
# max_help_lines = 4
if key == curses.KEY_UP:
old_selected_index = state.selected_index
state.selected_index = max_index if state.selected_index == 0 else state.selected_index - 1
move_highlight(old_selected_index, options, menu_win, menu_pad, help_win, help_text, max_help_lines, state)
old_selected_index = menu_state.selected_index
menu_state.selected_index = max_index if menu_state.selected_index == 0 else menu_state.selected_index - 1
move_highlight(old_selected_index, options, menu_win, menu_pad, help_win, help_text, max_help_lines, menu_state)
elif key == curses.KEY_DOWN:
old_selected_index = state.selected_index
state.selected_index = 0 if state.selected_index == max_index else state.selected_index + 1
move_highlight(old_selected_index, options, menu_win, menu_pad, help_win, help_text, max_help_lines, state)
old_selected_index = menu_state.selected_index
menu_state.selected_index = 0 if menu_state.selected_index == max_index else menu_state.selected_index + 1
move_highlight(old_selected_index, options, menu_win, menu_pad, help_win, help_text, max_help_lines, menu_state)
elif key == curses.KEY_RESIZE:
need_redraw = True
@@ -414,36 +413,36 @@ def settings_menu(stdscr: object, interface: object) -> None:
menu_win.refresh()
help_win.refresh()
elif key == ord("\t") and state.show_save_option:
old_selected_index = state.selected_index
state.selected_index = max_index
move_highlight(old_selected_index, options, menu_win, menu_pad, help_win, help_text, max_help_lines, state)
elif key == ord("\t") and menu_state.show_save_option:
old_selected_index = menu_state.selected_index
menu_state.selected_index = max_index
move_highlight(old_selected_index, options, menu_win, menu_pad, help_win, help_text, max_help_lines, menu_state)
elif key == curses.KEY_RIGHT or key == ord('\n'):
need_redraw = True
state.start_index.append(0)
menu_state.start_index.append(0)
menu_win.erase()
help_win.erase()
# draw_help_window(menu_win.getbegyx()[0], menu_win.getbegyx()[1], menu_win.getmaxyx()[0], max_help_lines, state.current_menu, selected_index, transform_menu_path(state.menu_path))
# draw_help_window(menu_win.getbegyx()[0], menu_win.getbegyx()[1], menu_win.getmaxyx()[0], max_help_lines, menu_state.current_menu, selected_index, transform_menu_path(menu_state.menu_path))
menu_win.refresh()
help_win.refresh()
if state.show_save_option and state.selected_index == len(options):
save_changes(interface, modified_settings, state)
if menu_state.show_save_option and menu_state.selected_index == len(options):
save_changes(interface, modified_settings, menu_state)
modified_settings.clear()
logging.info("Changes Saved")
if len(state.menu_path) > 1:
state.menu_path.pop()
state.current_menu = menu["Main Menu"]
for step in state.menu_path[1:]:
state.current_menu = state.current_menu.get(step, {})
state.selected_index = 0
if len(menu_state.menu_path) > 1:
menu_state.menu_path.pop()
menu_state.current_menu = menu["Main Menu"]
for step in menu_state.menu_path[1:]:
menu_state.current_menu = menu_state.current_menu.get(step, {})
menu_state.selected_index = 0
continue
selected_option = options[state.selected_index]
selected_option = options[menu_state.selected_index]
if selected_option == "Exit":
break
@@ -452,7 +451,7 @@ def settings_menu(stdscr: object, interface: object) -> None:
filename = get_text_input("Enter a filename for the config file")
if not filename:
logging.info("Export aborted: No filename provided.")
state.start_index.pop()
menu_state.start_index.pop()
continue # Go back to the menu
if not filename.lower().endswith(".yaml"):
filename += ".yaml"
@@ -465,14 +464,14 @@ def settings_menu(stdscr: object, interface: object) -> None:
overwrite = get_list_input(f"{filename} already exists. Overwrite?", None, ["Yes", "No"])
if overwrite == "No":
logging.info("Export cancelled: User chose not to overwrite.")
state.start_index.pop()
menu_state.start_index.pop()
continue # Return to menu
os.makedirs(os.path.dirname(yaml_file_path), exist_ok=True)
with open(yaml_file_path, "w", encoding="utf-8") as file:
file.write(config_text)
logging.info(f"Config file saved to {yaml_file_path}")
dialog(stdscr, "Config File Saved:", yaml_file_path)
state.start_index.pop()
menu_state.start_index.pop()
continue
except PermissionError:
logging.error(f"Permission denied: Unable to write to {yaml_file_path}")
@@ -480,7 +479,7 @@ def settings_menu(stdscr: object, interface: object) -> None:
logging.error(f"OS error while saving config: {e}")
except Exception as e:
logging.error(f"Unexpected error: {e}")
state.start_index.pop()
menu_state.start_index.pop()
continue
elif selected_option == "Load Config File":
@@ -503,7 +502,7 @@ def settings_menu(stdscr: object, interface: object) -> None:
overwrite = get_list_input(f"Are you sure you want to load {filename}?", None, ["Yes", "No"])
if overwrite == "Yes":
config_import(interface, file_path)
state.start_index.pop()
menu_state.start_index.pop()
continue
elif selected_option == "Config URL":
@@ -515,7 +514,7 @@ def settings_menu(stdscr: object, interface: object) -> None:
if overwrite == "Yes":
interface.localNode.setURL(new_value)
logging.info(f"New Config URL sent to node")
state.start_index.pop()
menu_state.start_index.pop()
continue
elif selected_option == "Reboot":
@@ -523,7 +522,7 @@ def settings_menu(stdscr: object, interface: object) -> None:
if confirmation == "Yes":
interface.localNode.reboot()
logging.info(f"Node Reboot Requested by menu")
state.start_index.pop()
menu_state.start_index.pop()
continue
elif selected_option == "Reset Node DB":
@@ -531,7 +530,7 @@ def settings_menu(stdscr: object, interface: object) -> None:
if confirmation == "Yes":
interface.localNode.resetNodeDb()
logging.info(f"Node DB Reset Requested by menu")
state.start_index.pop()
menu_state.start_index.pop()
continue
elif selected_option == "Shutdown":
@@ -539,7 +538,7 @@ def settings_menu(stdscr: object, interface: object) -> None:
if confirmation == "Yes":
interface.localNode.shutdown()
logging.info(f"Node Shutdown Requested by menu")
state.start_index.pop()
menu_state.start_index.pop()
continue
elif selected_option == "Factory Reset":
@@ -547,28 +546,28 @@ def settings_menu(stdscr: object, interface: object) -> None:
if confirmation == "Yes":
interface.localNode.factoryReset()
logging.info(f"Factory Reset Requested by menu")
state.start_index.pop()
menu_state.start_index.pop()
continue
elif selected_option == "App Settings":
menu_win.clear()
menu_win.refresh()
state.menu_path.append("App Settings")
state.menu_index.append(state.selected_index)
json_editor(stdscr, state) # Open the App Settings menu
state.current_menu = menu["Main Menu"]
state.menu_path = ["Main Menu"]
state.start_index.pop()
state.selected_index = 4
menu_state.menu_path.append("App Settings")
menu_state.menu_index.append(menu_state.selected_index)
json_editor(stdscr, menu_state) # Open the App Settings menu
menu_state.current_menu = menu["Main Menu"]
menu_state.menu_path = ["Main Menu"]
menu_state.start_index.pop()
menu_state.selected_index = 4
continue
# need_redraw = True
field_info = state.current_menu.get(selected_option)
field_info = menu_state.current_menu.get(selected_option)
if isinstance(field_info, tuple):
field, current_value = field_info
# Transform the menu path to get the full key
transformed_path = transform_menu_path(state.menu_path)
transformed_path = transform_menu_path(menu_state.menu_path)
full_key = '.'.join(transformed_path + [selected_option])
# Fetch human-readable name from field_mapping
@@ -578,33 +577,33 @@ def settings_menu(stdscr: object, interface: object) -> None:
if selected_option in ['longName', 'shortName']:
new_value = get_text_input(f"{human_readable_name} is currently: {current_value}")
new_value = current_value if new_value is None else new_value
state.current_menu[selected_option] = (field, new_value)
menu_state.current_menu[selected_option] = (field, new_value)
elif selected_option == 'isLicensed':
new_value = get_list_input(f"{human_readable_name} is currently: {current_value}", str(current_value), ["True", "False"])
new_value = new_value == "True"
state.current_menu[selected_option] = (field, new_value)
menu_state.current_menu[selected_option] = (field, new_value)
for option, (field, value) in state.current_menu.items():
for option, (field, value) in menu_state.current_menu.items():
modified_settings[option] = value
state.start_index.pop()
menu_state.start_index.pop()
elif selected_option in ['latitude', 'longitude', 'altitude']:
new_value = get_text_input(f"{human_readable_name} is currently: {current_value}")
new_value = current_value if new_value is None else new_value
state.current_menu[selected_option] = (field, new_value)
menu_state.current_menu[selected_option] = (field, new_value)
for option in ['latitude', 'longitude', 'altitude']:
if option in state.current_menu:
modified_settings[option] = state.current_menu[option][1]
if option in menu_state.current_menu:
modified_settings[option] = menu_state.current_menu[option][1]
state.start_index.pop()
menu_state.start_index.pop()
elif selected_option == "admin_key":
new_values = get_admin_key_input(current_value)
new_value = current_value if new_values is None else [base64.b64decode(key) for key in new_values]
state.start_index.pop()
menu_state.start_index.pop()
elif field.type == 8: # Handle boolean type
new_value = get_list_input(human_readable_name, str(current_value), ["True", "False"])
@@ -612,39 +611,39 @@ def settings_menu(stdscr: object, interface: object) -> None:
pass # Leave it as-is
else:
new_value = new_value == "True" or new_value is True
state.start_index.pop()
menu_state.start_index.pop()
elif field.label == field.LABEL_REPEATED: # Handle repeated field - Not currently used
new_value = get_repeated_input(current_value)
new_value = current_value if new_value is None else new_value.split(", ")
state.start_index.pop()
menu_state.start_index.pop()
elif field.enum_type: # Enum field
enum_options = {v.name: v.number for v in field.enum_type.values}
new_value_name = get_list_input(human_readable_name, current_value, list(enum_options.keys()))
new_value = enum_options.get(new_value_name, current_value)
state.start_index.pop()
menu_state.start_index.pop()
elif field.type == 7: # Field type 7 corresponds to FIXED32
new_value = get_fixed32_input(current_value)
state.start_index.pop()
menu_state.start_index.pop()
elif field.type == 13: # Field type 13 corresponds to UINT32
new_value = get_text_input(f"{human_readable_name} is currently: {current_value}")
new_value = current_value if new_value is None else int(new_value)
state.start_index.pop()
menu_state.start_index.pop()
elif field.type == 2: # Field type 13 corresponds to INT64
new_value = get_text_input(f"{human_readable_name} is currently: {current_value}")
new_value = current_value if new_value is None else float(new_value)
state.start_index.pop()
menu_state.start_index.pop()
else: # Handle other field types
new_value = get_text_input(f"{human_readable_name} is currently: {current_value}")
new_value = current_value if new_value is None else new_value
state.start_index.pop()
menu_state.start_index.pop()
for key in state.menu_path[3:]: # Skip "Main Menu"
for key in menu_state.menu_path[3:]: # Skip "Main Menu"
modified_settings = modified_settings.setdefault(key, {})
# Add the new value to the appropriate level
@@ -655,12 +654,12 @@ def settings_menu(stdscr: object, interface: object) -> None:
enum_value_descriptor = field.enum_type.values_by_number.get(new_value)
new_value = enum_value_descriptor.name if enum_value_descriptor else new_value
state.current_menu[selected_option] = (field, new_value)
menu_state.current_menu[selected_option] = (field, new_value)
else:
state.current_menu = state.current_menu[selected_option]
state.menu_path.append(selected_option)
state.menu_index.append(state.selected_index)
state.selected_index = 0
menu_state.current_menu = menu_state.current_menu[selected_option]
menu_state.menu_path.append(selected_option)
menu_state.menu_index.append(menu_state.selected_index)
menu_state.selected_index = 0
elif key == curses.KEY_LEFT:
@@ -670,22 +669,22 @@ def settings_menu(stdscr: object, interface: object) -> None:
help_win.erase()
# max_help_lines = 4
# draw_help_window(menu_win.getbegyx()[0], menu_win.getbegyx()[1], menu_win.getmaxyx()[0], max_help_lines, state.current_menu, selected_index, transform_menu_path(state.menu_path))
# draw_help_window(menu_win.getbegyx()[0], menu_win.getbegyx()[1], menu_win.getmaxyx()[0], max_help_lines, menu_state.current_menu, selected_index, transform_menu_path(menu_state.menu_path))
menu_win.refresh()
help_win.refresh()
if len(state.menu_path) < 2:
if len(menu_state.menu_path) < 2:
modified_settings.clear()
# Navigate back to the previous menu
if len(state.menu_path) > 1:
state.menu_path.pop()
state.current_menu = menu["Main Menu"]
for step in state.menu_path[1:]:
state.current_menu = state.current_menu.get(step, {})
state.selected_index = state.menu_index.pop()
state.start_index.pop()
if len(menu_state.menu_path) > 1:
menu_state.menu_path.pop()
menu_state.current_menu = menu["Main Menu"]
for step in menu_state.menu_path[1:]:
menu_state.current_menu = menu_state.current_menu.get(step, {})
menu_state.selected_index = menu_state.menu_index.pop()
menu_state.start_index.pop()
elif key == 27: # Escape key
menu_win.erase()
+1 -1
View File
@@ -1,5 +1,5 @@
import logging
import json
import logging
import os
# Get the parent directory of the script
+1
View File
@@ -2,6 +2,7 @@ import curses
from contact.ui.colors import get_color
def draw_splash(stdscr: object) -> None:
"""Draw the splash screen with a logo and connecting message."""
curses.curs_set(0)
stdscr.clear()
+2
View File
@@ -1,6 +1,8 @@
import re
def parse_ini_file(ini_file_path: str) -> tuple[dict[str, str], dict[str, str]]:
"""Parses an INI file and returns a mapping of keys to human-readable names and help text."""
field_mapping: dict[str, str] = {}
help_text: dict[str, str] = {}
current_section: str | None = None
-1
View File
@@ -1,6 +1,5 @@
import logging
import meshtastic.serial_interface, meshtastic.tcp_interface, meshtastic.ble_interface
import contact.globals as globals
def initialize_interface(args):
try: