flutter-dev 0.1.6__tar.gz → 0.1.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/CHANGELOG.md +13 -0
  2. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/PKG-INFO +15 -3
  3. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/README.md +14 -2
  4. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/managers/gui.py +137 -30
  5. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/pyproject.toml +1 -1
  6. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/tests/test_gui.py +85 -0
  7. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/.env.example +0 -0
  8. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/LICENSE +0 -0
  9. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/MANIFEST.in +0 -0
  10. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/common_utils.py +0 -0
  11. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/core/__init__.py +0 -0
  12. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/core/constants.py +0 -0
  13. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/core/state.py +0 -0
  14. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/create_page.py +0 -0
  15. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/fdev.py +0 -0
  16. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/flutter_dev.egg-info/SOURCES.txt +0 -0
  17. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/gemini_api.py +0 -0
  18. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/git_diff_output_editor.py +0 -0
  19. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/install_legacy.py +0 -0
  20. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/managers/__init__.py +0 -0
  21. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/managers/ai.py +0 -0
  22. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/managers/app.py +0 -0
  23. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/managers/brew.py +0 -0
  24. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/managers/build.py +0 -0
  25. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/managers/datetime.py +0 -0
  26. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/managers/device.py +0 -0
  27. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/managers/doctor.py +0 -0
  28. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/managers/git.py +0 -0
  29. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/managers/git_account.py +0 -0
  30. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/managers/localization.py +0 -0
  31. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/managers/merge.py +0 -0
  32. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/managers/mirror.py +0 -0
  33. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/managers/package.py +0 -0
  34. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/managers/project.py +0 -0
  35. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/managers/web_deploy.py +0 -0
  36. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/requirements.txt +0 -0
  37. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/setup.cfg +0 -0
  38. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/setup.py +0 -0
  39. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/switch_ai.py +0 -0
  40. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/tests/test_fdev_cli.py +0 -0
  41. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/tests/test_localization.py +0 -0
  42. {flutter_dev-0.1.6 → flutter_dev-0.1.8}/tests/test_package_commands.py +0 -0
@@ -2,6 +2,19 @@
2
2
 
3
3
  All notable changes to this project are documented in this file.
4
4
 
5
+ ## 0.1.8 - 2026-06-25
6
+
7
+ ### Fixed
8
+
9
+ - Made the dashboard command output panel visibly framed with a ready message so the terminal/log area does not appear missing before commands produce output.
10
+
11
+ ## 0.1.7 - 2026-06-25
12
+
13
+ ### Fixed
14
+
15
+ - Reworked the Tkinter dashboard to use classic Tk widgets with explicit colors so `fdev` stays visible on macOS Xcode/system Python runtimes that can render `ttk` widgets as a blank popup.
16
+ - Silenced the macOS system Tk deprecation warning before launching the dashboard.
17
+
5
18
  ## 0.1.6 - 2026-06-25
6
19
 
7
20
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flutter-dev
3
- Version: 0.1.6
3
+ Version: 0.1.8
4
4
  Summary: A cross-platform CLI toolkit for Flutter development workflows.
5
5
  Author: Royal Court BD
6
6
  License-Expression: MIT
@@ -42,7 +42,7 @@ The package is published on PyPI as `flutter-dev` and installs console commands
42
42
  python -m pip install flutter-dev
