ruff fixes and formatting
This commit is contained in:
@@ -93,40 +93,41 @@ async def main(page: Page):
|
|||||||
|
|
||||||
def reload_reticulum(page: Page, on_complete=None):
|
def reload_reticulum(page: Page, on_complete=None):
|
||||||
"""Hot reload Reticulum with updated configuration.
|
"""Hot reload Reticulum with updated configuration.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
page: Flet page instance
|
page: Flet page instance
|
||||||
on_complete: Optional callback to run when reload is complete
|
on_complete: Optional callback to run when reload is complete
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def reload_thread():
|
def reload_thread():
|
||||||
import time
|
import time
|
||||||
|
|
||||||
try:
|
try:
|
||||||
global RNS_INSTANCE
|
global RNS_INSTANCE
|
||||||
|
|
||||||
if RNS_INSTANCE:
|
if RNS_INSTANCE:
|
||||||
try:
|
try:
|
||||||
RNS_INSTANCE.exit_handler()
|
RNS_INSTANCE.exit_handler()
|
||||||
print("RNS exit handler completed")
|
print("RNS exit handler completed")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Warning during RNS shutdown: {e}")
|
print(f"Warning during RNS shutdown: {e}")
|
||||||
|
|
||||||
RNS.Reticulum._Reticulum__instance = None
|
RNS.Reticulum._Reticulum__instance = None
|
||||||
|
|
||||||
RNS.Transport.destinations = []
|
RNS.Transport.destinations = []
|
||||||
|
|
||||||
RNS_INSTANCE = None
|
RNS_INSTANCE = None
|
||||||
print("RNS instance cleared")
|
print("RNS instance cleared")
|
||||||
|
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
|
||||||
# Initialize storage system
|
# Initialize storage system
|
||||||
storage = initialize_storage(page)
|
storage = initialize_storage(page)
|
||||||
|
|
||||||
# Get Reticulum config directory from storage manager
|
# Get Reticulum config directory from storage manager
|
||||||
config_dir = storage.get_reticulum_config_path()
|
config_dir = storage.get_reticulum_config_path()
|
||||||
|
|
||||||
# Ensure any saved config is written to filesystem before RNS init
|
# Ensure any saved config is written to filesystem before RNS init
|
||||||
try:
|
try:
|
||||||
saved_config = storage.load_config()
|
saved_config = storage.load_config()
|
||||||
@@ -136,27 +137,28 @@ def reload_reticulum(page: Page, on_complete=None):
|
|||||||
config_file_path.write_text(saved_config, encoding="utf-8")
|
config_file_path.write_text(saved_config, encoding="utf-8")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Warning: Failed to write config file: {e}")
|
print(f"Warning: Failed to write config file: {e}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Re-initialize Reticulum
|
# Re-initialize Reticulum
|
||||||
import ren_browser.logs
|
import ren_browser.logs
|
||||||
|
|
||||||
ren_browser.logs.setup_rns_logging()
|
ren_browser.logs.setup_rns_logging()
|
||||||
RNS_INSTANCE = RNS.Reticulum(str(config_dir))
|
RNS_INSTANCE = RNS.Reticulum(str(config_dir))
|
||||||
|
|
||||||
# Success
|
# Success
|
||||||
if on_complete:
|
if on_complete:
|
||||||
on_complete(True, None)
|
on_complete(True, None)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error reinitializing Reticulum: {e}")
|
print(f"Error reinitializing Reticulum: {e}")
|
||||||
if on_complete:
|
if on_complete:
|
||||||
on_complete(False, str(e))
|
on_complete(False, str(e))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error during reload: {e}")
|
print(f"Error during reload: {e}")
|
||||||
if on_complete:
|
if on_complete:
|
||||||
on_complete(False, str(e))
|
on_complete(False, str(e))
|
||||||
|
|
||||||
page.run_thread(reload_thread)
|
page.run_thread(reload_thread)
|
||||||
|
|
||||||
|
|
||||||
@@ -172,10 +174,17 @@ def run():
|
|||||||
help="Select renderer (plaintext or micron)",
|
help="Select renderer (plaintext or micron)",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-w", "--web", action="store_true", help="Launch in web browser mode",
|
"-w",
|
||||||
|
"--web",
|
||||||
|
action="store_true",
|
||||||
|
help="Launch in web browser mode",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-p", "--port", type=int, default=None, help="Port for web server",
|
"-p",
|
||||||
|
"--port",
|
||||||
|
type=int,
|
||||||
|
default=None,
|
||||||
|
help="Port for web server",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-c",
|
"-c",
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ def hex_to_rgb(hex_color: str) -> str:
|
|||||||
|
|
||||||
def parse_micron_line(line: str) -> list:
|
def parse_micron_line(line: str) -> list:
|
||||||
"""Parse a single line of micron markup into styled text spans.
|
"""Parse a single line of micron markup into styled text spans.
|
||||||
|
|
||||||
Returns list of dicts with 'text', 'bold', 'italic', 'underline', 'color', 'bgcolor'.
|
Returns list of dicts with 'text', 'bold', 'italic', 'underline', 'color', 'bgcolor'.
|
||||||
"""
|
"""
|
||||||
spans = []
|
spans = []
|
||||||
@@ -37,14 +37,16 @@ def parse_micron_line(line: str) -> list:
|
|||||||
while i < len(line):
|
while i < len(line):
|
||||||
if line[i] == "`" and i + 1 < len(line):
|
if line[i] == "`" and i + 1 < len(line):
|
||||||
if current_text:
|
if current_text:
|
||||||
spans.append({
|
spans.append(
|
||||||
"text": current_text,
|
{
|
||||||
"bold": bold,
|
"text": current_text,
|
||||||
"italic": italic,
|
"bold": bold,
|
||||||
"underline": underline,
|
"italic": italic,
|
||||||
"color": color,
|
"underline": underline,
|
||||||
"bgcolor": bgcolor,
|
"color": color,
|
||||||
})
|
"bgcolor": bgcolor,
|
||||||
|
}
|
||||||
|
)
|
||||||
current_text = ""
|
current_text = ""
|
||||||
|
|
||||||
tag = line[i + 1]
|
tag = line[i + 1]
|
||||||
@@ -59,13 +61,13 @@ def parse_micron_line(line: str) -> list:
|
|||||||
underline = not underline
|
underline = not underline
|
||||||
i += 2
|
i += 2
|
||||||
elif tag == "F" and i + 5 <= len(line):
|
elif tag == "F" and i + 5 <= len(line):
|
||||||
color = hex_to_rgb(line[i+2:i+5])
|
color = hex_to_rgb(line[i + 2 : i + 5])
|
||||||
i += 5
|
i += 5
|
||||||
elif tag == "f":
|
elif tag == "f":
|
||||||
color = None
|
color = None
|
||||||
i += 2
|
i += 2
|
||||||
elif tag == "B" and i + 5 <= len(line):
|
elif tag == "B" and i + 5 <= len(line):
|
||||||
bgcolor = hex_to_rgb(line[i+2:i+5])
|
bgcolor = hex_to_rgb(line[i + 2 : i + 5])
|
||||||
i += 5
|
i += 5
|
||||||
elif tag == "b":
|
elif tag == "b":
|
||||||
bgcolor = None
|
bgcolor = None
|
||||||
@@ -85,21 +87,23 @@ def parse_micron_line(line: str) -> list:
|
|||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
if current_text:
|
if current_text:
|
||||||
spans.append({
|
spans.append(
|
||||||
"text": current_text,
|
{
|
||||||
"bold": bold,
|
"text": current_text,
|
||||||
"italic": italic,
|
"bold": bold,
|
||||||
"underline": underline,
|
"italic": italic,
|
||||||
"color": color,
|
"underline": underline,
|
||||||
"bgcolor": bgcolor,
|
"color": color,
|
||||||
})
|
"bgcolor": bgcolor,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return spans
|
return spans
|
||||||
|
|
||||||
|
|
||||||
def render_micron(content: str, on_link_click=None) -> ft.Control:
|
def render_micron(content: str, on_link_click=None) -> ft.Control:
|
||||||
"""Render micron markup content to a Flet control.
|
"""Render micron markup content to a Flet control.
|
||||||
|
|
||||||
Falls back to plaintext renderer if parsing fails.
|
Falls back to plaintext renderer if parsing fails.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -119,7 +123,7 @@ def render_micron(content: str, on_link_click=None) -> ft.Control:
|
|||||||
|
|
||||||
def _render_micron_internal(content: str, on_link_click=None) -> ft.Control:
|
def _render_micron_internal(content: str, on_link_click=None) -> ft.Control:
|
||||||
"""Internal micron rendering implementation.
|
"""Internal micron rendering implementation.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
content: Micron markup content to render.
|
content: Micron markup content to render.
|
||||||
on_link_click: Optional callback function(url) called when a link is clicked.
|
on_link_click: Optional callback function(url) called when a link is clicked.
|
||||||
@@ -186,23 +190,23 @@ def _render_micron_internal(content: str, on_link_click=None) -> ft.Control:
|
|||||||
|
|
||||||
if "`[" in line:
|
if "`[" in line:
|
||||||
row_controls = []
|
row_controls = []
|
||||||
remaining = line
|
|
||||||
last_end = 0
|
last_end = 0
|
||||||
|
|
||||||
for link_match in re.finditer(r"`\[([^`]*)`([^\]]*)\]", line):
|
for link_match in re.finditer(r"`\[([^`]*)`([^\]]*)\]", line):
|
||||||
before = line[last_end:link_match.start()]
|
before = line[last_end : link_match.start()]
|
||||||
if before:
|
if before:
|
||||||
before_spans = parse_micron_line(before)
|
before_spans = parse_micron_line(before)
|
||||||
for span in before_spans:
|
for span in before_spans:
|
||||||
row_controls.append(create_text_span(span))
|
row_controls.append(create_text_span(span))
|
||||||
|
|
||||||
label = link_match.group(1)
|
label = link_match.group(1)
|
||||||
url = link_match.group(2)
|
url = link_match.group(2)
|
||||||
|
|
||||||
def make_link_handler(link_url):
|
def make_link_handler(link_url):
|
||||||
def handler(e):
|
def handler(e):
|
||||||
if on_link_click:
|
if on_link_click:
|
||||||
on_link_click(link_url)
|
on_link_click(link_url)
|
||||||
|
|
||||||
return handler
|
return handler
|
||||||
|
|
||||||
row_controls.append(
|
row_controls.append(
|
||||||
@@ -215,9 +219,9 @@ def _render_micron_internal(content: str, on_link_click=None) -> ft.Control:
|
|||||||
on_click=make_link_handler(url),
|
on_click=make_link_handler(url),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
last_end = link_match.end()
|
last_end = link_match.end()
|
||||||
|
|
||||||
after = line[last_end:]
|
after = line[last_end:]
|
||||||
if after:
|
if after:
|
||||||
after_spans = parse_micron_line(after)
|
after_spans = parse_micron_line(after)
|
||||||
|
|||||||
@@ -51,9 +51,7 @@ class StorageManager:
|
|||||||
elif "APPDATA" in os.environ: # Windows
|
elif "APPDATA" in os.environ: # Windows
|
||||||
storage_dir = pathlib.Path(os.environ["APPDATA"]) / "ren_browser"
|
storage_dir = pathlib.Path(os.environ["APPDATA"]) / "ren_browser"
|
||||||
elif "XDG_CONFIG_HOME" in os.environ: # Linux XDG standard
|
elif "XDG_CONFIG_HOME" in os.environ: # Linux XDG standard
|
||||||
storage_dir = (
|
storage_dir = pathlib.Path(os.environ["XDG_CONFIG_HOME"]) / "ren_browser"
|
||||||
pathlib.Path(os.environ["XDG_CONFIG_HOME"]) / "ren_browser"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
storage_dir = pathlib.Path.home() / ".ren_browser"
|
storage_dir = pathlib.Path.home() / ".ren_browser"
|
||||||
|
|
||||||
@@ -126,7 +124,8 @@ class StorageManager:
|
|||||||
if self.page and hasattr(self.page, "client_storage"):
|
if self.page and hasattr(self.page, "client_storage"):
|
||||||
self.page.client_storage.set("ren_browser_config", config_content)
|
self.page.client_storage.set("ren_browser_config", config_content)
|
||||||
self.page.client_storage.set(
|
self.page.client_storage.set(
|
||||||
"ren_browser_config_error", f"File save failed: {error}",
|
"ren_browser_config_error",
|
||||||
|
f"File save failed: {error}",
|
||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -193,7 +192,8 @@ class StorageManager:
|
|||||||
|
|
||||||
if self.page and hasattr(self.page, "client_storage"):
|
if self.page and hasattr(self.page, "client_storage"):
|
||||||
self.page.client_storage.set(
|
self.page.client_storage.set(
|
||||||
"ren_browser_bookmarks", json.dumps(bookmarks),
|
"ren_browser_bookmarks",
|
||||||
|
json.dumps(bookmarks),
|
||||||
)
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
@@ -258,7 +258,9 @@ class StorageManager:
|
|||||||
json.dump(settings, f, indent=2)
|
json.dump(settings, f, indent=2)
|
||||||
|
|
||||||
if self.page and hasattr(self.page, "client_storage"):
|
if self.page and hasattr(self.page, "client_storage"):
|
||||||
self.page.client_storage.set("ren_browser_settings", json.dumps(settings))
|
self.page.client_storage.set(
|
||||||
|
"ren_browser_settings", json.dumps(settings)
|
||||||
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -270,7 +272,7 @@ class StorageManager:
|
|||||||
"horizontal_scroll": False,
|
"horizontal_scroll": False,
|
||||||
"page_bgcolor": "#000000",
|
"page_bgcolor": "#000000",
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
settings_path = self._storage_dir / "settings.json"
|
settings_path = self._storage_dir / "settings.json"
|
||||||
if settings_path.exists():
|
if settings_path.exists():
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ class TabsManager:
|
|||||||
self.page = page
|
self.page = page
|
||||||
self.page.on_resize = self._on_resize
|
self.page.on_resize = self._on_resize
|
||||||
self.manager = SimpleNamespace(tabs=[], index=0)
|
self.manager = SimpleNamespace(tabs=[], index=0)
|
||||||
|
|
||||||
storage = get_storage_manager(page)
|
storage = get_storage_manager(page)
|
||||||
self.settings = storage.load_app_settings()
|
self.settings = storage.load_app_settings()
|
||||||
|
|
||||||
self.tab_bar = ft.Container(
|
self.tab_bar = ft.Container(
|
||||||
content=ft.Row(
|
content=ft.Row(
|
||||||
spacing=6,
|
spacing=6,
|
||||||
@@ -60,7 +60,9 @@ class TabsManager:
|
|||||||
self._on_tab_go(None, 0)
|
self._on_tab_go(None, 0)
|
||||||
|
|
||||||
default_content = (
|
default_content = (
|
||||||
render_micron("Welcome to Ren Browser", on_link_click=handle_link_click_home)
|
render_micron(
|
||||||
|
"Welcome to Ren Browser", on_link_click=handle_link_click_home
|
||||||
|
)
|
||||||
if app_module.RENDERER == "micron"
|
if app_module.RENDERER == "micron"
|
||||||
else render_plaintext("Welcome to Ren Browser")
|
else render_plaintext("Welcome to Ren Browser")
|
||||||
)
|
)
|
||||||
@@ -96,16 +98,16 @@ class TabsManager:
|
|||||||
self.settings = settings
|
self.settings = settings
|
||||||
bgcolor = settings.get("page_bgcolor", "#000000")
|
bgcolor = settings.get("page_bgcolor", "#000000")
|
||||||
self.content_container.bgcolor = bgcolor
|
self.content_container.bgcolor = bgcolor
|
||||||
|
|
||||||
horizontal_scroll = settings.get("horizontal_scroll", False)
|
horizontal_scroll = settings.get("horizontal_scroll", False)
|
||||||
scroll_mode = ft.ScrollMode.ALWAYS if horizontal_scroll else ft.ScrollMode.AUTO
|
scroll_mode = ft.ScrollMode.ALWAYS if horizontal_scroll else ft.ScrollMode.AUTO
|
||||||
|
|
||||||
for tab in self.manager.tabs:
|
for tab in self.manager.tabs:
|
||||||
if "content" in tab and hasattr(tab["content"], "scroll"):
|
if "content" in tab and hasattr(tab["content"], "scroll"):
|
||||||
tab["content"].scroll = scroll_mode
|
tab["content"].scroll = scroll_mode
|
||||||
if "content_control" in tab and hasattr(tab["content_control"], "scroll"):
|
if "content_control" in tab and hasattr(tab["content_control"], "scroll"):
|
||||||
tab["content_control"].scroll = scroll_mode
|
tab["content_control"].scroll = scroll_mode
|
||||||
|
|
||||||
if self.content_container.content:
|
if self.content_container.content:
|
||||||
self.content_container.content.update()
|
self.content_container.content.update()
|
||||||
self.page.update()
|
self.page.update()
|
||||||
@@ -127,7 +129,9 @@ class TabsManager:
|
|||||||
cumulative_width = 0
|
cumulative_width = 0
|
||||||
visible_tabs_count = 0
|
visible_tabs_count = 0
|
||||||
|
|
||||||
tab_containers = [c for c in self.tab_bar.content.controls if isinstance(c, ft.Container)]
|
tab_containers = [
|
||||||
|
c for c in self.tab_bar.content.controls if isinstance(c, ft.Container)
|
||||||
|
]
|
||||||
|
|
||||||
for i, tab in enumerate(self.manager.tabs):
|
for i, tab in enumerate(self.manager.tabs):
|
||||||
estimated_width = len(tab["title"]) * 10 + 32 + self.tab_bar.content.spacing
|
estimated_width = len(tab["title"]) * 10 + 32 + self.tab_bar.content.spacing
|
||||||
@@ -183,7 +187,7 @@ class TabsManager:
|
|||||||
content_control = content
|
content_control = content
|
||||||
horizontal_scroll = self.settings.get("horizontal_scroll", False)
|
horizontal_scroll = self.settings.get("horizontal_scroll", False)
|
||||||
scroll_mode = ft.ScrollMode.ALWAYS if horizontal_scroll else ft.ScrollMode.AUTO
|
scroll_mode = ft.ScrollMode.ALWAYS if horizontal_scroll else ft.ScrollMode.AUTO
|
||||||
|
|
||||||
tab_content = ft.Column(
|
tab_content = ft.Column(
|
||||||
expand=True,
|
expand=True,
|
||||||
scroll=scroll_mode,
|
scroll=scroll_mode,
|
||||||
@@ -254,13 +258,17 @@ class TabsManager:
|
|||||||
return
|
return
|
||||||
idx = self.manager.index
|
idx = self.manager.index
|
||||||
|
|
||||||
tab_containers = [c for c in self.tab_bar.content.controls if isinstance(c, ft.Container)]
|
tab_containers = [
|
||||||
|
c for c in self.tab_bar.content.controls if isinstance(c, ft.Container)
|
||||||
|
]
|
||||||
control_to_remove = tab_containers[idx]
|
control_to_remove = tab_containers[idx]
|
||||||
|
|
||||||
self.manager.tabs.pop(idx)
|
self.manager.tabs.pop(idx)
|
||||||
self.tab_bar.content.controls.remove(control_to_remove)
|
self.tab_bar.content.controls.remove(control_to_remove)
|
||||||
|
|
||||||
updated_tab_containers = [c for c in self.tab_bar.content.controls if isinstance(c, ft.Container)]
|
updated_tab_containers = [
|
||||||
|
c for c in self.tab_bar.content.controls if isinstance(c, ft.Container)
|
||||||
|
]
|
||||||
for i, control in enumerate(updated_tab_containers):
|
for i, control in enumerate(updated_tab_containers):
|
||||||
control.on_click = lambda e, i=i: self.select_tab(i) # type: ignore
|
control.on_click = lambda e, i=i: self.select_tab(i) # type: ignore
|
||||||
|
|
||||||
@@ -278,7 +286,9 @@ class TabsManager:
|
|||||||
"""
|
"""
|
||||||
self.manager.index = idx
|
self.manager.index = idx
|
||||||
|
|
||||||
tab_containers = [c for c in self.tab_bar.content.controls if isinstance(c, ft.Container)]
|
tab_containers = [
|
||||||
|
c for c in self.tab_bar.content.controls if isinstance(c, ft.Container)
|
||||||
|
]
|
||||||
for i, control in enumerate(tab_containers):
|
for i, control in enumerate(tab_containers):
|
||||||
if i == idx:
|
if i == idx:
|
||||||
control.bgcolor = ft.Colors.BLUE_900
|
control.bgcolor = ft.Colors.BLUE_900
|
||||||
@@ -296,7 +306,7 @@ class TabsManager:
|
|||||||
url = tab["url_field"].value.strip()
|
url = tab["url_field"].value.strip()
|
||||||
if not url:
|
if not url:
|
||||||
return
|
return
|
||||||
|
|
||||||
placeholder_text = f"Loading content for {url}..."
|
placeholder_text = f"Loading content for {url}..."
|
||||||
import ren_browser.app as app_module
|
import ren_browser.app as app_module
|
||||||
|
|
||||||
@@ -330,12 +340,12 @@ class TabsManager:
|
|||||||
def fetch_and_update():
|
def fetch_and_update():
|
||||||
parts = url.split(":", 1)
|
parts = url.split(":", 1)
|
||||||
if len(parts) != 2:
|
if len(parts) != 2:
|
||||||
result = f"Error: Invalid URL format. Expected format: hash:/page/path"
|
result = "Error: Invalid URL format. Expected format: hash:/page/path"
|
||||||
page_path = ""
|
page_path = ""
|
||||||
else:
|
else:
|
||||||
dest_hash = parts[0]
|
dest_hash = parts[0]
|
||||||
page_path = parts[1] if parts[1].startswith("/") else f"/{parts[1]}"
|
page_path = parts[1] if parts[1].startswith("/") else f"/{parts[1]}"
|
||||||
|
|
||||||
req = PageRequest(destination_hash=dest_hash, page_path=page_path)
|
req = PageRequest(destination_hash=dest_hash, page_path=page_path)
|
||||||
page_fetcher = PageFetcher()
|
page_fetcher = PageFetcher()
|
||||||
try:
|
try:
|
||||||
@@ -343,7 +353,7 @@ class TabsManager:
|
|||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
app_module.log_error(str(ex))
|
app_module.log_error(str(ex))
|
||||||
result = f"Error: {ex}"
|
result = f"Error: {ex}"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
tab = self.manager.tabs[idx]
|
tab = self.manager.tabs[idx]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
@@ -353,7 +363,7 @@ class TabsManager:
|
|||||||
new_control = render_micron(result, on_link_click=handle_link_click)
|
new_control = render_micron(result, on_link_click=handle_link_click)
|
||||||
else:
|
else:
|
||||||
new_control = render_plaintext(result)
|
new_control = render_plaintext(result)
|
||||||
|
|
||||||
tab["content_control"] = new_control
|
tab["content_control"] = new_control
|
||||||
tab["content"].controls[0] = new_control
|
tab["content"].controls[0] = new_control
|
||||||
if self.manager.index == idx:
|
if self.manager.index == idx:
|
||||||
|
|||||||
@@ -77,8 +77,15 @@ def open_settings_tab(page: ft.Page, tab_manager):
|
|||||||
snack = ft.SnackBar(
|
snack = ft.SnackBar(
|
||||||
content=ft.Row(
|
content=ft.Row(
|
||||||
controls=[
|
controls=[
|
||||||
ft.Icon(ft.Icons.CHECK_CIRCLE, color=ft.Colors.GREEN_400, size=20),
|
ft.Icon(
|
||||||
ft.Text("Configuration saved! Restart app to apply changes.", color=ft.Colors.WHITE),
|
ft.Icons.CHECK_CIRCLE,
|
||||||
|
color=ft.Colors.GREEN_400,
|
||||||
|
size=20,
|
||||||
|
),
|
||||||
|
ft.Text(
|
||||||
|
"Configuration saved! Restart app to apply changes.",
|
||||||
|
color=ft.Colors.WHITE,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
tight=True,
|
tight=True,
|
||||||
),
|
),
|
||||||
@@ -93,7 +100,9 @@ def open_settings_tab(page: ft.Page, tab_manager):
|
|||||||
content=ft.Row(
|
content=ft.Row(
|
||||||
controls=[
|
controls=[
|
||||||
ft.Icon(ft.Icons.ERROR, color=ft.Colors.RED_400, size=20),
|
ft.Icon(ft.Icons.ERROR, color=ft.Colors.RED_400, size=20),
|
||||||
ft.Text("Failed to save configuration", color=ft.Colors.WHITE),
|
ft.Text(
|
||||||
|
"Failed to save configuration", color=ft.Colors.WHITE
|
||||||
|
),
|
||||||
],
|
],
|
||||||
tight=True,
|
tight=True,
|
||||||
),
|
),
|
||||||
@@ -127,7 +136,9 @@ def open_settings_tab(page: ft.Page, tab_manager):
|
|||||||
content=ft.Row(
|
content=ft.Row(
|
||||||
controls=[
|
controls=[
|
||||||
ft.Icon(ft.Icons.ERROR, color=ft.Colors.RED_400, size=20),
|
ft.Icon(ft.Icons.ERROR, color=ft.Colors.RED_400, size=20),
|
||||||
ft.Text("Failed to save configuration", color=ft.Colors.WHITE),
|
ft.Text(
|
||||||
|
"Failed to save configuration", color=ft.Colors.WHITE
|
||||||
|
),
|
||||||
],
|
],
|
||||||
tight=True,
|
tight=True,
|
||||||
),
|
),
|
||||||
@@ -138,11 +149,16 @@ def open_settings_tab(page: ft.Page, tab_manager):
|
|||||||
snack.open = True
|
snack.open = True
|
||||||
page.update()
|
page.update()
|
||||||
return
|
return
|
||||||
|
|
||||||
loading_snack = ft.SnackBar(
|
loading_snack = ft.SnackBar(
|
||||||
content=ft.Row(
|
content=ft.Row(
|
||||||
controls=[
|
controls=[
|
||||||
ft.ProgressRing(width=16, height=16, stroke_width=2, color=ft.Colors.BLUE_400),
|
ft.ProgressRing(
|
||||||
|
width=16,
|
||||||
|
height=16,
|
||||||
|
stroke_width=2,
|
||||||
|
color=ft.Colors.BLUE_400,
|
||||||
|
),
|
||||||
ft.Text("Reloading Reticulum...", color=ft.Colors.WHITE),
|
ft.Text("Reloading Reticulum...", color=ft.Colors.WHITE),
|
||||||
],
|
],
|
||||||
tight=True,
|
tight=True,
|
||||||
@@ -153,17 +169,24 @@ def open_settings_tab(page: ft.Page, tab_manager):
|
|||||||
page.overlay.append(loading_snack)
|
page.overlay.append(loading_snack)
|
||||||
loading_snack.open = True
|
loading_snack.open = True
|
||||||
page.update()
|
page.update()
|
||||||
|
|
||||||
def on_reload_complete(success, error):
|
def on_reload_complete(success, error):
|
||||||
loading_snack.open = False
|
loading_snack.open = False
|
||||||
page.update()
|
page.update()
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
snack = ft.SnackBar(
|
snack = ft.SnackBar(
|
||||||
content=ft.Row(
|
content=ft.Row(
|
||||||
controls=[
|
controls=[
|
||||||
ft.Icon(ft.Icons.CHECK_CIRCLE, color=ft.Colors.GREEN_400, size=20),
|
ft.Icon(
|
||||||
ft.Text("Reticulum reloaded successfully!", color=ft.Colors.WHITE),
|
ft.Icons.CHECK_CIRCLE,
|
||||||
|
color=ft.Colors.GREEN_400,
|
||||||
|
size=20,
|
||||||
|
),
|
||||||
|
ft.Text(
|
||||||
|
"Reticulum reloaded successfully!",
|
||||||
|
color=ft.Colors.WHITE,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
tight=True,
|
tight=True,
|
||||||
),
|
),
|
||||||
@@ -174,8 +197,12 @@ def open_settings_tab(page: ft.Page, tab_manager):
|
|||||||
snack = ft.SnackBar(
|
snack = ft.SnackBar(
|
||||||
content=ft.Row(
|
content=ft.Row(
|
||||||
controls=[
|
controls=[
|
||||||
ft.Icon(ft.Icons.ERROR, color=ft.Colors.RED_400, size=20),
|
ft.Icon(
|
||||||
ft.Text(f"Reload failed: {error}", color=ft.Colors.WHITE),
|
ft.Icons.ERROR, color=ft.Colors.RED_400, size=20
|
||||||
|
),
|
||||||
|
ft.Text(
|
||||||
|
f"Reload failed: {error}", color=ft.Colors.WHITE
|
||||||
|
),
|
||||||
],
|
],
|
||||||
tight=True,
|
tight=True,
|
||||||
),
|
),
|
||||||
@@ -185,10 +212,11 @@ def open_settings_tab(page: ft.Page, tab_manager):
|
|||||||
page.overlay.append(snack)
|
page.overlay.append(snack)
|
||||||
snack.open = True
|
snack.open = True
|
||||||
page.update()
|
page.update()
|
||||||
|
|
||||||
import ren_browser.app as app_module
|
import ren_browser.app as app_module
|
||||||
|
|
||||||
app_module.reload_reticulum(page, on_reload_complete)
|
app_module.reload_reticulum(page, on_reload_complete)
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
snack = ft.SnackBar(
|
snack = ft.SnackBar(
|
||||||
content=ft.Row(
|
content=ft.Row(
|
||||||
@@ -217,8 +245,15 @@ def open_settings_tab(page: ft.Page, tab_manager):
|
|||||||
snack = ft.SnackBar(
|
snack = ft.SnackBar(
|
||||||
content=ft.Row(
|
content=ft.Row(
|
||||||
controls=[
|
controls=[
|
||||||
ft.Icon(ft.Icons.CHECK_CIRCLE, color=ft.Colors.GREEN_400, size=20),
|
ft.Icon(
|
||||||
ft.Text("Appearance settings saved and applied!", color=ft.Colors.WHITE),
|
ft.Icons.CHECK_CIRCLE,
|
||||||
|
color=ft.Colors.GREEN_400,
|
||||||
|
size=20,
|
||||||
|
),
|
||||||
|
ft.Text(
|
||||||
|
"Appearance settings saved and applied!",
|
||||||
|
color=ft.Colors.WHITE,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
tight=True,
|
tight=True,
|
||||||
),
|
),
|
||||||
@@ -233,7 +268,10 @@ def open_settings_tab(page: ft.Page, tab_manager):
|
|||||||
content=ft.Row(
|
content=ft.Row(
|
||||||
controls=[
|
controls=[
|
||||||
ft.Icon(ft.Icons.ERROR, color=ft.Colors.RED_400, size=20),
|
ft.Icon(ft.Icons.ERROR, color=ft.Colors.RED_400, size=20),
|
||||||
ft.Text("Failed to save appearance settings", color=ft.Colors.WHITE),
|
ft.Text(
|
||||||
|
"Failed to save appearance settings",
|
||||||
|
color=ft.Colors.WHITE,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
tight=True,
|
tight=True,
|
||||||
),
|
),
|
||||||
@@ -410,7 +448,14 @@ def open_settings_tab(page: ft.Page, tab_manager):
|
|||||||
|
|
||||||
nav_card = ft.Container(
|
nav_card = ft.Container(
|
||||||
content=ft.Row(
|
content=ft.Row(
|
||||||
controls=[btn_config, btn_appearance, btn_errors, btn_ret, btn_storage, btn_refresh],
|
controls=[
|
||||||
|
btn_config,
|
||||||
|
btn_appearance,
|
||||||
|
btn_errors,
|
||||||
|
btn_ret,
|
||||||
|
btn_storage,
|
||||||
|
btn_refresh,
|
||||||
|
],
|
||||||
spacing=8,
|
spacing=8,
|
||||||
wrap=True,
|
wrap=True,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -84,7 +84,9 @@ def build_ui(page: Page):
|
|||||||
tab_manager._on_tab_go(None, idx)
|
tab_manager._on_tab_go(None, idx)
|
||||||
|
|
||||||
if req.page_path.endswith(".mu"):
|
if req.page_path.endswith(".mu"):
|
||||||
new_control = render_micron(result, on_link_click=handle_link_click)
|
new_control = render_micron(
|
||||||
|
result, on_link_click=handle_link_click
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
new_control = render_plaintext(result)
|
new_control = render_plaintext(result)
|
||||||
tab["content_control"] = new_control
|
tab["content_control"] = new_control
|
||||||
|
|||||||
@@ -62,7 +62,9 @@ def sample_page_request():
|
|||||||
from ren_browser.pages.page_request import PageRequest
|
from ren_browser.pages.page_request import PageRequest
|
||||||
|
|
||||||
return PageRequest(
|
return PageRequest(
|
||||||
destination_hash="1234567890abcdef", page_path="/page/index.mu", field_data=None,
|
destination_hash="1234567890abcdef",
|
||||||
|
page_path="/page/index.mu",
|
||||||
|
field_data=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ class TestAnnounce:
|
|||||||
def test_announce_with_none_display_name(self):
|
def test_announce_with_none_display_name(self):
|
||||||
"""Test Announce creation with None display name."""
|
"""Test Announce creation with None display name."""
|
||||||
announce = Announce(
|
announce = Announce(
|
||||||
destination_hash="1234567890abcdef", display_name=None, timestamp=1234567890,
|
destination_hash="1234567890abcdef",
|
||||||
|
display_name=None,
|
||||||
|
timestamp=1234567890,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert announce.destination_hash == "1234567890abcdef"
|
assert announce.destination_hash == "1234567890abcdef"
|
||||||
|
|||||||
@@ -59,7 +59,9 @@ class TestLogsModule:
|
|||||||
assert len(logs.RET_LOGS) == 1
|
assert len(logs.RET_LOGS) == 1
|
||||||
assert logs.RET_LOGS[0] == "[2023-01-01T12:00:00] Test RNS message"
|
assert logs.RET_LOGS[0] == "[2023-01-01T12:00:00] Test RNS message"
|
||||||
logs._original_rns_log.assert_called_once_with(
|
logs._original_rns_log.assert_called_once_with(
|
||||||
"Test RNS message", "arg1", kwarg1="value1",
|
"Test RNS message",
|
||||||
|
"arg1",
|
||||||
|
kwarg1="value1",
|
||||||
)
|
)
|
||||||
assert result == "original_result"
|
assert result == "original_result"
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ class TestPageRequest:
|
|||||||
def test_page_request_creation(self):
|
def test_page_request_creation(self):
|
||||||
"""Test basic PageRequest creation."""
|
"""Test basic PageRequest creation."""
|
||||||
request = PageRequest(
|
request = PageRequest(
|
||||||
destination_hash="1234567890abcdef", page_path="/page/index.mu",
|
destination_hash="1234567890abcdef",
|
||||||
|
page_path="/page/index.mu",
|
||||||
)
|
)
|
||||||
|
|
||||||
assert request.destination_hash == "1234567890abcdef"
|
assert request.destination_hash == "1234567890abcdef"
|
||||||
|
|||||||
@@ -51,11 +51,14 @@ class TestStorageManager:
|
|||||||
with (
|
with (
|
||||||
patch("os.name", "posix"),
|
patch("os.name", "posix"),
|
||||||
patch.dict(
|
patch.dict(
|
||||||
"os.environ", {"XDG_CONFIG_HOME": "/home/user/.config"}, clear=True,
|
"os.environ",
|
||||||
|
{"XDG_CONFIG_HOME": "/home/user/.config"},
|
||||||
|
clear=True,
|
||||||
|
),
|
||||||
|
patch("pathlib.Path.mkdir"),
|
||||||
|
patch(
|
||||||
|
"ren_browser.storage.storage.StorageManager._ensure_storage_directory",
|
||||||
),
|
),
|
||||||
patch("pathlib.Path.mkdir"),patch(
|
|
||||||
"ren_browser.storage.storage.StorageManager._ensure_storage_directory",
|
|
||||||
),
|
|
||||||
):
|
):
|
||||||
storage = StorageManager()
|
storage = StorageManager()
|
||||||
storage._storage_dir = storage._get_storage_directory()
|
storage._storage_dir = storage._get_storage_directory()
|
||||||
@@ -71,7 +74,11 @@ class TestStorageManager:
|
|||||||
"""Test storage directory detection for Android with ANDROID_DATA."""
|
"""Test storage directory detection for Android with ANDROID_DATA."""
|
||||||
with (
|
with (
|
||||||
patch("os.name", "posix"),
|
patch("os.name", "posix"),
|
||||||
patch.dict("os.environ", {"ANDROID_ROOT": "/system", "ANDROID_DATA": "/data"}, clear=True),
|
patch.dict(
|
||||||
|
"os.environ",
|
||||||
|
{"ANDROID_ROOT": "/system", "ANDROID_DATA": "/data"},
|
||||||
|
clear=True,
|
||||||
|
),
|
||||||
patch("pathlib.Path.mkdir"),
|
patch("pathlib.Path.mkdir"),
|
||||||
):
|
):
|
||||||
with patch(
|
with patch(
|
||||||
@@ -86,7 +93,11 @@ class TestStorageManager:
|
|||||||
"""Test storage directory detection for Android with EXTERNAL_STORAGE."""
|
"""Test storage directory detection for Android with EXTERNAL_STORAGE."""
|
||||||
with (
|
with (
|
||||||
patch("os.name", "posix"),
|
patch("os.name", "posix"),
|
||||||
patch.dict("os.environ", {"ANDROID_ROOT": "/system", "EXTERNAL_STORAGE": "/storage/emulated/0"}, clear=True),
|
patch.dict(
|
||||||
|
"os.environ",
|
||||||
|
{"ANDROID_ROOT": "/system", "EXTERNAL_STORAGE": "/storage/emulated/0"},
|
||||||
|
clear=True,
|
||||||
|
),
|
||||||
patch("pathlib.Path.mkdir"),
|
patch("pathlib.Path.mkdir"),
|
||||||
):
|
):
|
||||||
with patch(
|
with patch(
|
||||||
@@ -102,9 +113,10 @@ class TestStorageManager:
|
|||||||
with (
|
with (
|
||||||
patch("os.name", "posix"),
|
patch("os.name", "posix"),
|
||||||
patch.dict("os.environ", {"ANDROID_ROOT": "/system"}, clear=True),
|
patch.dict("os.environ", {"ANDROID_ROOT": "/system"}, clear=True),
|
||||||
patch("pathlib.Path.mkdir"),patch(
|
patch("pathlib.Path.mkdir"),
|
||||||
"ren_browser.storage.storage.StorageManager._ensure_storage_directory",
|
patch(
|
||||||
),
|
"ren_browser.storage.storage.StorageManager._ensure_storage_directory",
|
||||||
|
),
|
||||||
):
|
):
|
||||||
storage = StorageManager()
|
storage = StorageManager()
|
||||||
storage._storage_dir = storage._get_storage_directory()
|
storage._storage_dir = storage._get_storage_directory()
|
||||||
@@ -169,7 +181,8 @@ class TestStorageManager:
|
|||||||
|
|
||||||
assert result is True
|
assert result is True
|
||||||
mock_page.client_storage.set.assert_called_with(
|
mock_page.client_storage.set.assert_called_with(
|
||||||
"ren_browser_config", config_content,
|
"ren_browser_config",
|
||||||
|
config_content,
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_save_config_fallback(self):
|
def test_save_config_fallback(self):
|
||||||
@@ -182,13 +195,16 @@ class TestStorageManager:
|
|||||||
storage._storage_dir = Path(temp_dir)
|
storage._storage_dir = Path(temp_dir)
|
||||||
|
|
||||||
# Mock the reticulum config path to use temp dir and cause failure
|
# Mock the reticulum config path to use temp dir and cause failure
|
||||||
with patch.object(
|
with (
|
||||||
storage,
|
patch.object(
|
||||||
"get_reticulum_config_path",
|
storage,
|
||||||
return_value=Path(temp_dir) / "reticulum",
|
"get_reticulum_config_path",
|
||||||
), patch(
|
return_value=Path(temp_dir) / "reticulum",
|
||||||
"pathlib.Path.write_text",
|
),
|
||||||
side_effect=PermissionError("Access denied"),
|
patch(
|
||||||
|
"pathlib.Path.write_text",
|
||||||
|
side_effect=PermissionError("Access denied"),
|
||||||
|
),
|
||||||
):
|
):
|
||||||
config_content = "test config content"
|
config_content = "test config content"
|
||||||
result = storage.save_config(config_content)
|
result = storage.save_config(config_content)
|
||||||
@@ -196,7 +212,8 @@ class TestStorageManager:
|
|||||||
assert result is True
|
assert result is True
|
||||||
# Check that the config was set to client storage
|
# Check that the config was set to client storage
|
||||||
mock_page.client_storage.set.assert_any_call(
|
mock_page.client_storage.set.assert_any_call(
|
||||||
"ren_browser_config", config_content,
|
"ren_browser_config",
|
||||||
|
config_content,
|
||||||
)
|
)
|
||||||
# Verify that client storage was called at least once
|
# Verify that client storage was called at least once
|
||||||
assert mock_page.client_storage.set.call_count >= 1
|
assert mock_page.client_storage.set.call_count >= 1
|
||||||
@@ -354,10 +371,13 @@ class TestStorageManager:
|
|||||||
with patch.object(StorageManager, "_get_storage_directory") as mock_get_dir:
|
with patch.object(StorageManager, "_get_storage_directory") as mock_get_dir:
|
||||||
mock_get_dir.return_value = Path("/nonexistent/path")
|
mock_get_dir.return_value = Path("/nonexistent/path")
|
||||||
|
|
||||||
with patch(
|
with (
|
||||||
"pathlib.Path.mkdir",
|
patch(
|
||||||
side_effect=[PermissionError("Access denied"), None],
|
"pathlib.Path.mkdir",
|
||||||
), patch("tempfile.gettempdir", return_value="/tmp"):
|
side_effect=[PermissionError("Access denied"), None],
|
||||||
|
),
|
||||||
|
patch("tempfile.gettempdir", return_value="/tmp"),
|
||||||
|
):
|
||||||
storage = StorageManager()
|
storage = StorageManager()
|
||||||
|
|
||||||
expected_fallback = Path("/tmp") / "ren_browser"
|
expected_fallback = Path("/tmp") / "ren_browser"
|
||||||
@@ -444,7 +464,8 @@ class TestStorageManagerEdgeCases:
|
|||||||
storage = StorageManager()
|
storage = StorageManager()
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"pathlib.Path.write_text", side_effect=PermissionError("Access denied"),
|
"pathlib.Path.write_text",
|
||||||
|
side_effect=PermissionError("Access denied"),
|
||||||
):
|
):
|
||||||
test_path = Path("/mock/path")
|
test_path = Path("/mock/path")
|
||||||
result = storage._is_writable(test_path)
|
result = storage._is_writable(test_path)
|
||||||
|
|||||||
@@ -105,7 +105,9 @@ class TestTabsManager:
|
|||||||
"""Test that selecting a tab updates background colors correctly."""
|
"""Test that selecting a tab updates background colors correctly."""
|
||||||
tabs_manager._add_tab_internal("Tab 2", Mock())
|
tabs_manager._add_tab_internal("Tab 2", Mock())
|
||||||
|
|
||||||
tab_controls = tabs_manager.tab_bar.content.controls[:-2] # Exclude add/close buttons
|
tab_controls = tabs_manager.tab_bar.content.controls[
|
||||||
|
:-2
|
||||||
|
] # Exclude add/close buttons
|
||||||
|
|
||||||
tabs_manager.select_tab(1)
|
tabs_manager.select_tab(1)
|
||||||
|
|
||||||
@@ -195,7 +197,9 @@ class TestTabsManager:
|
|||||||
"""Test that tab click handlers are properly set."""
|
"""Test that tab click handlers are properly set."""
|
||||||
tabs_manager._add_tab_internal("Tab 2", Mock())
|
tabs_manager._add_tab_internal("Tab 2", Mock())
|
||||||
|
|
||||||
tab_controls = tabs_manager.tab_bar.content.controls[:-2] # Exclude add/close buttons
|
tab_controls = tabs_manager.tab_bar.content.controls[
|
||||||
|
:-2
|
||||||
|
] # Exclude add/close buttons
|
||||||
|
|
||||||
for i, control in enumerate(tab_controls):
|
for i, control in enumerate(tab_controls):
|
||||||
assert control.on_click is not None
|
assert control.on_click is not None
|
||||||
@@ -240,7 +244,7 @@ class TestTabsManager:
|
|||||||
def test_adaptive_overflow_behavior(self, tabs_manager):
|
def test_adaptive_overflow_behavior(self, tabs_manager):
|
||||||
"""Test that the overflow menu adapts to tab changes."""
|
"""Test that the overflow menu adapts to tab changes."""
|
||||||
# With page width at 800, add enough tabs that some should overflow.
|
# With page width at 800, add enough tabs that some should overflow.
|
||||||
for i in range(10): # Total 11 tabs
|
for i in range(10): # Total 11 tabs
|
||||||
tabs_manager._add_tab_internal(f"Tab {i + 2}", Mock())
|
tabs_manager._add_tab_internal(f"Tab {i + 2}", Mock())
|
||||||
|
|
||||||
# Check that an overflow menu exists
|
# Check that an overflow menu exists
|
||||||
@@ -249,13 +253,21 @@ class TestTabsManager:
|
|||||||
# Simulate a smaller screen, expecting more tabs to overflow
|
# Simulate a smaller screen, expecting more tabs to overflow
|
||||||
tabs_manager.page.width = 400
|
tabs_manager.page.width = 400
|
||||||
tabs_manager._update_tab_visibility()
|
tabs_manager._update_tab_visibility()
|
||||||
visible_tabs_small = sum(1 for c in tabs_manager.tab_bar.content.controls if isinstance(c, ft.Container) and c.visible)
|
visible_tabs_small = sum(
|
||||||
|
1
|
||||||
|
for c in tabs_manager.tab_bar.content.controls
|
||||||
|
if isinstance(c, ft.Container) and c.visible
|
||||||
|
)
|
||||||
assert visible_tabs_small < 11
|
assert visible_tabs_small < 11
|
||||||
|
|
||||||
# Simulate a larger screen, expecting all tabs to be visible
|
# Simulate a larger screen, expecting all tabs to be visible
|
||||||
tabs_manager.page.width = 1600
|
tabs_manager.page.width = 1600
|
||||||
tabs_manager._update_tab_visibility()
|
tabs_manager._update_tab_visibility()
|
||||||
visible_tabs_large = sum(1 for c in tabs_manager.tab_bar.content.controls if isinstance(c, ft.Container) and c.visible)
|
visible_tabs_large = sum(
|
||||||
|
1
|
||||||
|
for c in tabs_manager.tab_bar.content.controls
|
||||||
|
if isinstance(c, ft.Container) and c.visible
|
||||||
|
)
|
||||||
|
|
||||||
assert visible_tabs_large == 11
|
assert visible_tabs_large == 11
|
||||||
assert tabs_manager.overflow_menu is None
|
assert tabs_manager.overflow_menu is None
|
||||||
|
|||||||
@@ -29,7 +29,12 @@ class TestBuildUI:
|
|||||||
@patch("ren_browser.tabs.tabs.TabsManager")
|
@patch("ren_browser.tabs.tabs.TabsManager")
|
||||||
@patch("ren_browser.controls.shortcuts.Shortcuts")
|
@patch("ren_browser.controls.shortcuts.Shortcuts")
|
||||||
def test_build_ui_appbar_setup(
|
def test_build_ui_appbar_setup(
|
||||||
self, mock_shortcuts, mock_tabs, mock_fetcher, mock_announce_service, mock_page,
|
self,
|
||||||
|
mock_shortcuts,
|
||||||
|
mock_tabs,
|
||||||
|
mock_fetcher,
|
||||||
|
mock_announce_service,
|
||||||
|
mock_page,
|
||||||
):
|
):
|
||||||
"""Test that build_ui sets up the app bar correctly."""
|
"""Test that build_ui sets up the app bar correctly."""
|
||||||
mock_tab_manager = Mock()
|
mock_tab_manager = Mock()
|
||||||
@@ -51,7 +56,12 @@ class TestBuildUI:
|
|||||||
@patch("ren_browser.tabs.tabs.TabsManager")
|
@patch("ren_browser.tabs.tabs.TabsManager")
|
||||||
@patch("ren_browser.controls.shortcuts.Shortcuts")
|
@patch("ren_browser.controls.shortcuts.Shortcuts")
|
||||||
def test_build_ui_drawer_setup(
|
def test_build_ui_drawer_setup(
|
||||||
self, mock_shortcuts, mock_tabs, mock_fetcher, mock_announce_service, mock_page,
|
self,
|
||||||
|
mock_shortcuts,
|
||||||
|
mock_tabs,
|
||||||
|
mock_fetcher,
|
||||||
|
mock_announce_service,
|
||||||
|
mock_page,
|
||||||
):
|
):
|
||||||
"""Test that build_ui sets up the drawer correctly."""
|
"""Test that build_ui sets up the drawer correctly."""
|
||||||
mock_tab_manager = Mock()
|
mock_tab_manager = Mock()
|
||||||
|
|||||||
Reference in New Issue
Block a user