Implement settings tab with config editor and error logs viewer; refactor error logging functionality
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import argparse
|
||||
import subprocess
|
||||
import sys
|
||||
import pathlib
|
||||
import datetime
|
||||
|
||||
import flet as ft
|
||||
from flet import AppView, Page
|
||||
@@ -10,6 +12,12 @@ from ren_browser.ui.ui import build_ui
|
||||
# Current renderer name
|
||||
RENDERER = "plaintext"
|
||||
|
||||
ERROR_LOGS: list[str] = []
|
||||
|
||||
def log_error(msg: str):
|
||||
timestamp = datetime.datetime.now().isoformat()
|
||||
ERROR_LOGS.append(f"[{timestamp}] {msg}")
|
||||
|
||||
async def main(page: Page):
|
||||
# Build the main UI layout
|
||||
build_ui(page)
|
||||
@@ -37,37 +45,44 @@ if __name__ == "__main__":
|
||||
|
||||
def web():
|
||||
"""Launch Ren Browser in web mode via Flet CLI."""
|
||||
rc = subprocess.call(["flet", "run", "ren_browser/app.py", "--web"])
|
||||
script_path = pathlib.Path(__file__).resolve()
|
||||
rc = subprocess.call(["flet", "run", str(script_path), "--web"])
|
||||
sys.exit(rc)
|
||||
|
||||
def android():
|
||||
"""Launch Ren Browser in Android mode via Flet CLI."""
|
||||
rc = subprocess.call(["flet", "run", "ren_browser/app.py", "--android"])
|
||||
script_path = pathlib.Path(__file__).resolve()
|
||||
rc = subprocess.call(["flet", "run", str(script_path), "--android"])
|
||||
sys.exit(rc)
|
||||
|
||||
def ios():
|
||||
"""Launch Ren Browser in iOS mode via Flet CLI."""
|
||||
rc = subprocess.call(["flet", "run", "ren_browser/app.py", "--ios"])
|
||||
script_path = pathlib.Path(__file__).resolve()
|
||||
rc = subprocess.call(["flet", "run", str(script_path), "--ios"])
|
||||
sys.exit(rc)
|
||||
|
||||
# Hot reload (dev) mode entrypoints
|
||||
|
||||
def run_dev():
|
||||
"""Launch Ren Browser in desktop mode via Flet CLI with hot reload."""
|
||||
rc = subprocess.call(["flet", "run", "-d", "-r", "ren_browser/app.py"])
|
||||
script_path = pathlib.Path(__file__).resolve()
|
||||
rc = subprocess.call(["flet", "run", "-d", "-r", str(script_path)])
|
||||
sys.exit(rc)
|
||||
|
||||
def web_dev():
|
||||
"""Launch Ren Browser in web mode via Flet CLI with hot reload."""
|
||||
rc = subprocess.call(["flet", "run", "--web", "-d", "-r", "ren_browser/app.py"])
|
||||
script_path = pathlib.Path(__file__).resolve()
|
||||
rc = subprocess.call(["flet", "run", "--web", "-d", "-r", str(script_path)])
|
||||
sys.exit(rc)
|
||||
|
||||
def android_dev():
|
||||
"""Launch Ren Browser in Android mode via Flet CLI with hot reload."""
|
||||
rc = subprocess.call(["flet", "run", "--android", "-d", "-r", "ren_browser/app.py"])
|
||||
script_path = pathlib.Path(__file__).resolve()
|
||||
rc = subprocess.call(["flet", "run", "--android", "-d", "-r", str(script_path)])
|
||||
sys.exit(rc)
|
||||
|
||||
def ios_dev():
|
||||
"""Launch Ren Browser in iOS mode via Flet CLI with hot reload."""
|
||||
rc = subprocess.call(["flet", "run", "--ios", "-d", "-r", "ren_browser/app.py"])
|
||||
script_path = pathlib.Path(__file__).resolve()
|
||||
rc = subprocess.call(["flet", "run", "--ios", "-d", "-r", str(script_path)])
|
||||
sys.exit(rc)
|
||||
|
||||
63
ren_browser/ui/settings.py
Normal file
63
ren_browser/ui/settings.py
Normal file
@@ -0,0 +1,63 @@
|
||||
import flet as ft
|
||||
import pathlib
|
||||
from ren_browser.app import ERROR_LOGS
|
||||
|
||||
def open_settings_tab(page: ft.Page, tab_manager):
|
||||
# Locate Reticulum config file
|
||||
config_path = pathlib.Path(__file__).resolve().parents[2] / "config" / "config"
|
||||
try:
|
||||
config_text = config_path.read_text()
|
||||
except Exception as ex:
|
||||
config_text = f"Error reading config: {ex}"
|
||||
# Config editor
|
||||
config_field = ft.TextField(
|
||||
label="Reticulum config",
|
||||
value=config_text,
|
||||
expand=True,
|
||||
multiline=True,
|
||||
)
|
||||
# Save button handler
|
||||
def on_save_config(ev):
|
||||
try:
|
||||
config_path.write_text(config_field.value)
|
||||
page.snack_bar = ft.SnackBar(ft.Text("Config saved. Please restart the app."), open=True)
|
||||
except Exception as ex:
|
||||
page.snack_bar = ft.SnackBar(ft.Text(f"Error saving config: {ex}"), open=True)
|
||||
page.update()
|
||||
save_btn = ft.ElevatedButton("Save and Restart", on_click=on_save_config)
|
||||
# Error logs viewer
|
||||
error_text = "\n".join(ERROR_LOGS) or "No errors logged."
|
||||
error_field = ft.TextField(
|
||||
label="Error Logs",
|
||||
value=error_text,
|
||||
expand=True,
|
||||
multiline=True,
|
||||
read_only=True,
|
||||
)
|
||||
# Placeholder for content switching
|
||||
content_placeholder = ft.Container(expand=True)
|
||||
# View switch handlers
|
||||
def show_config(ev):
|
||||
content_placeholder.content = config_field
|
||||
page.update()
|
||||
def show_errors(ev):
|
||||
content_placeholder.content = error_field
|
||||
page.update()
|
||||
btn_config = ft.ElevatedButton("Config", on_click=show_config)
|
||||
btn_errors = ft.ElevatedButton("Errors", on_click=show_errors)
|
||||
button_row = ft.Row(controls=[btn_config, btn_errors])
|
||||
# Initialize to config view
|
||||
content_placeholder.content = config_field
|
||||
# Assemble settings UI
|
||||
settings_content = ft.Column(
|
||||
expand=True,
|
||||
controls=[
|
||||
button_row,
|
||||
content_placeholder,
|
||||
ft.Row([save_btn]),
|
||||
],
|
||||
)
|
||||
tab_manager._add_tab_internal("Settings", settings_content)
|
||||
idx = len(tab_manager.manager.tabs) - 1
|
||||
tab_manager.select_tab(idx)
|
||||
page.update()
|
||||
@@ -46,6 +46,8 @@ def build_ui(page: Page):
|
||||
try:
|
||||
result = page_fetcher.fetch_page(req)
|
||||
except Exception as ex:
|
||||
import ren_browser.app as app_module
|
||||
app_module.log_error(str(ex))
|
||||
result = f"Error: {ex}"
|
||||
# Skip update if tab has been closed or index out of range
|
||||
try:
|
||||
@@ -84,29 +86,9 @@ def build_ui(page: Page):
|
||||
|
||||
# Dynamic tabs manager for pages
|
||||
tab_manager = TabsManager(page)
|
||||
def open_settings_tab(e=None):
|
||||
import pathlib
|
||||
config_path = pathlib.Path(__file__).resolve().parents[2] / "config" / "config"
|
||||
try:
|
||||
config_text = config_path.read_text()
|
||||
except Exception as ex:
|
||||
config_text = f"Error reading config: {ex}"
|
||||
config_field = ft.TextField(label="Reticulum config", value=config_text, expand=True, multiline=True)
|
||||
def on_save_config(ev):
|
||||
try:
|
||||
config_path.write_text(config_field.value)
|
||||
page.snack_bar = ft.SnackBar(ft.Text("Config saved. Please restart the app."), open=True)
|
||||
except Exception as ex:
|
||||
page.snack_bar = ft.SnackBar(ft.Text(f"Error saving config: {ex}"), open=True)
|
||||
page.update()
|
||||
save_btn = ft.ElevatedButton("Save and Restart", on_click=on_save_config)
|
||||
settings_content = ft.Column(expand=True, controls=[config_field, ft.Row([save_btn])])
|
||||
tab_manager._add_tab_internal("Settings", settings_content)
|
||||
idx = len(tab_manager.manager.tabs) - 1
|
||||
tab_manager.select_tab(idx)
|
||||
page.update()
|
||||
|
||||
page.appbar.actions = [ft.IconButton(ft.Icons.SETTINGS, tooltip="Settings", on_click=open_settings_tab)]
|
||||
# Add Settings button using external settings module
|
||||
from ren_browser.ui.settings import open_settings_tab
|
||||
page.appbar.actions = [ft.IconButton(ft.Icons.SETTINGS, tooltip="Settings", on_click=lambda e: open_settings_tab(page, tab_manager))]
|
||||
Shortcuts(page, tab_manager)
|
||||
url_bar = ft.Row(
|
||||
controls=[
|
||||
|
||||
Reference in New Issue
Block a user