Skip to content

Commit 1741b03

Browse files
Update app.py
1 parent f5ba2d2 commit 1741b03

1 file changed

Lines changed: 75 additions & 12 deletions

File tree

src/bulkfolder/ui/app.py

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,76 +32,117 @@
3232
from .views.large_files_page import LargeFilesPage
3333
from .views.about_page import AboutPage
3434

35+
3536
class SplashScreen(ctk.CTkToplevel):
37+
""" Écran de chargement. """
3638
def __init__(self, master, logo_path):
3739
super().__init__(master)
3840
self.overrideredirect(True)
3941
self.attributes("-topmost", True)
4042
self.configure(fg_color=DR_BG)
43+
4144
width, height = 340, 380
4245
x = (self.winfo_screenwidth() // 2) - (width // 2)
4346
y = (self.winfo_screenheight() // 2) - (height // 2)
4447
self.geometry(f"{width}x{height}+{x}+{y}")
48+
4549
self.grid_columnconfigure(0, weight=1)
4650
self.grid_rowconfigure(0, weight=1)
51+
4752
inner = ctk.CTkFrame(self, fg_color="transparent")
4853
inner.grid(row=0, column=0)
54+
4955
if logo_path and logo_path.exists():
50-
img = Image.open(logo_path)
51-
self.photo = ctk.CTkImage(light_image=img, dark_image=img, size=(120, 120))
52-
ctk.CTkLabel(inner, text="", image=self.photo).pack(pady=(0, 20))
56+
try:
57+
img = Image.open(logo_path)
58+
self.photo = ctk.CTkImage(light_image=img, dark_image=img, size=(120, 120))
59+
ctk.CTkLabel(inner, text="", image=self.photo).pack(pady=(0, 20))
60+
except Exception: pass
61+
5362
ctk.CTkLabel(inner, text="BulkFolder", font=ctk.CTkFont(size=26, weight="bold"), text_color=DR_TEXT).pack()
5463
ctk.CTkLabel(inner, text="Organize & Rename safely", font=ctk.CTkFont(size=13), text_color=DR_MUTED).pack(pady=(0, 20))
64+
5565
self.pb = ctk.CTkProgressBar(inner, width=220, progress_color=DR_PURPLE, fg_color=DR_BORDER)
5666
self.pb.pack(pady=(5, 0))
5767
self.pb.set(0)
5868
self.pb.start()
5969

70+
6071
class App(ctk.CTk):
6172
def __init__(self):
73+
# OPTIMISATION : DPI Awareness pour la fluidité (multi-écran)
6274
try:
6375
if sys.platform.startswith("win"):
6476
import ctypes
6577
ctypes.windll.shcore.SetProcessDpiAwareness(1)
6678
except Exception: pass
79+
6780
super().__init__()
6881
self.withdraw()
82+
83+
# Bloqueur de saccades pour le redimensionnement (resize)
6984
self._resize_after_id = None
85+
7086
self.settings: AppSettings = load_settings()
87+
7188
ctk.set_appearance_mode("dark")
89+
ctk.set_default_color_theme("blue")
90+
91+
try:
92+
scale_val = float(self.settings.ui_scaling.replace("%", "")) / 100.0
93+
ctk.set_widget_scaling(scale_val)
94+
ctk.set_window_scaling(scale_val)
95+
except Exception: pass
96+
7297
self.title("BulkFolder")
7398
self.geometry("1240x800")
7499
self.minsize(1020, 700)
75100
self.configure(fg_color=DR_BG)
101+
102+
# Liaison du redimensionnement intelligent (Smart Resize)
76103
self.bind("<Configure>", self._smart_resize)
104+
77105
self.logo_path = Path(__file__).resolve().parent.parent.parent / "assets" / "logo.png"
78106
self._ensure_logo_exists(self.logo_path)
107+
79108
self.ui_state = UIState()
80109
self.last_plan = None
81110
self.last_scan = None
111+
self.renamer_plan = []
112+
self.chunker_plan = []
113+
114+
# Configuration de la grille
82115
self.grid_columnconfigure(0, weight=0)
83116
self.grid_columnconfigure(1, weight=1)
84117
self.grid_rowconfigure(0, weight=1)
118+
85119
self.splash = SplashScreen(self, self.logo_path)
86120
self.splash.update()
121+
87122
info = get_project_info()
88123
self.sidebar_view = SidebarView(info, self, on_page=self.switch_page, logo_path=self.logo_path)
89124
self.sidebar_view.grid(row=0, column=0, rowspan=2, sticky="nsw")
125+
90126
self.content_area = ctk.CTkFrame(self, corner_radius=0, fg_color=DR_BG)
91127
self.content_area.grid(row=0, column=1, sticky="nsew")
92128
self.content_area.grid_columnconfigure(0, weight=1)
93129
self.content_area.grid_rowconfigure(1, weight=1)
94130
self.content_area.grid_rowconfigure(2, weight=0)
131+
95132
self.topbar_view = TopbarView(self.content_area, on_toggle_sidebar=self.toggle_terminal)
96133
self.topbar_view.grid(row=0, column=0, sticky="ew", padx=18, pady=(18, 8))
134+
97135
self.page_container = ctk.CTkFrame(self.content_area, corner_radius=0, fg_color=DR_BG)
98136
self.page_container.grid(row=1, column=0, sticky="nsew")
99137
self.page_container.grid_columnconfigure(0, weight=1)
100138
self.page_container.grid_rowconfigure(0, weight=1)
139+
101140
self.logs_view = LogsView(self.content_area, on_close=self.toggle_terminal)
102141
self.logs_view.grid(row=2, column=0, sticky="ew", padx=18, pady=(0, 18))
103142
self._terminal_visible = True
104143
self.ui_state.log_view = self.logs_view
144+
145+
# Initialisation de toutes les pages (UI Originale)
105146
self.pages: dict[str, ctk.CTkFrame] = {}
106147
self.pages["Organizer"] = self._build_page_organizer(self.page_container)
107148
self.pages["Renamer"] = self._build_page_renamer(self.page_container)
@@ -114,29 +155,35 @@ def __init__(self):
114155
self.pages["LargeFiles"] = self._build_page_large_files(self.page_container)
115156
self.pages["Settings"] = self._build_page_settings(self.page_container)
116157
self.pages["About"] = self._build_page_about(self.page_container)
158+
117159
self._current_page = ""
118160
self.switch_page("Organizer")
161+
162+
self.log("System initialized.", level="DEBUG")
119163
self.after(2000, self._show_main_window)
120164

121165
def _smart_resize(self, event):
166+
""" Évite le rendu saccadé en attendant 50ms de stabilité. """
122167
if event.widget == self:
123-
if self._resize_after_id: self.after_cancel(self._resize_after_id)
168+
if self._resize_after_id:
169+
self.after_cancel(self._resize_after_id)
124170
self._resize_after_id = self.after(50, self._do_refresh)
125171

126172
def _do_refresh(self):
127173
self.update_idletasks()
128174
self._resize_after_id = None
129175

130-
@staticmethod
131-
def _ensure_logo_exists(png_path: Path):
132-
ico_path = png_path.with_suffix(".ico")
176+
def _ensure_logo_exists(self, png_path: Path):
177+
""" Génère et charge l'icône .ico. """
133178
if not png_path.exists(): return
179+
ico_path = png_path.with_suffix(".ico")
134180
try:
135181
img = Image.open(png_path).convert("RGBA")
136182
bbox = img.getbbox()
137183
if bbox: img = img.crop(bbox)
138184
layers = [img.resize((s, s), Image.Resampling.LANCZOS) for s in [256, 128, 64, 48, 32, 16]]
139185
layers[0].save(ico_path, format="ICO", append_images=layers[1:])
186+
self.iconbitmap(str(ico_path))
140187
except Exception: pass
141188

142189
def _show_main_window(self):
@@ -145,27 +192,41 @@ def _show_main_window(self):
145192
self.deiconify()
146193

147194
def _build_page_organizer(self, parent) -> ctk.CTkFrame:
195+
""" Conserve l'UI originale avec le Panel à gauche. """
148196
frame = ctk.CTkFrame(parent, corner_radius=0, fg_color=DR_BG)
149-
frame.grid_columnconfigure(0, weight=0); frame.grid_columnconfigure(1, weight=1); frame.grid_rowconfigure(0, weight=1)
150-
self.organizer_panel = OrganizerPanel(frame,
197+
frame.grid_columnconfigure(0, weight=0)
198+
frame.grid_columnconfigure(1, weight=1)
199+
frame.grid_rowconfigure(0, weight=1)
200+
201+
# Panel de contrôle à gauche
202+
self.organizer_panel = OrganizerPanel(
203+
frame,
151204
on_choose_folder=lambda: actions.choose_folder(self),
152205
on_scan=lambda: actions.scan_and_plan(self),
153206
on_apply=lambda: actions.apply_plan(self),
154207
on_undo=lambda: actions.undo_last_ops(self),
155208
on_toggle_subfolders=lambda enabled: actions.toggle_subfolders(self, enabled),
156209
)
157210
self.organizer_panel.grid(row=0, column=0, sticky="ns", padx=(18, 10), pady=(0, 18))
211+
212+
# Zone de droite (Cards + Tabs)
158213
right = ctk.CTkFrame(frame, corner_radius=0, fg_color=DR_BG)
159214
right.grid(row=0, column=1, sticky="nsew", padx=(10, 18), pady=(0, 18))
160-
right.grid_columnconfigure(0, weight=1); right.grid_rowconfigure(2, weight=1)
215+
right.grid_columnconfigure(0, weight=1)
216+
right.grid_rowconfigure(2, weight=1)
217+
161218
self.cards_view = CardsRow(right)
162219
self.cards_view.grid(row=0, column=0, sticky="ew", pady=(0, 8))
220+
163221
self.tabs = ctk.CTkTabview(right, fg_color=DR_BG)
164222
self.tabs.grid(row=2, column=0, sticky="nsew", pady=(8, 0))
223+
165224
self.dashboard_view = DashboardView(self.tabs.add("Dashboard"))
166225
self.dashboard_view.pack(fill="both", expand=True)
226+
167227
self.preview_view = PreviewView(self.tabs.add("Preview"))
168228
self.preview_view.pack(fill="both", expand=True)
229+
169230
return frame
170231

171232
def _build_page_renamer(self, p): return RenamerPage(p, on_choose_folder=lambda: actions.renamer_choose_folder(self), on_preview=lambda: actions.renamer_preview(self), on_apply=lambda: actions.renamer_apply(self))
@@ -189,9 +250,11 @@ def switch_page(self, page_name: str) -> None:
189250

190251
def toggle_terminal(self) -> None:
191252
if self._terminal_visible:
192-
self.logs_view.grid_forget(); self._terminal_visible = False
253+
self.logs_view.grid_forget()
254+
self._terminal_visible = False
193255
else:
194-
self.logs_view.grid(row=2, column=0, sticky="ew", padx=18, pady=(0, 18)); self._terminal_visible = True
256+
self.logs_view.grid(row=2, column=0, sticky="ew", padx=18, pady=(0, 18))
257+
self._terminal_visible = True
195258

196259
def set_status(self, s: str) -> None: self.topbar_view.set_status(s)
197260
def log(self, s: str, level: str = "INFO") -> None: self.ui_state.log(s, level=level)

0 commit comments

Comments
 (0)