clapp-pm 1.0.42__py3-none-any.whl → 1.0.44__py3-none-any.whl

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 (30) hide show
  1. {clapp_pm-1.0.42.data → clapp_pm-1.0.44.data}/data/version.json +1 -1
  2. {clapp_pm-1.0.42.dist-info → clapp_pm-1.0.44.dist-info}/METADATA +1 -1
  3. {clapp_pm-1.0.42.dist-info → clapp_pm-1.0.44.dist-info}/RECORD +30 -9
  4. packages/pycloudos/README.md +279 -0
  5. packages/pycloudos/core/appmon.py +0 -0
  6. packages/pycloudos/main.py +193 -0
  7. packages/pycloudos/manifest.json +15 -0
  8. packages/pycloudos/pycloud_fs/home/Desktop/test_desktop_file.txt +11 -0
  9. packages/pycloudos/pycloud_fs/home/default/Desktop/test_dosya.txt +1 -0
  10. packages/pycloudos/pycloud_fs/home/default/Desktop/test_script.py +11 -0
  11. packages/pycloudos/rain/__init__.py +7 -0
  12. packages/pycloudos/rain/contextmenu.py +1370 -0
  13. packages/pycloudos/rain/desktop.py +556 -0
  14. packages/pycloudos/rain/dock.py +722 -0
  15. packages/pycloudos/rain/flet_html_widgets.py +1448 -0
  16. packages/pycloudos/rain/theme.py +930 -0
  17. packages/pycloudos/rain/topbar.py +1421 -0
  18. packages/pycloudos/rain/ui.py +381 -0
  19. packages/pycloudos/rain/wallpaper.py +830 -0
  20. packages/pycloudos/rain/widgets.py +688 -0
  21. packages/pycloudos/rain/windowmanager.py +605 -0
  22. packages/pycloudos/requirements-dev.txt +43 -0
  23. packages/pycloudos/requirements.txt +43 -0
  24. packages/pycloudos/setup_deps.py +422 -0
  25. publish_command.py +45 -61
  26. version.py +1 -1
  27. {clapp_pm-1.0.42.dist-info → clapp_pm-1.0.44.dist-info}/WHEEL +0 -0
  28. {clapp_pm-1.0.42.dist-info → clapp_pm-1.0.44.dist-info}/entry_points.txt +0 -0
  29. {clapp_pm-1.0.42.dist-info → clapp_pm-1.0.44.dist-info}/licenses/LICENSE +0 -0
  30. {clapp_pm-1.0.42.dist-info → clapp_pm-1.0.44.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1421 @@
1
+ """
2
+ Rain Topbar - Modern Üst Çubuk Bileşeni
3
+ Sistem kontrol butonları, saat, bildirimler, denetim merkezi
4
+ macOS Big Sur/Monterey tarzında modern tasarım
5
+ HTML widget'ları ile hibrit yaklaşım
6
+ """
7
+
8
+ import logging
9
+ from datetime import datetime
10
+ from typing import Optional
11
+ from pathlib import Path
12
+
13
+ try:
14
+ from PyQt6.QtWidgets import (QWidget, QHBoxLayout, QVBoxLayout, QLabel, QPushButton,
15
+ QMenu, QSystemTrayIcon, QSpacerItem, QSizePolicy, QApplication,
16
+ QFrame, QSlider, QCheckBox, QGraphicsDropShadowEffect, QScrollArea)
17
+ from PyQt6.QtCore import Qt, QTimer, pyqtSignal, QPropertyAnimation, QEasingCurve, QRect, QSize
18
+ from PyQt6.QtGui import QFont, QIcon, QPixmap, QAction, QPainter, QColor
19
+ PYQT_AVAILABLE = True
20
+ except ImportError:
21
+ PYQT_AVAILABLE = False
22
+
23
+ # HTML widget'larını import et
24
+ try:
25
+ from rain.flet_html_widgets import (
26
+ HTMLNotificationWidget, HTMLClockWidget,
27
+ HTMLControlCenterWidget, HTMLCloudSearchWidget
28
+ )
29
+ HTML_WIDGETS_AVAILABLE = True
30
+ except ImportError:
31
+ HTML_WIDGETS_AVAILABLE = False
32
+
33
+ class RainTopbar(QWidget):
34
+ """Rain UI Topbar bileşeni - HTML widget'ları ile hibrit"""
35
+
36
+ # Sinyaller
37
+ cloud_menu_requested = pyqtSignal()
38
+ settings_requested = pyqtSignal()
39
+ shutdown_requested = pyqtSignal()
40
+
41
+ def __init__(self, kernel):
42
+ super().__init__()
43
+ self.kernel = kernel
44
+ self.logger = logging.getLogger("RainTopbar")
45
+
46
+ if not PYQT_AVAILABLE:
47
+ return
48
+
49
+ self.setup_ui()
50
+ self.setup_timer()
51
+ self.setup_connections()
52
+
53
+ def setup_ui(self):
54
+ """macOS tarzında tek parça topbar arayüzü"""
55
+ self.setFixedHeight(28) # macOS topbar yüksekliği
56
+
57
+ # macOS tarzında tek parça topbar stili - renk gradyanı tüm topbar'da
58
+ self.setStyleSheet("""
59
+ QWidget {
60
+ background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
61
+ stop:0 rgba(240, 240, 240, 0.98),
62
+ stop:1 rgba(220, 220, 220, 0.98));
63
+ border-bottom: 1px solid rgba(180, 180, 180, 0.8);
64
+ color: #333333;
65
+ }
66
+
67
+ QPushButton {
68
+ background: transparent;
69
+ border: none;
70
+ padding: 4px 12px;
71
+ color: #333333;
72
+ font-size: 13px;
73
+ font-weight: 500;
74
+ border-radius: 4px;
75
+ }
76
+
77
+ QPushButton:hover {
78
+ background: rgba(0, 0, 0, 0.1);
79
+ }
80
+
81
+ QPushButton:pressed {
82
+ background: rgba(0, 0, 0, 0.2);
83
+ }
84
+
85
+ QLabel {
86
+ color: #333333;
87
+ font-size: 13px;
88
+ background-color: transparent;
89
+ font-weight: 500;
90
+ }
91
+ """)
92
+
93
+ # Ana layout
94
+ layout = QHBoxLayout(self)
95
+ layout.setContentsMargins(8, 0, 8, 0)
96
+ layout.setSpacing(0)
97
+
98
+ # Sol taraf - Sabit sistem butonları
99
+ left_widget = QWidget()
100
+ left_widget.setStyleSheet("""
101
+ QWidget {
102
+ background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
103
+ stop:0 rgba(240, 240, 240, 0.98),
104
+ stop:1 rgba(220, 220, 220, 0.98));
105
+ }
106
+ """)
107
+ left_layout = QHBoxLayout(left_widget)
108
+ left_layout.setContentsMargins(0, 0, 0, 0)
109
+ left_layout.setSpacing(0)
110
+
111
+ # PyCloud butonu (Apple logosu gibi)
112
+ self.cloud_button = QPushButton("☁️")
113
+ self.cloud_button.setFixedWidth(40)
114
+ self.cloud_button.setStyleSheet("""
115
+ QPushButton {
116
+ font-size: 16px;
117
+ padding: 4px 8px;
118
+ text-align: center;
119
+ background: transparent;
120
+ }
121
+ """)
122
+ self.cloud_button.clicked.connect(self.show_cloud_menu)
123
+ left_layout.addWidget(self.cloud_button)
124
+
125
+ # Uygulamalar butonu
126
+ self.apps_button = QPushButton("Uygulamalar")
127
+ self.apps_button.setStyleSheet("""
128
+ QPushButton {
129
+ background: transparent;
130
+ }
131
+ """)
132
+ self.apps_button.clicked.connect(self.show_applications)
133
+ left_layout.addWidget(self.apps_button)
134
+
135
+ layout.addWidget(left_widget)
136
+
137
+ # Orta kısım - Dinamik uygulama menüleri
138
+ self.app_menu_widget = QWidget()
139
+ self.app_menu_widget.setStyleSheet("""
140
+ QWidget {
141
+ background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
142
+ stop:0 rgba(240, 240, 240, 0.98),
143
+ stop:1 rgba(220, 220, 220, 0.98));
144
+ }
145
+ """)
146
+ self.app_menu_layout = QHBoxLayout(self.app_menu_widget)
147
+ self.app_menu_layout.setContentsMargins(20, 0, 20, 0)
148
+ self.app_menu_layout.setSpacing(0)
149
+
150
+ # Varsayılan boş durum
151
+ self.clear_app_menus()
152
+
153
+ layout.addWidget(self.app_menu_widget)
154
+
155
+ # Esnek alan - orta kısmı genişletmek için
156
+ layout.addStretch()
157
+
158
+ # Sağ taraf - Sabit sistem kontrolleri - daha geniş alan
159
+ right_widget = QWidget()
160
+ right_widget.setStyleSheet("""
161
+ QWidget {
162
+ background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
163
+ stop:0 rgba(240, 240, 240, 0.98),
164
+ stop:1 rgba(220, 220, 220, 0.98));
165
+ }
166
+ """)
167
+ right_layout = QHBoxLayout(right_widget)
168
+ right_layout.setContentsMargins(0, 0, 0, 0)
169
+ right_layout.setSpacing(12) # Widget'lar arası boşluk artırıldı
170
+
171
+ # Sistem durumu
172
+ self.system_status = QLabel("●")
173
+ self.system_status.setStyleSheet("""
174
+ QLabel {
175
+ color: #00aa00;
176
+ font-size: 12px;
177
+ background: transparent;
178
+ }
179
+ """)
180
+ self.system_status.setToolTip("Sistem Durumu: Çalışıyor")
181
+ right_layout.addWidget(self.system_status)
182
+
183
+ # CloudSearch butonu - yeni eklenen
184
+ self.cloudsearch_button = QPushButton("🔍")
185
+ self.cloudsearch_button.setMinimumWidth(35)
186
+ self.cloudsearch_button.setStyleSheet("""
187
+ QPushButton {
188
+ background: transparent;
189
+ min-width: 35px;
190
+ text-align: center;
191
+ font-size: 14px;
192
+ }
193
+ """)
194
+ self.cloudsearch_button.clicked.connect(self.show_flet_cloudsearch_widget)
195
+ self.cloudsearch_button.setToolTip("CloudSearch - Dosya ve İçerik Arama")
196
+ # Özel ikon yükleme
197
+ self.load_cloudsearch_icon()
198
+ right_layout.addWidget(self.cloudsearch_button)
199
+
200
+ # Saat butonu - daha geniş alan
201
+ self.clock_button = QPushButton()
202
+ self.clock_button.setMinimumWidth(120) # Yatay düzen için daha geniş
203
+ self.clock_button.setStyleSheet("""
204
+ QPushButton {
205
+ font-weight: 600;
206
+ padding: 4px 12px;
207
+ background: transparent;
208
+ min-width: 120px;
209
+ text-align: center;
210
+ font-size: 12px;
211
+ }
212
+ """)
213
+ self.clock_button.clicked.connect(self.show_flet_clock_widget)
214
+ self.update_clock()
215
+ right_layout.addWidget(self.clock_button)
216
+
217
+ # Bildirimler butonu - daha geniş alan
218
+ self.notifications_button = QPushButton("🔔")
219
+ self.notifications_button.setMinimumWidth(35) # Genişlik artırıldı
220
+ self.notifications_button.setStyleSheet("""
221
+ QPushButton {
222
+ background: transparent;
223
+ min-width: 35px;
224
+ text-align: center;
225
+ }
226
+ """)
227
+ self.notifications_button.clicked.connect(self.show_flet_notification_widget)
228
+ # Özel ikon yükleme
229
+ self.load_notification_icon()
230
+ right_layout.addWidget(self.notifications_button)
231
+
232
+ # Denetim merkezi butonu - daha geniş alan
233
+ self.control_center_button = QPushButton("⚙️")
234
+ self.control_center_button.setMinimumWidth(35) # Genişlik artırıldı
235
+ self.control_center_button.setStyleSheet("""
236
+ QPushButton {
237
+ background: transparent;
238
+ min-width: 35px;
239
+ text-align: center;
240
+ }
241
+ """)
242
+ self.control_center_button.clicked.connect(self.show_flet_control_center_widget)
243
+ # Özel ikon yükleme
244
+ self.load_control_center_icon()
245
+ right_layout.addWidget(self.control_center_button)
246
+
247
+ layout.addWidget(right_widget)
248
+
249
+ # Widget'ları başlat
250
+ self.current_app_id = None
251
+
252
+ def setup_timer(self):
253
+ """Zamanlayıcıları kur"""
254
+ from PyQt6.QtWidgets import QApplication
255
+
256
+ # QApplication kontrolü
257
+ if QApplication.instance() is None:
258
+ self.logger.warning("QApplication not ready for timers")
259
+ return
260
+
261
+ try:
262
+ # Saat güncelleyici
263
+ self.clock_timer = QTimer(self)
264
+ self.clock_timer.timeout.connect(self.update_clock)
265
+ self.clock_timer.start(1000) # Her saniye
266
+
267
+ # Sistem durumu güncelleyici
268
+ self.status_timer = QTimer(self)
269
+ self.status_timer.timeout.connect(self.update_system_status)
270
+ self.status_timer.start(5000) # Her 5 saniye
271
+
272
+ self.logger.info("Topbar timers started successfully")
273
+
274
+ except Exception as e:
275
+ self.logger.error(f"Timer setup failed: {e}")
276
+
277
+ def cleanup(self):
278
+ """Temizlik işlemleri"""
279
+ try:
280
+ # Tüm HTML widget'ları gizle
281
+ self.hide_all_html_widgets()
282
+
283
+ # Timer'ları durdur
284
+ if hasattr(self, 'clock_timer') and self.clock_timer:
285
+ self.clock_timer.stop()
286
+ self.clock_timer.deleteLater()
287
+ self.clock_timer = None
288
+
289
+ if hasattr(self, 'status_timer') and self.status_timer:
290
+ self.status_timer.stop()
291
+ self.status_timer.deleteLater()
292
+ self.status_timer = None
293
+
294
+ except Exception as e:
295
+ self.logger.error(f"Cleanup failed: {e}")
296
+ pass
297
+
298
+ def setup_connections(self):
299
+ """Sinyal bağlantılarını kur"""
300
+ try:
301
+ from core.events import subscribe, SystemEvents
302
+ subscribe(SystemEvents.USER_LOGIN, self.on_user_login)
303
+ subscribe(SystemEvents.USER_LOGOUT, self.on_user_logout)
304
+ subscribe(SystemEvents.NOTIFICATION_SHOW, self.on_notification)
305
+ except ImportError:
306
+ self.logger.warning("Event system not available")
307
+
308
+ def update_clock(self):
309
+ """Saati güncelle"""
310
+ try:
311
+ # Widget'ın hala geçerli olup olmadığını kontrol et
312
+ if not hasattr(self, 'clock_button') or not self.clock_button:
313
+ return
314
+
315
+ # Widget'ın silinip silinmediğini kontrol et
316
+ try:
317
+ # Widget'a erişmeye çalış
318
+ self.clock_button.isVisible()
319
+ except (RuntimeError, AttributeError):
320
+ # Widget silinmiş, timer'ı durdur
321
+ if hasattr(self, 'clock_timer') and self.clock_timer:
322
+ self.clock_timer.stop()
323
+ return
324
+
325
+ now = datetime.now()
326
+ time_str = now.strftime("%H:%M")
327
+ date_str = now.strftime("%d %b")
328
+
329
+ # QLabel'ın hala geçerli olduğunu kontrol et
330
+ try:
331
+ # Yatay düzen - saat ve tarih yan yana
332
+ self.clock_button.setText(f"{time_str} {date_str}")
333
+ except (RuntimeError, AttributeError):
334
+ # Widget silinmiş, timer'ı durdur
335
+ if hasattr(self, 'clock_timer') and self.clock_timer:
336
+ self.clock_timer.stop()
337
+ return
338
+
339
+ except Exception as e:
340
+ self.logger.error(f"Failed to update clock: {e}")
341
+
342
+ def update_system_status(self):
343
+ """Sistem durumunu güncelle"""
344
+ if self.kernel and self.kernel.running:
345
+ uptime = self.kernel.get_uptime()
346
+ hours = int(uptime // 3600)
347
+ minutes = int((uptime % 3600) // 60)
348
+
349
+ self.system_status.setStyleSheet("color: #00ff00; font-size: 16px;")
350
+ self.system_status.setToolTip(f"Sistem Durumu: Çalışıyor\nÇalışma Süresi: {hours:02d}:{minutes:02d}")
351
+ else:
352
+ self.system_status.setStyleSheet("color: #ff0000; font-size: 16px;")
353
+ self.system_status.setToolTip("Sistem Durumu: Hata")
354
+
355
+ def show_cloud_menu(self):
356
+ """Bulut menüsünü göster"""
357
+ menu = QMenu(self)
358
+ menu.setStyleSheet("""
359
+ QMenu {
360
+ background-color: rgba(45, 45, 45, 0.95);
361
+ border: 1px solid rgba(80, 80, 80, 0.8);
362
+ border-radius: 8px;
363
+ padding: 6px;
364
+ min-width: 250px;
365
+ color: #ffffff;
366
+ }
367
+
368
+ QMenu::item {
369
+ background-color: transparent;
370
+ padding: 10px 18px;
371
+ border-radius: 6px;
372
+ margin: 1px;
373
+ color: #ffffff;
374
+ }
375
+
376
+ QMenu::item:selected {
377
+ background-color: rgba(70, 70, 70, 0.8);
378
+ }
379
+
380
+ QMenu::separator {
381
+ height: 1px;
382
+ background-color: rgba(100, 100, 100, 0.6);
383
+ margin: 6px 12px;
384
+ }
385
+ """)
386
+
387
+ # Uygulamalar
388
+ apps_action = QAction("📱 Uygulamalar", self)
389
+ apps_action.triggered.connect(self.show_applications)
390
+ menu.addAction(apps_action)
391
+
392
+ # App Store
393
+ appstore_action = QAction("🏪 App Store", self)
394
+ appstore_action.triggered.connect(self.show_appstore)
395
+ menu.addAction(appstore_action)
396
+
397
+ menu.addSeparator()
398
+
399
+ # Dosyalar
400
+ files_action = QAction("📁 Dosyalar", self)
401
+ files_action.triggered.connect(self.show_files)
402
+ menu.addAction(files_action)
403
+
404
+ # Terminal
405
+ terminal_action = QAction("💻 Terminal", self)
406
+ terminal_action.triggered.connect(self.show_terminal)
407
+ menu.addAction(terminal_action)
408
+
409
+ menu.addSeparator()
410
+
411
+ # Sistem Ayarları
412
+ settings_action = QAction("⚙️ Sistem Ayarları", self)
413
+ settings_action.triggered.connect(self.show_settings)
414
+ menu.addAction(settings_action)
415
+
416
+ # Görev Yöneticisi
417
+ taskmanager_action = QAction("📊 Görev Yöneticisi", self)
418
+ taskmanager_action.triggered.connect(self.show_task_manager)
419
+ menu.addAction(taskmanager_action)
420
+
421
+ menu.addSeparator()
422
+
423
+ # Yeniden Başlat
424
+ restart_action = QAction("🔄 Yeniden Başlat", self)
425
+ restart_action.triggered.connect(self.restart_system)
426
+ menu.addAction(restart_action)
427
+
428
+ # Kapat
429
+ shutdown_action = QAction("⏻ Kapat", self)
430
+ shutdown_action.triggered.connect(self.shutdown_system)
431
+ menu.addAction(shutdown_action)
432
+
433
+ # Menüyü göster
434
+ button_rect = self.cloud_button.geometry()
435
+ menu.exec(self.mapToGlobal(button_rect.bottomLeft()))
436
+
437
+ def show_user_menu(self):
438
+ """Kullanıcı menüsünü göster"""
439
+ menu = QMenu(self)
440
+ menu.setStyleSheet(self.cloud_button.parent().styleSheet())
441
+
442
+ # Mevcut kullanıcı bilgisi
443
+ current_user = None
444
+ if self.kernel:
445
+ user_manager = self.kernel.get_module("users")
446
+ if user_manager:
447
+ current_user = user_manager.get_current_user()
448
+
449
+ if current_user:
450
+ user_info = QAction(f"👤 {current_user.display_name}", self)
451
+ user_info.setEnabled(False)
452
+ menu.addAction(user_info)
453
+
454
+ menu.addSeparator()
455
+
456
+ # Profil Ayarları
457
+ profile_action = QAction("👤 Profil Ayarları", self)
458
+ profile_action.triggered.connect(self.show_profile_settings)
459
+ menu.addAction(profile_action)
460
+
461
+ # Kullanıcı Değiştir
462
+ switch_action = QAction("🔄 Kullanıcı Değiştir", self)
463
+ switch_action.triggered.connect(self.switch_user)
464
+ menu.addAction(switch_action)
465
+
466
+ # Çıkış Yap
467
+ logout_action = QAction("🚪 Çıkış Yap", self)
468
+ logout_action.triggered.connect(self.logout_user)
469
+ menu.addAction(logout_action)
470
+
471
+ # Menüyü göster
472
+ button_rect = self.control_center_button.geometry()
473
+ menu.exec(self.mapToGlobal(button_rect.bottomLeft()))
474
+
475
+ def show_notifications(self):
476
+ """Bildirimleri göster"""
477
+ self.logger.info("Notifications requested")
478
+
479
+ # Test bildirimleri göster
480
+ try:
481
+ notify_manager = self.kernel.get_module("notify")
482
+ if notify_manager:
483
+ from core.notify import NotificationType, NotificationPriority
484
+
485
+ # Bilgi bildirimi
486
+ notify_manager.show_notification(
487
+ "Sistem Bildirimi",
488
+ "PyCloud OS bildirim sistemi test ediliyor!",
489
+ NotificationType.INFO,
490
+ NotificationPriority.NORMAL,
491
+ source="Topbar"
492
+ )
493
+
494
+ # Başarı bildirimi
495
+ notify_manager.show_notification(
496
+ "İşlem Başarılı",
497
+ "Bildirim sistemi başarıyla çalışıyor.",
498
+ NotificationType.SUCCESS,
499
+ NotificationPriority.HIGH,
500
+ source="Topbar"
501
+ )
502
+
503
+ # Uyarı bildirimi
504
+ notify_manager.show_notification(
505
+ "Dikkat",
506
+ "Bu bir test uyarı bildirimidir.",
507
+ NotificationType.WARNING,
508
+ NotificationPriority.NORMAL,
509
+ source="Topbar"
510
+ )
511
+
512
+ except Exception as e:
513
+ self.logger.error(f"Failed to show test notifications: {e}")
514
+
515
+ # TODO: Bildirim geçmişi paneli
516
+
517
+ def show_applications(self):
518
+ """Uygulamaları göster"""
519
+ self.logger.info("Applications requested")
520
+ # Uygulama listesi menüsü göster - App Explorer kullan
521
+ try:
522
+ if self.kernel:
523
+ app_explorer = self.kernel.get_module("appexplorer")
524
+ if app_explorer:
525
+ self.show_app_explorer_menu()
526
+ else:
527
+ # Fallback: App Store aç
528
+ self._launch_app("app_store")
529
+ else:
530
+ self._launch_app("app_store")
531
+ except Exception as e:
532
+ self.logger.error(f"Failed to show applications: {e}")
533
+ self._launch_app("app_store")
534
+
535
+ def show_app_explorer_menu(self):
536
+ """App Explorer menüsünü göster"""
537
+ try:
538
+ app_explorer = self.kernel.get_module("appexplorer")
539
+ if not app_explorer:
540
+ return
541
+
542
+ menu = QMenu(self)
543
+ menu.setStyleSheet("""
544
+ QMenu {
545
+ background-color: rgba(45, 45, 45, 0.95);
546
+ border: 1px solid rgba(80, 80, 80, 0.8);
547
+ border-radius: 8px;
548
+ padding: 6px;
549
+ min-width: 250px;
550
+ color: #ffffff;
551
+ }
552
+
553
+ QMenu::item {
554
+ background-color: transparent;
555
+ padding: 10px 18px;
556
+ border-radius: 6px;
557
+ margin: 1px;
558
+ color: #ffffff;
559
+ }
560
+
561
+ QMenu::item:selected {
562
+ background-color: rgba(70, 70, 70, 0.8);
563
+ }
564
+
565
+ QMenu::separator {
566
+ height: 1px;
567
+ background-color: rgba(100, 100, 100, 0.6);
568
+ margin: 6px 12px;
569
+ }
570
+ """)
571
+
572
+ # Kategori bazlı uygulamalar
573
+ all_apps = app_explorer.get_all_apps()
574
+ categories = {}
575
+
576
+ # Uygulamaları kategorilere ayır
577
+ for app in all_apps:
578
+ if app.status.value == "indexed": # Sadece geçerli uygulamalar
579
+ category = app.category or "Diğer"
580
+ if category not in categories:
581
+ categories[category] = []
582
+ categories[category].append(app)
583
+
584
+ # Her kategori için alt menü oluştur
585
+ for category, apps in sorted(categories.items()):
586
+ if apps: # Boş kategorileri atla
587
+ category_menu = menu.addMenu(f"📁 {category}")
588
+ category_menu.setStyleSheet(menu.styleSheet())
589
+
590
+ # Kategorideki uygulamaları listele (en fazla 10 tane)
591
+ for app in sorted(apps, key=lambda x: x.name)[:10]:
592
+ # İkon yükle
593
+ icon = QIcon()
594
+ if app.icon_path and Path(app.icon_path).exists():
595
+ pixmap = QPixmap(app.icon_path)
596
+ if not pixmap.isNull():
597
+ # İkonu yüksek kalitede 16x16 boyutuna getir
598
+ scaled_pixmap = pixmap.scaled(
599
+ 16, 16,
600
+ Qt.AspectRatioMode.KeepAspectRatio,
601
+ Qt.TransformationMode.SmoothTransformation
602
+ )
603
+
604
+ # Şeffaf arka plan ile temiz ikon oluştur
605
+ clean_pixmap = QPixmap(16, 16)
606
+ clean_pixmap.fill(Qt.GlobalColor.transparent)
607
+
608
+ from PyQt6.QtGui import QPainter
609
+ painter = QPainter(clean_pixmap)
610
+ painter.setRenderHint(QPainter.RenderHint.Antialiasing)
611
+ painter.setRenderHint(QPainter.RenderHint.SmoothPixmapTransform)
612
+
613
+ # İkonu ortala
614
+ x = (16 - scaled_pixmap.width()) // 2
615
+ y = (16 - scaled_pixmap.height()) // 2
616
+ painter.drawPixmap(x, y, scaled_pixmap)
617
+ painter.end()
618
+
619
+ icon = QIcon(clean_pixmap)
620
+
621
+ # Action oluştur
622
+ app_action = QAction(app.name, self)
623
+ if not icon.isNull():
624
+ app_action.setIcon(icon)
625
+ app_action.triggered.connect(lambda checked, app_id=app.app_id: self._launch_app(app_id))
626
+ category_menu.addAction(app_action)
627
+
628
+ # Çok fazla uygulama varsa "Daha fazla..." ekle
629
+ if len(apps) > 10:
630
+ more_action = QAction(f"... ve {len(apps) - 10} daha", self)
631
+ more_action.triggered.connect(lambda: self._launch_app("app_store"))
632
+ category_menu.addAction(more_action)
633
+
634
+ # Hiç uygulama yoksa
635
+ if not categories:
636
+ no_apps_action = QAction("Hiç uygulama bulunamadı", self)
637
+ no_apps_action.setEnabled(False)
638
+ menu.addAction(no_apps_action)
639
+
640
+ menu.addSeparator()
641
+
642
+ # App Store'u aç
643
+ appstore_action = QAction("🏪 App Store'u Aç", self)
644
+ appstore_action.triggered.connect(lambda: self._launch_app("app_store"))
645
+ menu.addAction(appstore_action)
646
+
647
+ # Uygulamaları yenile
648
+ refresh_action = QAction("🔄 Uygulamaları Yenile", self)
649
+ refresh_action.triggered.connect(self.refresh_app_explorer)
650
+ menu.addAction(refresh_action)
651
+
652
+ # Menüyü göster
653
+ button_pos = self.cloud_button.mapToGlobal(self.cloud_button.rect().bottomLeft())
654
+ menu.exec(button_pos)
655
+
656
+ except Exception as e:
657
+ self.logger.error(f"Failed to show app explorer menu: {e}")
658
+
659
+ def refresh_app_explorer(self):
660
+ """App Explorer'ı yenile"""
661
+ try:
662
+ app_explorer = self.kernel.get_module("appexplorer")
663
+ if app_explorer:
664
+ app_explorer.force_discovery()
665
+ self.logger.info("App explorer refreshed")
666
+ except Exception as e:
667
+ self.logger.error(f"Failed to refresh app explorer: {e}")
668
+
669
+ def show_appstore(self):
670
+ """App Store'u göster"""
671
+ self.logger.info("App Store requested")
672
+ self._launch_app("app_store")
673
+
674
+ def show_files(self):
675
+ """Dosya yöneticisini göster"""
676
+ self.logger.info("File manager requested")
677
+ self._launch_app("cloud_files")
678
+
679
+ def show_terminal(self):
680
+ """Terminal'i göster"""
681
+ self.logger.info("Terminal requested")
682
+ self._launch_app("cloud_terminal")
683
+
684
+ def show_task_manager(self):
685
+ """Görev yöneticisini göster"""
686
+ self.logger.info("Task manager requested")
687
+ self._launch_app("cloud_taskmanager")
688
+
689
+ def show_profile_settings(self):
690
+ """Profil ayarlarını göster"""
691
+ self.logger.info("Profile settings requested")
692
+ # TODO: Profil ayarları implementasyonu
693
+
694
+ def switch_user(self):
695
+ """Kullanıcı değiştir"""
696
+ self.logger.info("User switch requested")
697
+ # TODO: Kullanıcı değiştirme implementasyonu
698
+
699
+ def logout_user(self):
700
+ """Kullanıcı çıkışı"""
701
+ self.logger.info("User logout requested")
702
+ if self.kernel:
703
+ user_manager = self.kernel.get_module("users")
704
+ if user_manager:
705
+ user_manager.logout()
706
+
707
+ def restart_system(self):
708
+ """Sistemi yeniden başlat"""
709
+ self.logger.info("System restart requested")
710
+ if self.kernel:
711
+ self.kernel.restart()
712
+
713
+ def shutdown_system(self):
714
+ """Sistemi kapat"""
715
+ self.logger.info("System shutdown requested")
716
+ self.shutdown_requested.emit()
717
+ if self.kernel:
718
+ self.kernel.shutdown()
719
+
720
+ def on_user_login(self, event):
721
+ """Kullanıcı giriş olayı"""
722
+ username = event.data.get("username", "")
723
+ self.control_center_button.setText(f"👤 {username}")
724
+ self.logger.info(f"User logged in: {username}")
725
+
726
+ def on_user_logout(self, event):
727
+ """Kullanıcı çıkış olayı"""
728
+ self.control_center_button.setText("👤 Giriş Yap")
729
+ self.logger.info("User logged out")
730
+
731
+ def on_notification(self, event):
732
+ """Bildirim olayı"""
733
+ # Bildirim sayısını güncelle
734
+ # TODO: Bildirim sayacı implementasyonu
735
+ pass
736
+
737
+ def _launch_app(self, app_id: str):
738
+ """Uygulama başlat"""
739
+ try:
740
+ if self.kernel:
741
+ launcher = self.kernel.get_module("launcher")
742
+ if launcher:
743
+ launcher.launch_app(app_id)
744
+ self.logger.info(f"Launched app: {app_id}")
745
+ else:
746
+ self.logger.error("Launcher module not available")
747
+ else:
748
+ self.logger.error("Kernel not available")
749
+ except Exception as e:
750
+ self.logger.error(f"Failed to launch app {app_id}: {e}")
751
+
752
+ def show_settings(self):
753
+ """Ayarları göster"""
754
+ self.logger.info("Settings requested")
755
+ self._launch_app("cloud_settings")
756
+
757
+ def clear_app_menus(self):
758
+ """Uygulama menülerini temizle"""
759
+ # Mevcut widget'ları temizle
760
+ for i in reversed(range(self.app_menu_layout.count())):
761
+ child = self.app_menu_layout.itemAt(i).widget()
762
+ if child:
763
+ child.setParent(None)
764
+
765
+ # Varsayılan boş durum mesajı
766
+ empty_label = QLabel("PyCloud OS")
767
+ empty_label.setStyleSheet("""
768
+ QLabel {
769
+ color: #666666;
770
+ font-weight: 600;
771
+ padding: 4px 12px;
772
+ }
773
+ """)
774
+ self.app_menu_layout.addWidget(empty_label)
775
+
776
+ def set_app_menus(self, app_id: str, menus: list):
777
+ """Belirli bir uygulama için menüleri ayarla"""
778
+ if self.current_app_id == app_id:
779
+ return # Zaten aynı uygulama
780
+
781
+ self.current_app_id = app_id
782
+
783
+ # Mevcut menüleri temizle
784
+ for i in reversed(range(self.app_menu_layout.count())):
785
+ child = self.app_menu_layout.itemAt(i).widget()
786
+ if child:
787
+ child.setParent(None)
788
+
789
+ # Uygulama adını ekle
790
+ app_name_label = QLabel(self.get_app_display_name(app_id))
791
+ app_name_label.setStyleSheet("""
792
+ QLabel {
793
+ color: #333333;
794
+ font-weight: bold;
795
+ padding: 4px 12px;
796
+ }
797
+ """)
798
+ self.app_menu_layout.addWidget(app_name_label)
799
+
800
+ # Menü butonlarını ekle
801
+ for menu_item in menus:
802
+ menu_button = QPushButton(menu_item['title'])
803
+ if 'action' in menu_item:
804
+ menu_button.clicked.connect(menu_item['action'])
805
+ self.app_menu_layout.addWidget(menu_button)
806
+
807
+ def get_app_display_name(self, app_id: str) -> str:
808
+ """Uygulama ID'sinden görünen adı al"""
809
+ app_names = {
810
+ 'cloud_files': 'Dosyalar',
811
+ 'cloud_browser': 'Tarayıcı',
812
+ 'cloud_terminal': 'Terminal',
813
+ 'cloud_notepad': 'Not Defteri',
814
+ 'cloud_pyide': 'Python IDE',
815
+ 'cloud_settings': 'Ayarlar',
816
+ 'cloud_taskmanager': 'Görev Yöneticisi'
817
+ }
818
+ return app_names.get(app_id, app_id)
819
+
820
+ def on_app_focus_changed(self, app_id: str):
821
+ """Uygulama odağı değiştiğinde çağrılır"""
822
+ if not app_id:
823
+ self.clear_app_menus()
824
+ return
825
+
826
+ # Uygulamaya özel menüleri ayarla
827
+ if app_id == 'cloud_files':
828
+ self.set_files_menus()
829
+ elif app_id == 'cloud_browser':
830
+ self.set_browser_menus()
831
+ elif app_id == 'cloud_terminal':
832
+ self.set_terminal_menus()
833
+ elif app_id == 'cloud_notepad':
834
+ self.set_notepad_menus()
835
+ elif app_id == 'cloud_pyide':
836
+ self.set_pyide_menus()
837
+ elif app_id == 'cloud_settings':
838
+ self.set_settings_menus()
839
+ else:
840
+ # Genel uygulama menüleri
841
+ self.set_generic_app_menus(app_id)
842
+
843
+ def set_files_menus(self):
844
+ """Dosyalar uygulaması için menüler"""
845
+ menus = [
846
+ {'title': 'Dosya', 'action': self.show_file_menu},
847
+ {'title': 'Düzenle', 'action': self.show_edit_menu},
848
+ {'title': 'Görünüm', 'action': self.show_view_menu},
849
+ {'title': 'Git', 'action': self.show_go_menu},
850
+ {'title': 'Pencere', 'action': self.show_window_menu}
851
+ ]
852
+ self.set_app_menus('cloud_files', menus)
853
+
854
+ def set_browser_menus(self):
855
+ """Tarayıcı uygulaması için menüler"""
856
+ menus = [
857
+ {'title': 'Dosya', 'action': self.show_browser_file_menu},
858
+ {'title': 'Düzenle', 'action': self.show_browser_edit_menu},
859
+ {'title': 'Görünüm', 'action': self.show_browser_view_menu},
860
+ {'title': 'Geçmiş', 'action': self.show_browser_history_menu},
861
+ {'title': 'Yer İmleri', 'action': self.show_browser_bookmarks_menu},
862
+ {'title': 'Pencere', 'action': self.show_window_menu}
863
+ ]
864
+ self.set_app_menus('cloud_browser', menus)
865
+
866
+ def set_terminal_menus(self):
867
+ """Terminal uygulaması için menüler"""
868
+ menus = [
869
+ {'title': 'Terminal', 'action': self.show_terminal_menu},
870
+ {'title': 'Düzenle', 'action': self.show_edit_menu},
871
+ {'title': 'Görünüm', 'action': self.show_view_menu},
872
+ {'title': 'Pencere', 'action': self.show_window_menu}
873
+ ]
874
+ self.set_app_menus('cloud_terminal', menus)
875
+
876
+ def set_notepad_menus(self):
877
+ """Not Defteri uygulaması için menüler"""
878
+ menus = [
879
+ {'title': 'Dosya', 'action': self.show_notepad_file_menu},
880
+ {'title': 'Düzenle', 'action': self.show_notepad_edit_menu},
881
+ {'title': 'Format', 'action': self.show_notepad_format_menu},
882
+ {'title': 'Görünüm', 'action': self.show_view_menu}
883
+ ]
884
+ self.set_app_menus('cloud_notepad', menus)
885
+
886
+ def set_pyide_menus(self):
887
+ """Python IDE uygulaması için menüler"""
888
+ menus = [
889
+ {'title': 'Dosya', 'action': self.show_pyide_file_menu},
890
+ {'title': 'Düzenle', 'action': self.show_pyide_edit_menu},
891
+ {'title': 'Görünüm', 'action': self.show_view_menu},
892
+ {'title': 'Çalıştır', 'action': self.show_pyide_run_menu},
893
+ {'title': 'Araçlar', 'action': self.show_pyide_tools_menu}
894
+ ]
895
+ self.set_app_menus('cloud_pyide', menus)
896
+
897
+ def set_settings_menus(self):
898
+ """Ayarlar uygulaması için menüler"""
899
+ menus = [
900
+ {'title': 'Ayarlar', 'action': self.show_settings_menu},
901
+ {'title': 'Görünüm', 'action': self.show_view_menu}
902
+ ]
903
+ self.set_app_menus('cloud_settings', menus)
904
+
905
+ def set_generic_app_menus(self, app_id: str):
906
+ """Genel uygulama menüleri"""
907
+ menus = [
908
+ {'title': 'Dosya', 'action': self.show_file_menu},
909
+ {'title': 'Düzenle', 'action': self.show_edit_menu},
910
+ {'title': 'Görünüm', 'action': self.show_view_menu}
911
+ ]
912
+ self.set_app_menus(app_id, menus)
913
+
914
+ # Menü action metodları
915
+ def show_file_menu(self):
916
+ """Dosya menüsünü göster"""
917
+ self.logger.info("File menu requested")
918
+ # TODO: Dosya menüsü implementasyonu
919
+
920
+ def show_edit_menu(self):
921
+ """Düzenle menüsünü göster"""
922
+ self.logger.info("Edit menu requested")
923
+ # TODO: Düzenle menüsü implementasyonu
924
+
925
+ def show_view_menu(self):
926
+ """Görünüm menüsünü göster"""
927
+ self.logger.info("View menu requested")
928
+ # TODO: Görünüm menüsü implementasyonu
929
+
930
+ def show_go_menu(self):
931
+ """Git menüsünü göster"""
932
+ self.logger.info("Go menu requested")
933
+ # TODO: Git menüsü implementasyonu
934
+
935
+ def show_window_menu(self):
936
+ """Pencere menüsünü göster"""
937
+ self.logger.info("Window menu requested")
938
+ # TODO: Pencere menüsü implementasyonu
939
+
940
+ def show_browser_file_menu(self):
941
+ """Tarayıcı dosya menüsünü göster"""
942
+ self.logger.info("Browser file menu requested")
943
+ # TODO: Tarayıcı dosya menüsü implementasyonu
944
+
945
+ def show_browser_edit_menu(self):
946
+ """Tarayıcı düzenle menüsünü göster"""
947
+ self.logger.info("Browser edit menu requested")
948
+ # TODO: Tarayıcı düzenle menüsü implementasyonu
949
+
950
+ def show_browser_view_menu(self):
951
+ """Tarayıcı görünüm menüsünü göster"""
952
+ self.logger.info("Browser view menu requested")
953
+ # TODO: Tarayıcı görünüm menüsü implementasyonu
954
+
955
+ def show_browser_history_menu(self):
956
+ """Tarayıcı geçmiş menüsünü göster"""
957
+ self.logger.info("Browser history menu requested")
958
+ # TODO: Tarayıcı geçmiş menüsü implementasyonu
959
+
960
+ def show_browser_bookmarks_menu(self):
961
+ """Tarayıcı yer imleri menüsünü göster"""
962
+ self.logger.info("Browser bookmarks menu requested")
963
+ # TODO: Tarayıcı yer imleri menüsü implementasyonu
964
+
965
+ def show_terminal_menu(self):
966
+ """Terminal menüsünü göster"""
967
+ self.logger.info("Terminal menu requested")
968
+ # TODO: Terminal menüsü implementasyonu
969
+
970
+ def show_notepad_file_menu(self):
971
+ """Not defteri dosya menüsünü göster"""
972
+ self.logger.info("Notepad file menu requested")
973
+ # TODO: Not defteri dosya menüsü implementasyonu
974
+
975
+ def show_notepad_edit_menu(self):
976
+ """Not defteri düzenle menüsünü göster"""
977
+ self.logger.info("Notepad edit menu requested")
978
+ # TODO: Not defteri düzenle menüsü implementasyonu
979
+
980
+ def show_notepad_format_menu(self):
981
+ """Not defteri format menüsünü göster"""
982
+ self.logger.info("Notepad format menu requested")
983
+ # TODO: Not defteri format menüsü implementasyonu
984
+
985
+ def show_pyide_file_menu(self):
986
+ """Python IDE dosya menüsünü göster"""
987
+ self.logger.info("PyIDE file menu requested")
988
+ # TODO: Python IDE dosya menüsü implementasyonu
989
+
990
+ def show_pyide_edit_menu(self):
991
+ """Python IDE düzenle menüsünü göster"""
992
+ self.logger.info("PyIDE edit menu requested")
993
+ # TODO: Python IDE düzenle menüsü implementasyonu
994
+
995
+ def show_pyide_run_menu(self):
996
+ """Python IDE çalıştır menüsünü göster"""
997
+ self.logger.info("PyIDE run menu requested")
998
+ # TODO: Python IDE çalıştır menüsü implementasyonu
999
+
1000
+ def show_pyide_tools_menu(self):
1001
+ """Python IDE araçlar menüsünü göster"""
1002
+ self.logger.info("PyIDE tools menu requested")
1003
+ # TODO: Python IDE araçlar menüsü implementasyonu
1004
+
1005
+ def show_settings_menu(self):
1006
+ """Ayarlar menüsünü göster"""
1007
+ self.logger.info("Settings menu requested")
1008
+ # TODO: Ayarlar menüsü implementasyonu
1009
+
1010
+ def load_notification_icon(self):
1011
+ """Bildirim butonu için özel ikon yükle"""
1012
+ try:
1013
+ # Özel ikon yolları
1014
+ icon_paths = [
1015
+ "assets/icons/notification.png",
1016
+ "assets/icons/bell.png",
1017
+ "rain/assets/notification.png",
1018
+ "icons/notification.png"
1019
+ ]
1020
+
1021
+ for icon_path in icon_paths:
1022
+ if Path(icon_path).exists():
1023
+ icon = QIcon(icon_path)
1024
+ if not icon.isNull():
1025
+ self.notifications_button.setIcon(icon)
1026
+ self.notifications_button.setText("") # Metni kaldır
1027
+ self.notifications_button.setIconSize(QSize(20, 20))
1028
+ self.logger.info(f"Notification icon loaded from: {icon_path}")
1029
+ return
1030
+
1031
+ # Varsayılan emoji ikon
1032
+ self.notifications_button.setText("🔔")
1033
+ self.logger.info("Using default notification emoji icon")
1034
+
1035
+ except Exception as e:
1036
+ self.logger.error(f"Failed to load notification icon: {e}")
1037
+ self.notifications_button.setText("🔔")
1038
+
1039
+ def load_control_center_icon(self):
1040
+ """Denetim merkezi butonu için özel ikon yükle"""
1041
+ try:
1042
+ # Özel ikon yolları
1043
+ icon_paths = [
1044
+ "assets/icons/settings.png",
1045
+ "assets/icons/control.png",
1046
+ "rain/assets/settings.png",
1047
+ "icons/settings.png"
1048
+ ]
1049
+
1050
+ for icon_path in icon_paths:
1051
+ if Path(icon_path).exists():
1052
+ icon = QIcon(icon_path)
1053
+ if not icon.isNull():
1054
+ self.control_center_button.setIcon(icon)
1055
+ self.control_center_button.setText("") # Metni kaldır
1056
+ self.control_center_button.setIconSize(QSize(20, 20))
1057
+ self.logger.info(f"Control center icon loaded from: {icon_path}")
1058
+ return
1059
+
1060
+ # Varsayılan emoji ikon
1061
+ self.control_center_button.setText("⚙️")
1062
+ self.logger.info("Using default control center emoji icon")
1063
+
1064
+ except Exception as e:
1065
+ self.logger.error(f"Failed to load control center icon: {e}")
1066
+ self.control_center_button.setText("⚙️")
1067
+
1068
+ def set_notification_icon(self, icon_path: str):
1069
+ """Bildirim ikonu manuel olarak ayarla"""
1070
+ try:
1071
+ if Path(icon_path).exists():
1072
+ icon = QIcon(icon_path)
1073
+ if not icon.isNull():
1074
+ self.notifications_button.setIcon(icon)
1075
+ self.notifications_button.setText("")
1076
+ self.notifications_button.setIconSize(QSize(20, 20))
1077
+ self.logger.info(f"Notification icon set to: {icon_path}")
1078
+ return True
1079
+ return False
1080
+ except Exception as e:
1081
+ self.logger.error(f"Failed to set notification icon: {e}")
1082
+ return False
1083
+
1084
+ def set_control_center_icon(self, icon_path: str):
1085
+ """Denetim merkezi ikonu manuel olarak ayarla"""
1086
+ try:
1087
+ if Path(icon_path).exists():
1088
+ icon = QIcon(icon_path)
1089
+ if not icon.isNull():
1090
+ self.control_center_button.setIcon(icon)
1091
+ self.control_center_button.setText("")
1092
+ self.control_center_button.setIconSize(QSize(20, 20))
1093
+ self.logger.info(f"Control center icon set to: {icon_path}")
1094
+ return True
1095
+ return False
1096
+ except Exception as e:
1097
+ self.logger.error(f"Failed to set control center icon: {e}")
1098
+ return False
1099
+
1100
+ def set_cloudsearch_icon(self, icon_path: str):
1101
+ """CloudSearch ikonu manuel olarak ayarla"""
1102
+ try:
1103
+ if Path(icon_path).exists():
1104
+ icon = QIcon(icon_path)
1105
+ if not icon.isNull():
1106
+ self.cloudsearch_button.setIcon(icon)
1107
+ self.cloudsearch_button.setText("")
1108
+ self.cloudsearch_button.setIconSize(QSize(20, 20))
1109
+ self.logger.info(f"CloudSearch icon set to: {icon_path}")
1110
+ return True
1111
+ return False
1112
+ except Exception as e:
1113
+ self.logger.error(f"Failed to set CloudSearch icon: {e}")
1114
+ return False
1115
+
1116
+ def show_flet_notification_widget(self):
1117
+ """Modern HTML bildirim widget'ını göster"""
1118
+ if not HTML_WIDGETS_AVAILABLE:
1119
+ self.logger.warning("HTML widgets not available")
1120
+ return
1121
+
1122
+ try:
1123
+ # Eğer widget zaten açıksa kapat
1124
+ if hasattr(self, 'html_notification_widget') and self.html_notification_widget:
1125
+ self.html_notification_widget.hide()
1126
+ self.html_notification_widget.deleteLater()
1127
+ self.html_notification_widget = None
1128
+ self.logger.info("HTML notification widget closed")
1129
+ return
1130
+
1131
+ # Yeni widget oluştur
1132
+ self.html_notification_widget = HTMLNotificationWidget()
1133
+
1134
+ # Widget kapanma sinyalini bağla
1135
+ self.html_notification_widget.widget_closed.connect(self.on_notification_widget_closed)
1136
+
1137
+ # Widget'ı topbar'ın altında konumlandır - ekran içinde kalacak şekilde
1138
+ topbar_pos = self.mapToGlobal(self.pos())
1139
+ button_pos = self.notifications_button.mapToGlobal(self.notifications_button.pos())
1140
+
1141
+ # Widget boyutları (380x450)
1142
+ widget_width = 380
1143
+ widget_height = 450
1144
+
1145
+ # Ekran boyutlarını al
1146
+ screen = self.screen()
1147
+ screen_geometry = screen.availableGeometry()
1148
+
1149
+ # X konumu - butonun sağından başlayıp widget genişliği kadar sola kaydır
1150
+ widget_x = button_pos.x() - widget_width + self.notifications_button.width()
1151
+
1152
+ # Ekran sınırlarını kontrol et
1153
+ if widget_x < 0:
1154
+ widget_x = 10 # Sol kenara minimum 10px boşluk
1155
+ elif widget_x + widget_width > screen_geometry.width():
1156
+ widget_x = screen_geometry.width() - widget_width - 10 # Sağ kenara minimum 10px boşluk
1157
+
1158
+ # Y konumu - topbar'ın altında
1159
+ widget_y = topbar_pos.y() + self.height() + 10
1160
+
1161
+ # Ekran alt sınırını kontrol et
1162
+ if widget_y + widget_height > screen_geometry.height():
1163
+ widget_y = screen_geometry.height() - widget_height - 10 # Alt kenara minimum 10px boşluk
1164
+
1165
+ self.html_notification_widget.move(widget_x, widget_y)
1166
+ self.html_notification_widget.show_widget()
1167
+
1168
+ self.logger.info(f"HTML notification widget opened at ({widget_x}, {widget_y})")
1169
+
1170
+ except Exception as e:
1171
+ self.logger.error(f"Failed to show HTML notification widget: {e}")
1172
+
1173
+ def show_flet_clock_widget(self):
1174
+ """Modern HTML saat widget'ını göster"""
1175
+ if not HTML_WIDGETS_AVAILABLE:
1176
+ self.logger.warning("HTML widgets not available")
1177
+ return
1178
+
1179
+ try:
1180
+ # Eğer widget zaten açıksa kapat
1181
+ if hasattr(self, 'html_clock_widget') and self.html_clock_widget:
1182
+ self.html_clock_widget.hide()
1183
+ self.html_clock_widget.deleteLater()
1184
+ self.html_clock_widget = None
1185
+ self.logger.info("HTML clock widget closed")
1186
+ return
1187
+
1188
+ # Yeni widget oluştur
1189
+ self.html_clock_widget = HTMLClockWidget()
1190
+
1191
+ # Widget kapanma sinyalini bağla
1192
+ self.html_clock_widget.widget_closed.connect(self.on_clock_widget_closed)
1193
+
1194
+ # Widget'ı topbar'ın altında konumlandır - ekran içinde kalacak şekilde
1195
+ topbar_pos = self.mapToGlobal(self.pos())
1196
+ button_pos = self.clock_button.mapToGlobal(self.clock_button.pos())
1197
+
1198
+ # Widget boyutları (330x400)
1199
+ widget_width = 330
1200
+ widget_height = 400
1201
+
1202
+ # Ekran boyutlarını al
1203
+ screen = self.screen()
1204
+ screen_geometry = screen.availableGeometry()
1205
+
1206
+ # X konumu - butonun ortasından widget'ı ortalamaya çalış
1207
+ widget_x = button_pos.x() + (self.clock_button.width() // 2) - (widget_width // 2)
1208
+
1209
+ # Ekran sınırlarını kontrol et
1210
+ if widget_x < 0:
1211
+ widget_x = 10 # Sol kenara minimum 10px boşluk
1212
+ elif widget_x + widget_width > screen_geometry.width():
1213
+ widget_x = screen_geometry.width() - widget_width - 10 # Sağ kenara minimum 10px boşluk
1214
+
1215
+ # Y konumu - topbar'ın altında
1216
+ widget_y = topbar_pos.y() + self.height() + 10
1217
+
1218
+ # Ekran alt sınırını kontrol et
1219
+ if widget_y + widget_height > screen_geometry.height():
1220
+ widget_y = screen_geometry.height() - widget_height - 10 # Alt kenara minimum 10px boşluk
1221
+
1222
+ self.html_clock_widget.move(widget_x, widget_y)
1223
+ self.html_clock_widget.show_widget()
1224
+
1225
+ self.logger.info(f"HTML clock widget opened at ({widget_x}, {widget_y})")
1226
+
1227
+ except Exception as e:
1228
+ self.logger.error(f"Failed to show HTML clock widget: {e}")
1229
+
1230
+ def show_flet_control_center_widget(self):
1231
+ """Modern HTML denetim merkezi widget'ını göster"""
1232
+ if not HTML_WIDGETS_AVAILABLE:
1233
+ self.logger.warning("HTML widgets not available")
1234
+ return
1235
+
1236
+ try:
1237
+ # Eğer widget zaten açıksa kapat
1238
+ if hasattr(self, 'html_control_widget') and self.html_control_widget:
1239
+ self.html_control_widget.hide()
1240
+ self.html_control_widget.deleteLater()
1241
+ self.html_control_widget = None
1242
+ self.logger.info("HTML control center widget closed")
1243
+ return
1244
+
1245
+ # Yeni widget oluştur
1246
+ self.html_control_widget = HTMLControlCenterWidget()
1247
+
1248
+ # Widget kapanma sinyalini bağla
1249
+ self.html_control_widget.widget_closed.connect(self.on_control_widget_closed)
1250
+
1251
+ # Widget'ı topbar'ın altında konumlandır - ekran içinde kalacak şekilde
1252
+ topbar_pos = self.mapToGlobal(self.pos())
1253
+ button_pos = self.control_center_button.mapToGlobal(self.control_center_button.pos())
1254
+
1255
+ # Widget boyutları (360x520)
1256
+ widget_width = 360
1257
+ widget_height = 520
1258
+
1259
+ # Ekran boyutlarını al
1260
+ screen = self.screen()
1261
+ screen_geometry = screen.availableGeometry()
1262
+
1263
+ # X konumu - butonun sağından başlayıp widget genişliği kadar sola kaydır
1264
+ widget_x = button_pos.x() - widget_width + self.control_center_button.width()
1265
+
1266
+ # Ekran sınırlarını kontrol et
1267
+ if widget_x < 0:
1268
+ widget_x = 10 # Sol kenara minimum 10px boşluk
1269
+ elif widget_x + widget_width > screen_geometry.width():
1270
+ widget_x = screen_geometry.width() - widget_width - 10 # Sağ kenara minimum 10px boşluk
1271
+
1272
+ # Y konumu - topbar'ın altında
1273
+ widget_y = topbar_pos.y() + self.height() + 10
1274
+
1275
+ # Ekran alt sınırını kontrol et
1276
+ if widget_y + widget_height > screen_geometry.height():
1277
+ widget_y = screen_geometry.height() - widget_height - 10 # Alt kenara minimum 10px boşluk
1278
+
1279
+ self.html_control_widget.move(widget_x, widget_y)
1280
+ self.html_control_widget.show_widget()
1281
+
1282
+ self.logger.info(f"HTML control center widget opened at ({widget_x}, {widget_y})")
1283
+
1284
+ except Exception as e:
1285
+ self.logger.error(f"Failed to show HTML control center widget: {e}")
1286
+
1287
+ def show_flet_cloudsearch_widget(self):
1288
+ """Modern HTML CloudSearch widget'ını göster"""
1289
+ if not HTML_WIDGETS_AVAILABLE:
1290
+ self.logger.warning("HTML widgets not available")
1291
+ return
1292
+
1293
+ try:
1294
+ # Eğer widget zaten açıksa kapat
1295
+ if hasattr(self, 'html_search_widget') and self.html_search_widget:
1296
+ self.html_search_widget.hide()
1297
+ self.html_search_widget.deleteLater()
1298
+ self.html_search_widget = None
1299
+ self.logger.info("HTML CloudSearch widget closed")
1300
+ return
1301
+
1302
+ # Yeni widget oluştur
1303
+ self.html_search_widget = HTMLCloudSearchWidget()
1304
+
1305
+ # Widget kapanma sinyalini bağla
1306
+ self.html_search_widget.widget_closed.connect(self.on_search_widget_closed)
1307
+
1308
+ # Widget'ı topbar'ın altında konumlandır - ekran içinde kalacak şekilde
1309
+ topbar_pos = self.mapToGlobal(self.pos())
1310
+ button_pos = self.cloudsearch_button.mapToGlobal(self.cloudsearch_button.pos())
1311
+
1312
+ # Widget boyutları (400x500)
1313
+ widget_width = 400
1314
+ widget_height = 500
1315
+
1316
+ # Ekran boyutlarını al
1317
+ screen = self.screen()
1318
+ screen_geometry = screen.availableGeometry()
1319
+
1320
+ # X konumu - butonun sağından başlayıp widget genişliği kadar sola kaydır
1321
+ widget_x = button_pos.x() - widget_width + self.cloudsearch_button.width()
1322
+
1323
+ # Ekran sınırlarını kontrol et
1324
+ if widget_x < 0:
1325
+ widget_x = 10 # Sol kenara minimum 10px boşluk
1326
+ elif widget_x + widget_width > screen_geometry.width():
1327
+ widget_x = screen_geometry.width() - widget_width - 10 # Sağ kenara minimum 10px boşluk
1328
+
1329
+ # Y konumu - topbar'ın altında
1330
+ widget_y = topbar_pos.y() + self.height() + 10
1331
+
1332
+ # Ekran alt sınırını kontrol et
1333
+ if widget_y + widget_height > screen_geometry.height():
1334
+ widget_y = screen_geometry.height() - widget_height - 10 # Alt kenara minimum 10px boşluk
1335
+
1336
+ self.html_search_widget.move(widget_x, widget_y)
1337
+ self.html_search_widget.show_widget()
1338
+
1339
+ self.logger.info(f"HTML CloudSearch widget opened at ({widget_x}, {widget_y})")
1340
+
1341
+ except Exception as e:
1342
+ self.logger.error(f"Failed to show HTML CloudSearch widget: {e}")
1343
+
1344
+ def on_notification_widget_closed(self):
1345
+ """Bildirim widget'ı kapandığında çağrılır"""
1346
+ if hasattr(self, 'html_notification_widget'):
1347
+ self.html_notification_widget = None
1348
+ self.logger.info("Notification widget closed by outside click")
1349
+
1350
+ def on_clock_widget_closed(self):
1351
+ """Saat widget'ı kapandığında çağrılır"""
1352
+ if hasattr(self, 'html_clock_widget'):
1353
+ self.html_clock_widget = None
1354
+ self.logger.info("Clock widget closed by outside click")
1355
+
1356
+ def on_control_widget_closed(self):
1357
+ """Denetim merkezi widget'ı kapandığında çağrılır"""
1358
+ if hasattr(self, 'html_control_widget'):
1359
+ self.html_control_widget = None
1360
+ self.logger.info("Control center widget closed by outside click")
1361
+
1362
+ def on_search_widget_closed(self):
1363
+ """CloudSearch widget'ı kapandığında çağrılır"""
1364
+ if hasattr(self, 'html_search_widget'):
1365
+ self.html_search_widget = None
1366
+ self.logger.info("CloudSearch widget closed by outside click")
1367
+
1368
+ def hide_all_html_widgets(self):
1369
+ """Tüm HTML widget'larını gizle"""
1370
+ try:
1371
+ # HTML widget'larını gizle
1372
+ if hasattr(self, 'html_notification_widget') and self.html_notification_widget:
1373
+ self.html_notification_widget.hide()
1374
+ self.html_notification_widget.deleteLater()
1375
+ self.html_notification_widget = None
1376
+
1377
+ if hasattr(self, 'html_clock_widget') and self.html_clock_widget:
1378
+ self.html_clock_widget.hide()
1379
+ self.html_clock_widget.deleteLater()
1380
+ self.html_clock_widget = None
1381
+
1382
+ if hasattr(self, 'html_control_widget') and self.html_control_widget:
1383
+ self.html_control_widget.hide()
1384
+ self.html_control_widget.deleteLater()
1385
+ self.html_control_widget = None
1386
+
1387
+ if hasattr(self, 'html_search_widget') and self.html_search_widget:
1388
+ self.html_search_widget.hide()
1389
+ self.html_search_widget.deleteLater()
1390
+ self.html_search_widget = None
1391
+
1392
+ except Exception as e:
1393
+ self.logger.error(f"Failed to hide HTML widgets: {e}")
1394
+
1395
+ def load_cloudsearch_icon(self):
1396
+ """CloudSearch butonu için özel ikon yükle"""
1397
+ try:
1398
+ # Özel ikon yolları
1399
+ icon_paths = [
1400
+ "assets/icons/search.png",
1401
+ "rain/assets/search.png",
1402
+ "icons/search.png"
1403
+ ]
1404
+
1405
+ for icon_path in icon_paths:
1406
+ if Path(icon_path).exists():
1407
+ icon = QIcon(icon_path)
1408
+ if not icon.isNull():
1409
+ self.cloudsearch_button.setIcon(icon)
1410
+ self.cloudsearch_button.setText("") # Metni kaldır
1411
+ self.cloudsearch_button.setIconSize(QSize(20, 20))
1412
+ self.logger.info(f"CloudSearch icon loaded from: {icon_path}")
1413
+ return
1414
+
1415
+ # Varsayılan ikon
1416
+ self.cloudsearch_button.setText("🔍")
1417
+ self.logger.info("Using default CloudSearch icon")
1418
+
1419
+ except Exception as e:
1420
+ self.logger.error(f"Failed to load CloudSearch icon: {e}")
1421
+ self.cloudsearch_button.setText("🔍")