43
43
  ```
44
44
 
45
- Current package metadata declares version `0.1.6`, Python `>=3.8`, MIT license, and support for macOS, Linux, and Windows.
45
+ Current package metadata declares version `0.1.8`, Python `>=3.8`, MIT license, and support for macOS, Linux, and Windows.
46
46
 
47
47
  ## Key Features
48
48
 
@@ -53,7 +53,7 @@ Current package metadata declares version `0.1.6`, Python `>=3.8`, MIT license,
53
53
  - AI-assisted Git commits using Groq, Mistral, SambaNova, or OpenRouter-compatible chat completion APIs.
54
54
  - Git workflow helpers for version tags, branch sync, deployment branch merge, discard, and GitHub account management through `gh`.
55
55
  - Feature/page generator that creates a `lib/features/<name>` structure using the project's presenter/base-state pattern.
56
- - Small Tkinter desktop dashboard opened by running `fdev` with no command, with live colored command logs.
56
+ - Small Tkinter desktop dashboard opened by running `fdev` with no command, with a framed live command output panel.
57
57
  - Environment diagnostics through `fdev doctor`.
58
58
  - Small utilities for Homebrew cleanup, file merging from `paths.txt`, AI provider switching, PyPI self-upgrade/delete, and git diff prompt export.
59
59
 
@@ -433,6 +433,18 @@ fdev delete
433
433
 
434
434
  Both commands print the detected OS and exact Python executable before running. They use that executable with `-m pip`, not a hardcoded `python`, `python3`, `pip`, or `pip3`, so the active venv/global Python that launched `fdev` is the environment that gets upgraded or deleted. On Windows, `fdev delete` and `fdev upgrade` schedule the same `sys.executable -m pip ...` operation in a delayed command process so the currently running console launcher can exit first.
435
435
 
436
+ ### Blank Dashboard On macOS
437
+
438
+ If `fdev` prints an Xcode/system Tk warning or opens a blank dashboard, upgrade to `flutter-dev` 0.1.7 or newer:
439
+
440
+ ```bash
441
+ fdev upgrade
442
+ ```
443
+
444
+ `fdev` prints the Python executable it is using. If that path is `/Applications/Xcode.app/Contents/Developer/usr/bin/python3`, the CLI is running on Xcode's bundled Python and system Tk; 0.1.7 uses a more conservative Tk UI path for that runtime.
445
+
446
+ If the dashboard opens but the command output area looks missing or empty, upgrade to `flutter-dev` 0.1.8 or newer.
447
+
436
448
  ### Flutter Project Not Detected
437
449
 
438
450
  Run project-specific commands from the directory that contains `pubspec.yaml`.
@@ -8,7 +8,7 @@ The package is published on PyPI as `flutter-dev` and installs console commands
8
8
  python -m pip install flutter-dev
9
9
  ```
10
10
 
11
- Current package metadata declares version `0.1.6`, Python `>=3.8`, MIT license, and support for macOS, Linux, and Windows.
11
+ Current package metadata declares version `0.1.8`, Python `>=3.8`, MIT license, and support for macOS, Linux, and Windows.
12
12
 
13
13
  ## Key Features
14
14
 
@@ -19,7 +19,7 @@ Current package metadata declares version `0.1.6`, Python `>=3.8`, MIT license,
19
19
  - AI-assisted Git commits using Groq, Mistral, SambaNova, or OpenRouter-compatible chat completion APIs.
20
20
  - Git workflow helpers for version tags, branch sync, deployment branch merge, discard, and GitHub account management through `gh`.
21
21
  - Feature/page generator that creates a `lib/features/<name>` structure using the project's presenter/base-state pattern.
22
- - Small Tkinter desktop dashboard opened by running `fdev` with no command, with live colored command logs.
22
+ - Small Tkinter desktop dashboard opened by running `fdev` with no command, with a framed live command output panel.
23
23
  - Environment diagnostics through `fdev doctor`.
24
24
  - Small utilities for Homebrew cleanup, file merging from `paths.txt`, AI provider switching, PyPI self-upgrade/delete, and git diff prompt export.
25
25
 
@@ -399,6 +399,18 @@ fdev delete
399
399
 
400
400
  Both commands print the detected OS and exact Python executable before running. They use that executable with `-m pip`, not a hardcoded `python`, `python3`, `pip`, or `pip3`, so the active venv/global Python that launched `fdev` is the environment that gets upgraded or deleted. On Windows, `fdev delete` and `fdev upgrade` schedule the same `sys.executable -m pip ...` operation in a delayed command process so the currently running console launcher can exit first.
401
401
 
402
+ ### Blank Dashboard On macOS
403
+
404
+ If `fdev` prints an Xcode/system Tk warning or opens a blank dashboard, upgrade to `flutter-dev` 0.1.7 or newer:
405
+
406
+ ```bash
407
+ fdev upgrade
408
+ ```
409
+
410
+ `fdev` prints the Python executable it is using. If that path is `/Applications/Xcode.app/Contents/Developer/usr/bin/python3`, the CLI is running on Xcode's bundled Python and system Tk; 0.1.7 uses a more conservative Tk UI path for that runtime.
411
+
412
+ If the dashboard opens but the command output area looks missing or empty, upgrade to `flutter-dev` 0.1.8 or newer.
413
+
402
414
  ### Flutter Project Not Detected
403
415
 
404
416
  Run project-specific commands from the directory that contains `pubspec.yaml`.
@@ -5,6 +5,7 @@ Small Tkinter GUI for running fdev commands with live logs.
5
5
 
6
6
  from __future__ import annotations
7
7
 
8
+ import os
8
9
  import shlex
9
10
  import subprocess
10
11
  import sys
@@ -37,6 +38,23 @@ ANSI_COLORS = {
37
38
  97: "bright_white",
38
39
  }
39
40
 
41
+ UI_BG = "#f8fafc"
42
+ SIDEBAR_BG = "#e5e7eb"
43
+ PANEL_BG = "#ffffff"
44
+ TEXT_FG = "#111827"
45
+ MUTED_FG = "#475569"
46
+ BUTTON_BG = "#e2e8f0"
47
+ BUTTON_ACTIVE_BG = "#cbd5e1"
48
+ LOG_BG = "#111827"
49
+ LOG_FG = "#e5e7eb"
50
+ LOG_BORDER = "#475569"
51
+ LOG_READY_MESSAGE = "[fdev] Ready. Command output will appear here.\n"
52
+
53
+
54
+ def prepare_tk_environment():
55
+ """Prepare Tk for older macOS system Tk runtimes before importing tkinter."""
56
+ os.environ.setdefault("TK_SILENCE_DEPRECATION", "1")
57
+
40
58
 
41
59
  def _apply_ansi_codes(codes: List[int], current_tag: Optional[str]) -> Optional[str]:
42
60
  if not codes:
@@ -303,86 +321,150 @@ class FdevGui:
303
321
 
304
322
  def _build_widgets(self):
305
323
  import tkinter as tk
306
- from tkinter import ttk
324
+
325
+ self.root.configure(bg=UI_BG)
307
326
 
308
327
  self.root.columnconfigure(1, weight=1)
309
328
  self.root.rowconfigure(0, weight=1)
310
329
 
311
- sidebar = ttk.Frame(self.root, padding=(10, 10))
330
+ sidebar = tk.Frame(self.root, bg=SIDEBAR_BG, padx=10, pady=10)
312
331
  sidebar.grid(row=0, column=0, sticky="ns")
313
332
 
314
- title = ttk.Label(sidebar, text="fdev", font=("TkDefaultFont", 16, "bold"))
333
+ title = tk.Label(
334
+ sidebar,
335
+ text="fdev",
336
+ font=("TkDefaultFont", 16, "bold"),
337
+ bg=SIDEBAR_BG,
338
+ fg=TEXT_FG,
339
+ )
315
340
  title.grid(row=0, column=0, sticky="w", pady=(0, 10))
316
341
 
317
342
  for index, section_name in enumerate(self.sections, start=1):
318
- button = ttk.Button(
343
+ button = tk.Button(
319
344
  sidebar,
320
345
  text=section_name,
321
346
  command=lambda name=section_name: self._show_section(name),
347
+ bg=BUTTON_BG,
348
+ fg=TEXT_FG,
349
+ activebackground=BUTTON_ACTIVE_BG,
350
+ activeforeground=TEXT_FG,
351
+ relief="raised",
352
+ bd=1,
353
+ padx=10,
354
+ pady=4,
322
355
  )
323
356
  button.grid(row=index, column=0, sticky="ew", pady=3)
324
357
 
325
- content = ttk.Frame(self.root, padding=(8, 10, 10, 10))
358
+ content = tk.Frame(self.root, bg=UI_BG, padx=8, pady=10)
326
359
  content.grid(row=0, column=1, sticky="nsew")
327
360
  content.columnconfigure(0, weight=1)
328
361
  content.rowconfigure(1, weight=1)
329
362
 
330
- header = ttk.Frame(content)
363
+ header = tk.Frame(content, bg=UI_BG)
331
364
  header.grid(row=0, column=0, sticky="ew", pady=(0, 8))
332
365
  header.columnconfigure(0, weight=1)
333
366
 
334
- self.section_label = ttk.Label(header, text="", font=("TkDefaultFont", 14, "bold"))
367
+ self.section_label = tk.Label(
368
+ header,
369
+ text="",
370
+ font=("TkDefaultFont", 14, "bold"),
371
+ bg=UI_BG,
372
+ fg=TEXT_FG,
373
+ )
335
374
  self.section_label.grid(row=0, column=0, sticky="w")
336
375
 
337
- self.status_label = ttk.Label(header, text="Ready")
376
+ self.status_label = tk.Label(header, text="Ready", bg=UI_BG, fg=MUTED_FG)
338
377
  self.status_label.grid(row=0, column=1, sticky="e")
339
378
 
340
- body = ttk.Frame(content)
379
+ body = tk.Frame(content, bg=UI_BG)
341
380
  body.grid(row=1, column=0, sticky="nsew")
342
381
  body.columnconfigure(0, weight=1)
343
382
  body.rowconfigure(0, weight=0)
344
383
  body.rowconfigure(1, weight=1)
345
384
 
346
- self.command_frame = ttk.Frame(body, padding=(0, 0, 0, 6))
385
+ self.command_frame = tk.Frame(body, bg=UI_BG, pady=6)
347
386
  self.command_frame.grid(row=0, column=0, sticky="ew")
348
387
  self.command_frame.columnconfigure(0, weight=1)
349
388
  self.command_frame.columnconfigure(1, weight=1)
350
389
 
351
- log_frame = ttk.Frame(body)
352
- log_frame.grid(row=1, column=0, sticky="nsew", pady=(6, 0))
353
- log_frame.columnconfigure(0, weight=1)
354
- log_frame.rowconfigure(0, weight=1)
390
+ self.log_frame = tk.Frame(
391
+ body,
392
+ bg=LOG_BG,
393
+ bd=1,
394
+ relief="solid",
395
+ highlightbackground=LOG_BORDER,
396
+ highlightcolor=LOG_BORDER,
397
+ highlightthickness=1,
398
+ )
399
+ self.log_frame.grid(row=1, column=0, sticky="nsew", pady=(6, 0))
400
+ self.log_frame.columnconfigure(0, weight=1)
401
+ self.log_frame.rowconfigure(1, weight=1)
402
+
403
+ self.log_header = tk.Label(
404
+ self.log_frame,
405
+ text="Command Output",
406
+ bg=LOG_BG,
407
+ fg=LOG_FG,
408
+ anchor="w",
409
+ padx=8,
410
+ pady=4,
411
+ )
412
+ self.log_header.grid(row=0, column=0, columnspan=2, sticky="ew")
355
413
 
356
414
  self.log_text = tk.Text(
357
- log_frame,
415
+ self.log_frame,
358
416
  height=12,
359
417
  wrap="word",
360
418
  state="disabled",
361
- bg="#111827",
362
- fg="#e5e7eb",
363
- insertbackground="#e5e7eb",
419
+ bg=LOG_BG,
420
+ fg=LOG_FG,
421
+ insertbackground=LOG_FG,
422
+ relief="flat",
423
+ bd=0,
424
+ padx=8,
425
+ pady=6,
426
+ highlightthickness=0,
364
427
  )
365
- self.log_text.grid(row=0, column=0, sticky="nsew")
428
+ self.log_text.grid(row=1, column=0, sticky="nsew")
366
429
 
367
- scrollbar = ttk.Scrollbar(log_frame, orient="vertical", command=self.log_text.yview)
368
- scrollbar.grid(row=0, column=1, sticky="ns")
430
+ scrollbar = tk.Scrollbar(self.log_frame, orient="vertical", command=self.log_text.yview)
431
+ scrollbar.grid(row=1, column=1, sticky="ns")
369
432
  self.log_text.configure(yscrollcommand=scrollbar.set)
370
433
  self._configure_log_tags()
434
+ self._append_log(LOG_READY_MESSAGE)
371
435
 
372
- input_bar = ttk.Frame(content)
436
+ input_bar = tk.Frame(content, bg=UI_BG)
373
437
  input_bar.grid(row=2, column=0, sticky="ew", pady=(8, 0))
374
438
  input_bar.columnconfigure(0, weight=1)
375
439
 
376
- self.input_entry = ttk.Entry(input_bar)
440
+ self.input_entry = tk.Entry(input_bar, bg=PANEL_BG, fg=TEXT_FG, insertbackground=TEXT_FG)
377
441
  self.input_entry.grid(row=0, column=0, sticky="ew", padx=(0, 6))
378
442
  self.input_entry.bind("<Return>", lambda _event: self._send_input())
379
443
 
380
- ttk.Button(input_bar, text="Send Input", command=self._send_input).grid(row=0, column=1, padx=(0, 6))
381
- ttk.Button(input_bar, text="Stop", command=self._stop_process).grid(row=0, column=2, padx=(0, 6))
382
- ttk.Button(input_bar, text="Clear", command=self._clear_log).grid(row=0, column=3)
444
+ tk.Button(
445
+ input_bar,
446
+ text="Send Input",
447
+ command=self._send_input,
448
+ bg=BUTTON_BG,
449
+ activebackground=BUTTON_ACTIVE_BG,
450
+ ).grid(row=0, column=1, padx=(0, 6))
451
+ tk.Button(
452
+ input_bar,
453
+ text="Stop",
454
+ command=self._stop_process,
455
+ bg=BUTTON_BG,
456
+ activebackground=BUTTON_ACTIVE_BG,
457
+ ).grid(row=0, column=2, padx=(0, 6))
458
+ tk.Button(
459
+ input_bar,
460
+ text="Clear",
461
+ command=self._clear_log,
462
+ bg=BUTTON_BG,
463
+ activebackground=BUTTON_ACTIVE_BG,
464
+ ).grid(row=0, column=3)
383
465
 
384
466
  def _show_section(self, section_name: str):
385
- from tkinter import ttk
467
+ import tkinter as tk
386
468
 
387
469
  self.current_section = section_name
388
470
  self.section_label.configure(text=section_name)
@@ -394,18 +476,41 @@ class FdevGui:
394
476
  row = index // 2
395
477
  column = index % 2
396
478
 
397
- container = ttk.Frame(self.command_frame, padding=6)
479
+ container = tk.Frame(
480
+ self.command_frame,
481
+ bg=PANEL_BG,
482
+ bd=1,
483
+ relief="solid",
484
+ padx=6,
485
+ pady=6,
486
+ )
398
487
  container.grid(row=row, column=column, sticky="nsew", padx=4, pady=4)
399
488
  container.columnconfigure(0, weight=1)
400
489
 
401
- button = ttk.Button(
490
+ button = tk.Button(
402
491
  container,
403
492
  text=command.label,
404
493
  command=lambda item=command: self._run_command(item),
494
+ bg=BUTTON_BG,
495
+ fg=TEXT_FG,
496
+ activebackground=BUTTON_ACTIVE_BG,
497
+ activeforeground=TEXT_FG,
498
+ relief="raised",
499
+ bd=1,
500
+ padx=8,
501
+ pady=4,
405
502
  )
406
503
  button.grid(row=0, column=0, sticky="ew")
407
504
 
408
- description = ttk.Label(container, text=command.description, wraplength=260)
505
+ description = tk.Label(
506
+ container,
507
+ text=command.description,
508
+ wraplength=260,
509
+ bg=PANEL_BG,
510
+ fg=MUTED_FG,
511
+ justify="left",
512
+ anchor="w",
513
+ )
409
514
  description.grid(row=1, column=0, sticky="w", pady=(4, 0))
410
515
 
411
516
  def _run_command(self, command: GuiCommand):
@@ -489,6 +594,7 @@ class FdevGui:
489
594
  self.log_text.configure(state="normal")
490
595
  self.log_text.delete("1.0", "end")
491
596
  self.log_text.configure(state="disabled")
597
+ self._append_log(LOG_READY_MESSAGE)
492
598
 
493
599
  def _send_input(self):
494
600
  text = self.input_entry.get()
@@ -523,6 +629,7 @@ class FdevGui:
523
629
 
524
630
  def launch_gui() -> int:
525
631
  """Launch the fdev Tkinter dashboard."""
632
+ prepare_tk_environment()
526
633
  try:
527
634
  import tkinter as tk
528
635
  except ImportError:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "flutter-dev"
7
- version = "0.1.6"
7
+ version = "0.1.8"
8
8
  description = "A cross-platform CLI toolkit for Flutter development workflows."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -2,10 +2,12 @@ import sys
2
2
  import unittest
3
3
  from pathlib import Path
4
4
  from tkinter import TclError
5
+ from unittest.mock import patch
5
6
 
6
7
  from managers.gui import (
7
8
  FdevGui,
8
9
  GuiCommand,
10
+ prepare_tk_environment,
9
11
  parse_ansi_segments,
10
12
  build_fdev_command,
11
13
  get_gui_sections,
@@ -144,6 +146,14 @@ class GuiCatalogTests(unittest.TestCase):
144
146
  ["sync", "dev", "main"],
145
147
  )
146
148
 
149
+ def test_prepare_tk_environment_silences_macos_system_tk_warning(self):
150
+ with patch.dict("os.environ", {}, clear=True):
151
+ prepare_tk_environment()
152
+
153
+ import os
154
+
155
+ self.assertEqual(os.environ["TK_SILENCE_DEPRECATION"], "1")
156
+
147
157
  def test_dashboard_uses_stable_grid_layout_without_paned_window(self):
148
158
  try:
149
159
  import tkinter as tk
@@ -172,6 +182,81 @@ class GuiCatalogTests(unittest.TestCase):
172
182
  finally:
173
183
  root.destroy()
174
184
 
185
+ def test_dashboard_maps_initial_widgets_after_mainloop_starts(self):
186
+ try:
187
+ import tkinter as tk
188
+ except ImportError:
189
+ self.skipTest("Tkinter is not available")
190
+
191
+ try:
192
+ root = tk.Tk()
193
+ except TclError as error:
194
+ self.skipTest(f"Tk display is not available: {error}")
195
+
196
+ try:
197
+ app = FdevGui(root)
198
+ root.after(100, root.quit)
199
+ app.run()
200
+
201
+ self.assertTrue(app.command_frame.winfo_ismapped())
202
+ self.assertTrue(app.log_text.winfo_ismapped())
203
+ self.assertGreater(app.command_frame.winfo_width(), 100)
204
+ self.assertGreater(app.log_text.winfo_width(), 100)
205
+ finally:
206
+ root.destroy()
207
+
208
+ def test_dashboard_keeps_terminal_panel_visible_on_launch(self):
209
+ try:
210
+ import tkinter as tk
211
+ except ImportError:
212
+ self.skipTest("Tkinter is not available")
213
+
214
+ try:
215
+ root = tk.Tk()
216
+ except TclError as error:
217
+ self.skipTest(f"Tk display is not available: {error}")
218
+
219
+ try:
220
+ app = FdevGui(root)
221
+ root.update()
222
+
223
+ self.assertTrue(app.log_frame.winfo_ismapped())
224
+ self.assertEqual(app.log_frame.cget("relief"), "solid")
225
+ self.assertIn("[fdev] Ready", app.log_text.get("1.0", "end"))
226
+ finally:
227
+ root.destroy()
228
+
229
+ def test_dashboard_uses_classic_tk_widgets_for_system_tk_compatibility(self):
230
+ try:
231
+ import tkinter as tk
232
+ except ImportError:
233
+ self.skipTest("Tkinter is not available")
234
+
235
+ try:
236
+ root = tk.Tk()
237
+ except TclError as error:
238
+ self.skipTest(f"Tk display is not available: {error}")
239
+
240
+ try:
241
+ app = FdevGui(root)
242
+ root.update_idletasks()
243
+
244
+ widget_classes = {
245
+ widget.winfo_class()
246
+ for widget in _walk_widgets(root)
247
+ }
248
+
249
+ self.assertFalse(
250
+ {"TButton", "TEntry", "TFrame", "TLabel", "TScrollbar"} & widget_classes
251
+ )
252
+ self.assertIn("Button", widget_classes)
253
+ self.assertIn("Label", widget_classes)
254
+ self.assertIn("Entry", widget_classes)
255
+ self.assertIn("Scrollbar", widget_classes)
256
+ self.assertGreater(app.command_frame.winfo_width(), 100)
257
+ finally:
258
+ root.destroy()
259
+
175
260
 
176
261
  def _walk_widgets(widget):
177
262
  yield widget
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes