clapp-pm 1.0.44__py3-none-any.whl → 1.0.45__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.
@@ -1,1448 +0,0 @@
1
- """
2
- Rain Flet HTML Widgets - Flet Widget'larını HTML olarak PyQt6'da göster
3
- Flet widget'larını HTML'e çevirip QWebEngineView'de gösterir
4
- """
5
-
6
- import logging
7
- import tempfile
8
- import os
9
- import json
10
- from pathlib import Path
11
- from typing import Optional
12
- from datetime import datetime
13
-
14
- try:
15
- from PyQt6.QtWidgets import QWidget, QVBoxLayout, QApplication
16
- from PyQt6.QtCore import Qt, QUrl, QTimer, pyqtSignal
17
- from PyQt6.QtWebEngineWidgets import QWebEngineView
18
- from PyQt6.QtWebEngineCore import QWebEngineSettings
19
- from PyQt6.QtGui import QMouseEvent
20
- PYQT_AVAILABLE = True
21
- except ImportError:
22
- PYQT_AVAILABLE = False
23
-
24
- class FletHTMLWidget(QWidget):
25
- """Flet widget'ını HTML olarak gösteren base sınıf"""
26
-
27
- # Widget kapanma sinyali
28
- widget_closed = pyqtSignal()
29
-
30
- def __init__(self, widget_name: str, width: int = 400, height: int = 500):
31
- super().__init__()
32
- self.widget_name = widget_name
33
- self.logger = logging.getLogger(f"FletHTML_{widget_name}")
34
-
35
- if not PYQT_AVAILABLE:
36
- self.logger.error("PyQt6 not available")
37
- return
38
-
39
- self.setFixedSize(width, height)
40
- self.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint)
41
- self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
42
-
43
- # Global mouse event filter'ı kur
44
- self.installEventFilter(self)
45
-
46
- self.setup_ui()
47
-
48
- def setup_ui(self):
49
- """UI kurulumu"""
50
- layout = QVBoxLayout(self)
51
- layout.setContentsMargins(0, 0, 0, 0)
52
-
53
- # Web view oluştur
54
- self.web_view = QWebEngineView()
55
- self.web_view.setStyleSheet("""
56
- QWebEngineView {
57
- background: transparent;
58
- border: none;
59
- }
60
- """)
61
-
62
- # Web engine ayarları
63
- settings = self.web_view.settings()
64
- settings.setAttribute(QWebEngineSettings.WebAttribute.LocalContentCanAccessRemoteUrls, True)
65
- settings.setAttribute(QWebEngineSettings.WebAttribute.LocalContentCanAccessFileUrls, True)
66
-
67
- layout.addWidget(self.web_view)
68
-
69
- def load_html_content(self, html_content: str):
70
- """HTML içeriğini yükle"""
71
- try:
72
- # Geçici HTML dosyası oluştur
73
- temp_file = tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False, encoding='utf-8')
74
- temp_file.write(html_content)
75
- temp_file.close()
76
-
77
- # HTML dosyasını yükle
78
- file_url = QUrl.fromLocalFile(temp_file.name)
79
- self.web_view.load(file_url)
80
-
81
- self.logger.info(f"Loaded HTML content for {self.widget_name}")
82
-
83
- except Exception as e:
84
- self.logger.error(f"Failed to load HTML content: {e}")
85
-
86
- def showEvent(self, event):
87
- """Widget gösterildiğinde global mouse event'leri dinlemeye başla"""
88
- super().showEvent(event)
89
- if QApplication.instance():
90
- QApplication.instance().installEventFilter(self)
91
-
92
- def hideEvent(self, event):
93
- """Widget gizlendiğinde global mouse event'leri dinlemeyi bırak"""
94
- super().hideEvent(event)
95
- if QApplication.instance():
96
- QApplication.instance().removeEventFilter(self)
97
-
98
- def eventFilter(self, obj, event):
99
- """Global event filter - dış tıklamaları yakala"""
100
- if event.type() == event.Type.MouseButtonPress:
101
- # Eğer tıklama bu widget'ın dışındaysa kapat
102
- if not self.geometry().contains(event.globalPosition().toPoint()):
103
- self.close_widget()
104
- return True
105
- return super().eventFilter(obj, event)
106
-
107
- def close_widget(self):
108
- """Widget'ı kapat"""
109
- self.widget_closed.emit()
110
- self.hide()
111
- self.logger.info(f"{self.widget_name} widget closed by outside click")
112
-
113
- class HTMLNotificationWidget(FletHTMLWidget):
114
- """HTML bildirim widget'ı"""
115
-
116
- def __init__(self):
117
- super().__init__("Notification", 380, 450)
118
- self.notifications_data = self.get_notifications_data()
119
-
120
- def get_notifications_data(self):
121
- """Bildirim verilerini al"""
122
- return [
123
- {
124
- "title": "Sistem Bildirimi",
125
- "message": "PyCloud OS başarıyla başlatıldı ve tüm servisler çalışıyor",
126
- "time": "2 dakika önce",
127
- "icon": "📢"
128
- },
129
- {
130
- "title": "Uygulama Güncellemesi",
131
- "message": "Cloud Files v2.1.0 güncellendi",
132
- "time": "1 saat önce",
133
- "icon": "🔄"
134
- },
135
- {
136
- "title": "Güvenlik Uyarısı",
137
- "message": "Yeni giriş denemesi tespit edildi",
138
- "time": "3 saat önce",
139
- "icon": "⚠️"
140
- },
141
- {
142
- "title": "Yedekleme Tamamlandı",
143
- "message": "Haftalık sistem yedeklemesi başarıyla tamamlandı",
144
- "time": "1 gün önce",
145
- "icon": "✅"
146
- }
147
- ]
148
-
149
- def show_widget(self):
150
- """Widget'ı göster"""
151
- html_content = self.generate_notification_html()
152
- self.load_html_content(html_content)
153
- self.show()
154
-
155
- def generate_notification_html(self):
156
- """Bildirim HTML'ini oluştur"""
157
- notifications_html = ""
158
-
159
- for notif in self.notifications_data:
160
- notifications_html += f"""
161
- <div class="notification-item">
162
- <div class="notification-icon">{notif['icon']}</div>
163
- <div class="notification-content">
164
- <div class="notification-title">{notif['title']}</div>
165
- <div class="notification-message">{notif['message']}</div>
166
- </div>
167
- <div class="notification-time">{notif['time']}</div>
168
- </div>
169
- """
170
-
171
- return f"""
172
- <!DOCTYPE html>
173
- <html>
174
- <head>
175
- <meta charset="UTF-8">
176
- <title>Bildirimler</title>
177
- <style>
178
- body {{
179
- margin: 0;
180
- padding: 20px;
181
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
182
- background: rgba(30, 30, 30, 0.98);
183
- color: white;
184
- border-radius: 18px;
185
- border: 2px solid rgba(80, 80, 80, 0.9);
186
- box-shadow: 0 15px 40px rgba(0, 0, 0, 0.3);
187
- width: 340px;
188
- height: 410px;
189
- overflow: hidden;
190
- }}
191
-
192
- .header {{
193
- display: flex;
194
- justify-content: space-between;
195
- align-items: center;
196
- margin-bottom: 16px;
197
- }}
198
-
199
- .title {{
200
- font-size: 20px;
201
- font-weight: bold;
202
- color: white;
203
- }}
204
-
205
- .count {{
206
- background: rgba(0, 120, 255, 0.8);
207
- color: white;
208
- padding: 4px 8px;
209
- border-radius: 10px;
210
- font-size: 12px;
211
- font-weight: bold;
212
- }}
213
-
214
- .notifications-list {{
215
- max-height: 280px;
216
- overflow-y: auto;
217
- margin-bottom: 16px;
218
- }}
219
-
220
- .notification-item {{
221
- background: rgba(45, 45, 45, 0.9);
222
- border: 1px solid rgba(100, 100, 100, 0.5);
223
- border-radius: 12px;
224
- padding: 12px;
225
- margin-bottom: 8px;
226
- display: flex;
227
- align-items: flex-start;
228
- gap: 12px;
229
- transition: background 0.2s;
230
- }}
231
-
232
- .notification-item:hover {{
233
- background: rgba(55, 55, 55, 0.9);
234
- }}
235
-
236
- .notification-icon {{
237
- background: rgba(0, 120, 255, 0.3);
238
- border-radius: 20px;
239
- width: 40px;
240
- height: 40px;
241
- display: flex;
242
- align-items: center;
243
- justify-content: center;
244
- font-size: 20px;
245
- flex-shrink: 0;
246
- }}
247
-
248
- .notification-content {{
249
- flex: 1;
250
- min-width: 0;
251
- }}
252
-
253
- .notification-title {{
254
- font-size: 14px;
255
- font-weight: bold;
256
- color: white;
257
- margin-bottom: 4px;
258
- white-space: nowrap;
259
- overflow: hidden;
260
- text-overflow: ellipsis;
261
- }}
262
-
263
- .notification-message {{
264
- font-size: 12px;
265
- color: #cccccc;
266
- line-height: 1.4;
267
- display: -webkit-box;
268
- -webkit-line-clamp: 2;
269
- -webkit-box-orient: vertical;
270
- overflow: hidden;
271
- }}
272
-
273
- .notification-time {{
274
- font-size: 10px;
275
- color: #888888;
276
- flex-shrink: 0;
277
- text-align: right;
278
- }}
279
-
280
- .buttons {{
281
- display: flex;
282
- gap: 12px;
283
- }}
284
-
285
- .button {{
286
- background: rgba(60, 60, 60, 0.8);
287
- border: 1px solid rgba(120, 120, 120, 0.6);
288
- border-radius: 10px;
289
- padding: 10px 16px;
290
- color: white;
291
- font-weight: 600;
292
- font-size: 13px;
293
- cursor: pointer;
294
- transition: background 0.2s;
295
- text-decoration: none;
296
- display: inline-block;
297
- }}
298
-
299
- .button:hover {{
300
- background: rgba(80, 80, 80, 0.9);
301
- }}
302
-
303
- .button.clear {{
304
- background: rgba(200, 60, 60, 0.8);
305
- }}
306
-
307
- .button.clear:hover {{
308
- background: rgba(220, 80, 80, 0.9);
309
- }}
310
-
311
- .button.settings {{
312
- background: rgba(0, 120, 255, 0.8);
313
- }}
314
-
315
- .button.settings:hover {{
316
- background: rgba(0, 140, 255, 0.9);
317
- }}
318
-
319
- /* Scrollbar styling */
320
- .notifications-list::-webkit-scrollbar {{
321
- width: 8px;
322
- }}
323
-
324
- .notifications-list::-webkit-scrollbar-track {{
325
- background: rgba(60, 60, 60, 0.5);
326
- border-radius: 4px;
327
- }}
328
-
329
- .notifications-list::-webkit-scrollbar-thumb {{
330
- background: rgba(120, 120, 120, 0.8);
331
- border-radius: 4px;
332
- }}
333
-
334
- .notifications-list::-webkit-scrollbar-thumb:hover {{
335
- background: rgba(140, 140, 140, 0.9);
336
- }}
337
- </style>
338
- </head>
339
- <body>
340
- <div class="header">
341
- <div class="title">🔔 Bildirimler</div>
342
- <div class="count">{len(self.notifications_data)}</div>
343
- </div>
344
-
345
- <div class="notifications-list">
346
- {notifications_html}
347
- </div>
348
-
349
- <div class="buttons">
350
- <div class="button clear" onclick="clearNotifications()">🗑️ Temizle</div>
351
- <div class="button settings" onclick="openSettings()">⚙️ Ayarlar</div>
352
- </div>
353
-
354
- <script>
355
- function clearNotifications() {{
356
- alert('🗑️ Bildirimler temizlendi');
357
- }}
358
-
359
- function openSettings() {{
360
- alert('⚙️ Bildirim ayarları açılıyor...');
361
- }}
362
- </script>
363
- </body>
364
- </html>
365
- """
366
-
367
- class HTMLClockWidget(FletHTMLWidget):
368
- """HTML saat widget'ı"""
369
-
370
- def __init__(self):
371
- super().__init__("Clock", 330, 400)
372
-
373
- def show_widget(self):
374
- """Widget'ı göster"""
375
- html_content = self.generate_clock_html()
376
- self.load_html_content(html_content)
377
- self.show()
378
-
379
- # Saati her saniye güncelle
380
- self.timer = QTimer()
381
- self.timer.timeout.connect(self.update_clock)
382
- self.timer.start(1000)
383
-
384
- def update_clock(self):
385
- """Saati güncelle"""
386
- try:
387
- # JavaScript ile saati güncelle
388
- now = datetime.now()
389
- time_str = now.strftime("%H:%M:%S")
390
- js_code = f"document.getElementById('current-time').textContent = '{time_str}';"
391
- self.web_view.page().runJavaScript(js_code)
392
- except Exception as e:
393
- self.logger.error(f"Failed to update clock: {e}")
394
-
395
- def generate_clock_html(self):
396
- """Saat HTML'ini oluştur"""
397
- now = datetime.now()
398
-
399
- return f"""
400
- <!DOCTYPE html>
401
- <html>
402
- <head>
403
- <meta charset="UTF-8">
404
- <title>Saat & Takvim</title>
405
- <style>
406
- body {{
407
- margin: 0;
408
- padding: 20px;
409
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
410
- background: rgba(30, 30, 30, 0.98);
411
- color: white;
412
- border-radius: 18px;
413
- border: 2px solid rgba(80, 80, 80, 0.9);
414
- box-shadow: 0 15px 40px rgba(0, 0, 0, 0.3);
415
- width: 290px;
416
- height: 360px;
417
- overflow: hidden;
418
- }}
419
-
420
- .title {{
421
- font-size: 20px;
422
- font-weight: bold;
423
- color: white;
424
- text-align: center;
425
- margin-bottom: 16px;
426
- }}
427
-
428
- .card {{
429
- background: rgba(45, 45, 45, 0.9);
430
- border: 1px solid rgba(100, 100, 100, 0.5);
431
- border-radius: 16px;
432
- padding: 16px;
433
- margin-bottom: 16px;
434
- }}
435
-
436
- .time-card {{
437
- text-align: center;
438
- }}
439
-
440
- .big-time {{
441
- font-size: 36px;
442
- font-weight: bold;
443
- color: white;
444
- margin-bottom: 8px;
445
- }}
446
-
447
- .date {{
448
- font-size: 16px;
449
- color: #cccccc;
450
- }}
451
-
452
- .calendar-title {{
453
- font-size: 16px;
454
- font-weight: bold;
455
- color: white;
456
- margin-bottom: 12px;
457
- }}
458
-
459
- .month-year {{
460
- font-size: 15px;
461
- font-weight: bold;
462
- text-align: center;
463
- color: white;
464
- margin-bottom: 12px;
465
- }}
466
-
467
- .days-header {{
468
- display: flex;
469
- justify-content: space-around;
470
- background: rgba(60, 60, 60, 0.6);
471
- border-radius: 8px;
472
- padding: 8px;
473
- margin-bottom: 12px;
474
- }}
475
-
476
- .day-name {{
477
- font-size: 11px;
478
- color: #bbbbbb;
479
- text-align: center;
480
- flex: 1;
481
- }}
482
-
483
- .today-highlight {{
484
- background: rgba(0, 200, 100, 0.3);
485
- border: 2px solid rgba(0, 200, 100, 0.6);
486
- border-radius: 10px;
487
- padding: 12px;
488
- display: flex;
489
- align-items: center;
490
- gap: 12px;
491
- }}
492
-
493
- .today-icon {{
494
- font-size: 24px;
495
- color: #00ff88;
496
- }}
497
-
498
- .today-text {{
499
- font-size: 14px;
500
- color: white;
501
- font-weight: bold;
502
- }}
503
-
504
- .timezone-card {{
505
- display: flex;
506
- align-items: center;
507
- gap: 12px;
508
- }}
509
-
510
- .timezone-icon {{
511
- font-size: 20px;
512
- color: white;
513
- }}
514
-
515
- .timezone-text {{
516
- font-size: 14px;
517
- color: #cccccc;
518
- }}
519
- </style>
520
- </head>
521
- <body>
522
- <div class="title">🕐 Saat & Takvim</div>
523
-
524
- <div class="card time-card">
525
- <div class="big-time" id="current-time">{now.strftime("%H:%M:%S")}</div>
526
- <div class="date">{now.strftime("%A, %d %B %Y")}</div>
527
- </div>
528
-
529
- <div class="card">
530
- <div class="calendar-title">📅 Bu Ay</div>
531
- <div class="month-year">{now.strftime("%B %Y")}</div>
532
-
533
- <div class="days-header">
534
- <div class="day-name">Pzt</div>
535
- <div class="day-name">Sal</div>
536
- <div class="day-name">Çar</div>
537
- <div class="day-name">Per</div>
538
- <div class="day-name">Cum</div>
539
- <div class="day-name">Cmt</div>
540
- <div class="day-name">Paz</div>
541
- </div>
542
-
543
- <div class="today-highlight">
544
- <div class="today-icon">📅</div>
545
- <div class="today-text">Bugün: {now.day} {now.strftime('%B')}</div>
546
- </div>
547
- </div>
548
-
549
- <div class="card">
550
- <div class="timezone-card">
551
- <div class="timezone-icon">🌍</div>
552
- <div class="timezone-text">Türkiye Saati (UTC+3)</div>
553
- </div>
554
- </div>
555
- </body>
556
- </html>
557
- """
558
-
559
- class HTMLControlCenterWidget(FletHTMLWidget):
560
- """HTML denetim merkezi widget'ı"""
561
-
562
- def __init__(self):
563
- super().__init__("ControlCenter", 360, 520)
564
-
565
- def show_widget(self):
566
- """Widget'ı göster"""
567
- html_content = self.generate_control_center_html()
568
- self.load_html_content(html_content)
569
- self.show()
570
-
571
- def generate_control_center_html(self):
572
- """Denetim merkezi HTML'ini oluştur - ListView yapısı"""
573
- return """
574
- <!DOCTYPE html>
575
- <html>
576
- <head>
577
- <meta charset="UTF-8">
578
- <title>Denetim Merkezi</title>
579
- <style>
580
- body {
581
- margin: 0;
582
- padding: 20px;
583
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
584
- background: rgba(30, 30, 30, 0.98);
585
- color: white;
586
- border-radius: 18px;
587
- border: 2px solid rgba(80, 80, 80, 0.9);
588
- box-shadow: 0 15px 40px rgba(0, 0, 0, 0.3);
589
- width: 320px;
590
- height: 480px;
591
- overflow: hidden;
592
- display: flex;
593
- flex-direction: column;
594
- }
595
-
596
- .title {
597
- font-size: 20px;
598
- font-weight: bold;
599
- color: white;
600
- text-align: center;
601
- margin-bottom: 16px;
602
- flex-shrink: 0;
603
- }
604
-
605
- .content {
606
- flex: 1;
607
- overflow-y: auto;
608
- padding-right: 5px;
609
- }
610
-
611
- .content::-webkit-scrollbar {
612
- width: 6px;
613
- }
614
-
615
- .content::-webkit-scrollbar-track {
616
- background: rgba(60, 60, 60, 0.3);
617
- border-radius: 3px;
618
- }
619
-
620
- .content::-webkit-scrollbar-thumb {
621
- background: rgba(120, 120, 120, 0.6);
622
- border-radius: 3px;
623
- }
624
-
625
- .content::-webkit-scrollbar-thumb:hover {
626
- background: rgba(140, 140, 140, 0.8);
627
- }
628
-
629
- .section-title {
630
- font-size: 16px;
631
- font-weight: bold;
632
- color: rgba(255, 255, 255, 0.8);
633
- margin: 16px 0 12px 0;
634
- padding-left: 8px;
635
- border-left: 3px solid rgba(0, 120, 255, 0.8);
636
- }
637
-
638
- .list-item {
639
- background: rgba(45, 45, 45, 0.9);
640
- border: 1px solid rgba(100, 100, 100, 0.5);
641
- border-radius: 12px;
642
- padding: 12px 16px;
643
- margin-bottom: 8px;
644
- display: flex;
645
- align-items: center;
646
- justify-content: space-between;
647
- cursor: pointer;
648
- transition: all 0.2s;
649
- }
650
-
651
- .list-item:hover {
652
- background: rgba(55, 55, 55, 0.9);
653
- transform: translateX(2px);
654
- }
655
-
656
- .item-left {
657
- display: flex;
658
- align-items: center;
659
- gap: 12px;
660
- }
661
-
662
- .item-icon {
663
- font-size: 20px;
664
- width: 24px;
665
- text-align: center;
666
- }
667
-
668
- .item-info {
669
- display: flex;
670
- flex-direction: column;
671
- }
672
-
673
- .item-title {
674
- font-size: 14px;
675
- font-weight: bold;
676
- color: white;
677
- margin-bottom: 2px;
678
- }
679
-
680
- .item-subtitle {
681
- font-size: 12px;
682
- color: rgba(255, 255, 255, 0.7);
683
- }
684
-
685
- .item-right {
686
- display: flex;
687
- align-items: center;
688
- gap: 8px;
689
- }
690
-
691
- .toggle-switch {
692
- width: 44px;
693
- height: 24px;
694
- background: rgba(80, 80, 80, 0.8);
695
- border-radius: 12px;
696
- position: relative;
697
- cursor: pointer;
698
- transition: background 0.2s;
699
- }
700
-
701
- .toggle-switch.on {
702
- background: rgba(0, 200, 100, 0.8);
703
- }
704
-
705
- .toggle-switch::after {
706
- content: '';
707
- position: absolute;
708
- width: 20px;
709
- height: 20px;
710
- background: white;
711
- border-radius: 10px;
712
- top: 2px;
713
- left: 2px;
714
- transition: transform 0.2s;
715
- }
716
-
717
- .toggle-switch.on::after {
718
- transform: translateX(20px);
719
- }
720
-
721
- .slider-item {
722
- background: rgba(45, 45, 45, 0.9);
723
- border: 1px solid rgba(100, 100, 100, 0.5);
724
- border-radius: 12px;
725
- padding: 16px;
726
- margin-bottom: 8px;
727
- }
728
-
729
- .slider-header {
730
- display: flex;
731
- justify-content: space-between;
732
- align-items: center;
733
- margin-bottom: 12px;
734
- }
735
-
736
- .slider-title {
737
- font-size: 14px;
738
- font-weight: bold;
739
- color: white;
740
- display: flex;
741
- align-items: center;
742
- gap: 8px;
743
- }
744
-
745
- .slider-value {
746
- font-size: 14px;
747
- color: white;
748
- font-weight: bold;
749
- min-width: 40px;
750
- text-align: right;
751
- }
752
-
753
- .slider {
754
- width: 100%;
755
- height: 8px;
756
- border-radius: 4px;
757
- background: rgba(80, 80, 80, 0.8);
758
- outline: none;
759
- cursor: pointer;
760
- appearance: none;
761
- }
762
-
763
- .slider::-webkit-slider-thumb {
764
- appearance: none;
765
- width: 20px;
766
- height: 20px;
767
- border-radius: 10px;
768
- background: white;
769
- border: 2px solid rgba(0, 120, 255, 0.8);
770
- cursor: pointer;
771
- }
772
-
773
- .system-item {
774
- background: rgba(60, 60, 60, 0.8);
775
- border: 1px solid rgba(120, 120, 120, 0.6);
776
- }
777
-
778
- .system-item.danger {
779
- background: rgba(200, 60, 60, 0.8);
780
- border: 1px solid rgba(200, 60, 60, 0.9);
781
- }
782
-
783
- .system-item:hover {
784
- background: rgba(80, 80, 80, 0.9);
785
- }
786
-
787
- .system-item.danger:hover {
788
- background: rgba(220, 80, 80, 0.9);
789
- }
790
-
791
- .status-badge {
792
- background: rgba(0, 200, 100, 0.8);
793
- color: white;
794
- padding: 2px 8px;
795
- border-radius: 10px;
796
- font-size: 11px;
797
- font-weight: bold;
798
- }
799
-
800
- .status-badge.off {
801
- background: rgba(120, 120, 120, 0.8);
802
- }
803
- </style>
804
- </head>
805
- <body>
806
- <div class="title">⚙️ Denetim Merkezi</div>
807
-
808
- <div class="content">
809
- <div class="section-title">🔧 Hızlı Ayarlar</div>
810
-
811
- <div class="list-item" onclick="toggleWifi()">
812
- <div class="item-left">
813
- <div class="item-icon">📶</div>
814
- <div class="item-info">
815
- <div class="item-title">WiFi</div>
816
- <div class="item-subtitle">Bağlı: PyCloud-Network</div>
817
- </div>
818
- </div>
819
- <div class="item-right">
820
- <div class="toggle-switch on" id="wifi-toggle"></div>
821
- </div>
822
- </div>
823
-
824
- <div class="list-item" onclick="toggleBluetooth()">
825
- <div class="item-left">
826
- <div class="item-icon">🔵</div>
827
- <div class="item-info">
828
- <div class="item-title">Bluetooth</div>
829
- <div class="item-subtitle">Kapalı</div>
830
- </div>
831
- </div>
832
- <div class="item-right">
833
- <div class="toggle-switch" id="bluetooth-toggle"></div>
834
- </div>
835
- </div>
836
-
837
- <div class="list-item" onclick="toggleDarkMode()">
838
- <div class="item-left">
839
- <div class="item-icon">🌙</div>
840
- <div class="item-info">
841
- <div class="item-title">Gece Modu</div>
842
- <div class="item-subtitle">Koyu tema aktif</div>
843
- </div>
844
- </div>
845
- <div class="item-right">
846
- <div class="toggle-switch on" id="darkmode-toggle"></div>
847
- </div>
848
- </div>
849
-
850
- <div class="list-item" onclick="toggleSilent()">
851
- <div class="item-left">
852
- <div class="item-icon">🔕</div>
853
- <div class="item-info">
854
- <div class="item-title">Sessiz Mod</div>
855
- <div class="item-subtitle">Bildirimler kapalı</div>
856
- </div>
857
- </div>
858
- <div class="item-right">
859
- <div class="toggle-switch" id="silent-toggle"></div>
860
- </div>
861
- </div>
862
-
863
- <div class="section-title">🎚️ Ses & Görüntü</div>
864
-
865
- <div class="slider-item">
866
- <div class="slider-header">
867
- <div class="slider-title">
868
- <span>🔊</span>
869
- <span>Ses Seviyesi</span>
870
- </div>
871
- <div class="slider-value" id="volume-value">70%</div>
872
- </div>
873
- <input type="range" min="0" max="100" value="70" class="slider" id="volume-slider" oninput="updateVolume(this.value)">
874
- </div>
875
-
876
- <div class="slider-item">
877
- <div class="slider-header">
878
- <div class="slider-title">
879
- <span>☀️</span>
880
- <span>Parlaklık</span>
881
- </div>
882
- <div class="slider-value" id="brightness-value">80%</div>
883
- </div>
884
- <input type="range" min="0" max="100" value="80" class="slider" id="brightness-slider" oninput="updateBrightness(this.value)">
885
- </div>
886
-
887
- <div class="section-title">⚙️ Sistem</div>
888
-
889
- <div class="list-item system-item" onclick="openSettings()">
890
- <div class="item-left">
891
- <div class="item-icon">⚙️</div>
892
- <div class="item-info">
893
- <div class="item-title">Sistem Ayarları</div>
894
- <div class="item-subtitle">Tüm ayarları yönet</div>
895
- </div>
896
- </div>
897
- <div class="item-right">
898
- <div style="color: rgba(255, 255, 255, 0.5);">›</div>
899
- </div>
900
- </div>
901
-
902
- <div class="list-item system-item" onclick="openTaskManager()">
903
- <div class="item-left">
904
- <div class="item-icon">📊</div>
905
- <div class="item-info">
906
- <div class="item-title">Görev Yöneticisi</div>
907
- <div class="item-subtitle">CPU: 23% | RAM: 45%</div>
908
- </div>
909
- </div>
910
- <div class="item-right">
911
- <div style="color: rgba(255, 255, 255, 0.5);">›</div>
912
- </div>
913
- </div>
914
-
915
- <div class="list-item system-item" onclick="restartSystem()">
916
- <div class="item-left">
917
- <div class="item-icon">🔄</div>
918
- <div class="item-info">
919
- <div class="item-title">Yeniden Başlat</div>
920
- <div class="item-subtitle">Sistemi yeniden başlat</div>
921
- </div>
922
- </div>
923
- <div class="item-right">
924
- <div style="color: rgba(255, 255, 255, 0.5);">›</div>
925
- </div>
926
- </div>
927
-
928
- <div class="list-item system-item danger" onclick="shutdownSystem()">
929
- <div class="item-left">
930
- <div class="item-icon">⏻</div>
931
- <div class="item-info">
932
- <div class="item-title">Sistemi Kapat</div>
933
- <div class="item-subtitle">Güvenli kapatma</div>
934
- </div>
935
- </div>
936
- <div class="item-right">
937
- <div style="color: rgba(255, 255, 255, 0.8);">›</div>
938
- </div>
939
- </div>
940
- </div>
941
-
942
- <script>
943
- function toggleWifi() {
944
- const toggle = document.getElementById('wifi-toggle');
945
- toggle.classList.toggle('on');
946
- const subtitle = toggle.closest('.list-item').querySelector('.item-subtitle');
947
- if (toggle.classList.contains('on')) {
948
- subtitle.textContent = 'Bağlı: PyCloud-Network';
949
- console.log('📶 WiFi açıldı');
950
- } else {
951
- subtitle.textContent = 'Kapalı';
952
- console.log('📶 WiFi kapatıldı');
953
- }
954
- }
955
-
956
- function toggleBluetooth() {
957
- const toggle = document.getElementById('bluetooth-toggle');
958
- toggle.classList.toggle('on');
959
- const subtitle = toggle.closest('.list-item').querySelector('.item-subtitle');
960
- if (toggle.classList.contains('on')) {
961
- subtitle.textContent = 'Açık - Cihaz aranıyor';
962
- console.log('🔵 Bluetooth açıldı');
963
- } else {
964
- subtitle.textContent = 'Kapalı';
965
- console.log('🔵 Bluetooth kapatıldı');
966
- }
967
- }
968
-
969
- function toggleDarkMode() {
970
- const toggle = document.getElementById('darkmode-toggle');
971
- toggle.classList.toggle('on');
972
- const subtitle = toggle.closest('.list-item').querySelector('.item-subtitle');
973
- if (toggle.classList.contains('on')) {
974
- subtitle.textContent = 'Koyu tema aktif';
975
- console.log('🌙 Gece modu açıldı');
976
- } else {
977
- subtitle.textContent = 'Açık tema aktif';
978
- console.log('🌙 Gece modu kapatıldı');
979
- }
980
- }
981
-
982
- function toggleSilent() {
983
- const toggle = document.getElementById('silent-toggle');
984
- toggle.classList.toggle('on');
985
- const subtitle = toggle.closest('.list-item').querySelector('.item-subtitle');
986
- if (toggle.classList.contains('on')) {
987
- subtitle.textContent = 'Bildirimler kapalı';
988
- console.log('🔕 Sessiz mod açıldı');
989
- } else {
990
- subtitle.textContent = 'Bildirimler açık';
991
- console.log('🔕 Sessiz mod kapatıldı');
992
- }
993
- }
994
-
995
- function updateVolume(value) {
996
- document.getElementById('volume-value').textContent = value + '%';
997
- console.log('🔊 Ses seviyesi: ' + value + '%');
998
- }
999
-
1000
- function updateBrightness(value) {
1001
- document.getElementById('brightness-value').textContent = value + '%';
1002
- console.log('☀️ Parlaklık: ' + value + '%');
1003
- }
1004
-
1005
- function openSettings() {
1006
- console.log('⚙️ Sistem ayarları açılıyor...');
1007
- }
1008
-
1009
- function openTaskManager() {
1010
- console.log('📊 Görev yöneticisi açılıyor...');
1011
- }
1012
-
1013
- function restartSystem() {
1014
- if (confirm('Sistemi yeniden başlatmak istediğinizden emin misiniz?')) {
1015
- console.log('🔄 Sistem yeniden başlatılıyor...');
1016
- }
1017
- }
1018
-
1019
- function shutdownSystem() {
1020
- if (confirm('Sistemi kapatmak istediğinizden emin misiniz?')) {
1021
- console.log('⏻ Sistem kapatılıyor...');
1022
- }
1023
- }
1024
- </script>
1025
- </body>
1026
- </html>
1027
- """
1028
-
1029
- class HTMLCloudSearchWidget(FletHTMLWidget):
1030
- """HTML CloudSearch widget'ı"""
1031
-
1032
- def __init__(self):
1033
- super().__init__("CloudSearch", 420, 480)
1034
-
1035
- def show_widget(self):
1036
- """Widget'ı göster"""
1037
- html_content = self.generate_cloudsearch_html()
1038
- self.load_html_content(html_content)
1039
- self.show()
1040
-
1041
- def generate_cloudsearch_html(self):
1042
- """CloudSearch HTML'ini oluştur"""
1043
- return """
1044
- <!DOCTYPE html>
1045
- <html>
1046
- <head>
1047
- <meta charset="UTF-8">
1048
- <title>CloudSearch</title>
1049
- <style>
1050
- body {
1051
- margin: 0;
1052
- padding: 20px;
1053
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
1054
- background: rgba(30, 30, 30, 0.98);
1055
- color: white;
1056
- border-radius: 18px;
1057
- border: 2px solid rgba(80, 80, 80, 0.9);
1058
- box-shadow: 0 15px 40px rgba(0, 0, 0, 0.3);
1059
- width: 380px;
1060
- height: 440px;
1061
- overflow: hidden;
1062
- }
1063
-
1064
- .header {
1065
- display: flex;
1066
- justify-content: space-between;
1067
- align-items: center;
1068
- margin-bottom: 16px;
1069
- }
1070
-
1071
- .title {
1072
- font-size: 20px;
1073
- font-weight: bold;
1074
- color: white;
1075
- }
1076
-
1077
- .open-app-btn {
1078
- background: rgba(156, 39, 176, 0.8);
1079
- border: none;
1080
- border-radius: 8px;
1081
- padding: 8px 12px;
1082
- color: white;
1083
- font-size: 12px;
1084
- cursor: pointer;
1085
- transition: background 0.2s;
1086
- }
1087
-
1088
- .open-app-btn:hover {
1089
- background: rgba(176, 59, 196, 0.9);
1090
- }
1091
-
1092
- .search-container {
1093
- margin-bottom: 16px;
1094
- }
1095
-
1096
- .search-input {
1097
- width: 100%;
1098
- padding: 12px 16px;
1099
- background: rgba(45, 45, 45, 0.9);
1100
- border: 1px solid rgba(100, 100, 100, 0.5);
1101
- border-radius: 12px;
1102
- color: white;
1103
- font-size: 16px;
1104
- outline: none;
1105
- box-sizing: border-box;
1106
- }
1107
-
1108
- .search-input::placeholder {
1109
- color: rgba(255, 255, 255, 0.54);
1110
- }
1111
-
1112
- .search-input:focus {
1113
- border-color: rgba(0, 120, 255, 0.8);
1114
- }
1115
-
1116
- .filters {
1117
- display: flex;
1118
- gap: 8px;
1119
- margin-bottom: 16px;
1120
- overflow-x: auto;
1121
- }
1122
-
1123
- .filter-btn {
1124
- background: rgba(60, 60, 60, 0.8);
1125
- border: 1px solid rgba(120, 120, 120, 0.6);
1126
- border-radius: 15px;
1127
- padding: 6px 12px;
1128
- color: white;
1129
- font-size: 11px;
1130
- cursor: pointer;
1131
- transition: background 0.2s;
1132
- white-space: nowrap;
1133
- }
1134
-
1135
- .filter-btn:hover {
1136
- background: rgba(80, 80, 80, 0.9);
1137
- }
1138
-
1139
- .filter-btn.active {
1140
- background: rgba(0, 120, 255, 0.8);
1141
- }
1142
-
1143
- .results-title {
1144
- font-size: 14px;
1145
- font-weight: bold;
1146
- color: rgba(255, 255, 255, 0.7);
1147
- margin-bottom: 8px;
1148
- }
1149
-
1150
- .results-list {
1151
- max-height: 240px;
1152
- overflow-y: auto;
1153
- margin-bottom: 16px;
1154
- }
1155
-
1156
- .result-item {
1157
- background: rgba(45, 45, 45, 0.9);
1158
- border: 1px solid rgba(100, 100, 100, 0.5);
1159
- border-radius: 10px;
1160
- padding: 10px;
1161
- margin-bottom: 8px;
1162
- display: flex;
1163
- align-items: center;
1164
- gap: 12px;
1165
- cursor: pointer;
1166
- transition: background 0.2s;
1167
- }
1168
-
1169
- .result-item:hover {
1170
- background: rgba(55, 55, 55, 0.9);
1171
- }
1172
-
1173
- .result-icon {
1174
- background: rgba(0, 120, 255, 0.8);
1175
- border-radius: 8px;
1176
- width: 32px;
1177
- height: 32px;
1178
- display: flex;
1179
- align-items: center;
1180
- justify-content: center;
1181
- font-size: 16px;
1182
- flex-shrink: 0;
1183
- }
1184
-
1185
- .result-content {
1186
- flex: 1;
1187
- min-width: 0;
1188
- }
1189
-
1190
- .result-name {
1191
- font-size: 13px;
1192
- font-weight: bold;
1193
- color: white;
1194
- margin-bottom: 2px;
1195
- white-space: nowrap;
1196
- overflow: hidden;
1197
- text-overflow: ellipsis;
1198
- }
1199
-
1200
- .result-path {
1201
- font-size: 10px;
1202
- color: rgba(255, 255, 255, 0.6);
1203
- white-space: nowrap;
1204
- overflow: hidden;
1205
- text-overflow: ellipsis;
1206
- }
1207
-
1208
- .result-meta {
1209
- font-size: 9px;
1210
- color: rgba(255, 255, 255, 0.54);
1211
- display: flex;
1212
- gap: 4px;
1213
- }
1214
-
1215
- .open-btn {
1216
- background: rgba(0, 120, 255, 0.8);
1217
- border: none;
1218
- border-radius: 6px;
1219
- padding: 6px 10px;
1220
- color: white;
1221
- font-size: 10px;
1222
- cursor: pointer;
1223
- transition: background 0.2s;
1224
- }
1225
-
1226
- .open-btn:hover {
1227
- background: rgba(0, 140, 255, 0.9);
1228
- }
1229
-
1230
- .bottom-buttons {
1231
- display: flex;
1232
- gap: 12px;
1233
- }
1234
-
1235
- .bottom-btn {
1236
- background: rgba(60, 60, 60, 0.8);
1237
- border: 1px solid rgba(120, 120, 120, 0.6);
1238
- border-radius: 10px;
1239
- padding: 10px 16px;
1240
- color: white;
1241
- font-weight: 600;
1242
- font-size: 13px;
1243
- cursor: pointer;
1244
- transition: background 0.2s;
1245
- flex: 1;
1246
- text-align: center;
1247
- }
1248
-
1249
- .bottom-btn:hover {
1250
- background: rgba(80, 80, 80, 0.9);
1251
- }
1252
-
1253
- .empty-state {
1254
- text-align: center;
1255
- padding: 40px 20px;
1256
- color: rgba(255, 255, 255, 0.54);
1257
- }
1258
-
1259
- .empty-icon {
1260
- font-size: 48px;
1261
- margin-bottom: 16px;
1262
- color: rgba(255, 255, 255, 0.3);
1263
- }
1264
-
1265
- /* Scrollbar styling */
1266
- .results-list::-webkit-scrollbar {
1267
- width: 8px;
1268
- }
1269
-
1270
- .results-list::-webkit-scrollbar-track {
1271
- background: rgba(60, 60, 60, 0.5);
1272
- border-radius: 4px;
1273
- }
1274
-
1275
- .results-list::-webkit-scrollbar-thumb {
1276
- background: rgba(120, 120, 120, 0.8);
1277
- border-radius: 4px;
1278
- }
1279
-
1280
- .results-list::-webkit-scrollbar-thumb:hover {
1281
- background: rgba(140, 140, 140, 0.9);
1282
- }
1283
- </style>
1284
- </head>
1285
- <body>
1286
- <div class="header">
1287
- <div class="title">🔍 CloudSearch</div>
1288
- <button class="open-app-btn" onclick="openCloudSearchApp()">Tam Uygulama</button>
1289
- </div>
1290
-
1291
- <div class="search-container">
1292
- <input type="text" class="search-input" placeholder="Dosya, klasör veya içerik ara..." oninput="performSearch(this.value)">
1293
- </div>
1294
-
1295
- <div class="filters">
1296
- <div class="filter-btn active" onclick="setFilter('all')">📄 Tümü</div>
1297
- <div class="filter-btn" onclick="setFilter('documents')">📝 Belgeler</div>
1298
- <div class="filter-btn" onclick="setFilter('images')">🖼️ Resimler</div>
1299
- <div class="filter-btn" onclick="setFilter('code')">💻 Kod</div>
1300
- </div>
1301
-
1302
- <div class="results-title" id="results-title">Arama sonuçları burada görünecek</div>
1303
-
1304
- <div class="results-list" id="results-list">
1305
- <div class="empty-state">
1306
- <div class="empty-icon">🔍</div>
1307
- <div>Arama yapmak için yukarıdaki kutuya yazın</div>
1308
- </div>
1309
- </div>
1310
-
1311
- <div class="bottom-buttons">
1312
- <div class="bottom-btn" onclick="openCloudSearchApp()">🔍 Gelişmiş Arama</div>
1313
- <div class="bottom-btn" onclick="openFileManager()">📁 Dosya Yöneticisi</div>
1314
- </div>
1315
-
1316
- <script>
1317
- let currentFilter = 'all';
1318
- let searchResults = [];
1319
-
1320
- const mockResults = [
1321
- {
1322
- name: 'document.txt',
1323
- path: '/users/documents/document.txt',
1324
- type: 'text',
1325
- size: '2.4 KB',
1326
- modified: '2 saat önce',
1327
- icon: '📄'
1328
- },
1329
- {
1330
- name: 'project.py',
1331
- path: '/users/projects/project.py',
1332
- type: 'python',
1333
- size: '15.7 KB',
1334
- modified: '1 gün önce',
1335
- icon: '🐍'
1336
- },
1337
- {
1338
- name: 'image.png',
1339
- path: '/users/pictures/image.png',
1340
- type: 'image',
1341
- size: '1.2 MB',
1342
- modified: '3 gün önce',
1343
- icon: '🖼️'
1344
- }
1345
- ];
1346
-
1347
- function performSearch(query) {
1348
- if (query.length < 2) {
1349
- showEmptyState();
1350
- return;
1351
- }
1352
-
1353
- // Simüle edilmiş arama
1354
- searchResults = mockResults.filter(item =>
1355
- item.name.toLowerCase().includes(query.toLowerCase())
1356
- );
1357
-
1358
- displayResults();
1359
- }
1360
-
1361
- function setFilter(filter) {
1362
- currentFilter = filter;
1363
-
1364
- // Filter butonlarını güncelle
1365
- document.querySelectorAll('.filter-btn').forEach(btn => {
1366
- btn.classList.remove('active');
1367
- });
1368
- event.target.classList.add('active');
1369
-
1370
- displayResults();
1371
- }
1372
-
1373
- function displayResults() {
1374
- const resultsList = document.getElementById('results-list');
1375
- const resultsTitle = document.getElementById('results-title');
1376
-
1377
- if (searchResults.length === 0) {
1378
- showEmptyState();
1379
- return;
1380
- }
1381
-
1382
- resultsTitle.textContent = `Sonuçlar (${searchResults.length})`;
1383
-
1384
- let html = '';
1385
- searchResults.forEach(result => {
1386
- html += `
1387
- <div class="result-item" onclick="openFile('${result.path}')">
1388
- <div class="result-icon">${result.icon}</div>
1389
- <div class="result-content">
1390
- <div class="result-name">${result.name}</div>
1391
- <div class="result-path">${result.path}</div>
1392
- <div class="result-meta">
1393
- <span>${result.size}</span>
1394
- <span>•</span>
1395
- <span>${result.modified}</span>
1396
- </div>
1397
- </div>
1398
- <button class="open-btn" onclick="event.stopPropagation(); openFile('${result.path}')">Aç</button>
1399
- </div>
1400
- `;
1401
- });
1402
-
1403
- resultsList.innerHTML = html;
1404
- }
1405
-
1406
- function showEmptyState() {
1407
- const resultsList = document.getElementById('results-list');
1408
- const resultsTitle = document.getElementById('results-title');
1409
-
1410
- resultsTitle.textContent = 'Arama sonuçları burada görünecek';
1411
- resultsList.innerHTML = `
1412
- <div class="empty-state">
1413
- <div class="empty-icon">🔍</div>
1414
- <div>Arama yapmak için yukarıdaki kutuya yazın</div>
1415
- </div>
1416
- `;
1417
- }
1418
-
1419
- function openFile(path) {
1420
- alert('📂 ' + path + ' açılıyor...');
1421
- }
1422
-
1423
- function openCloudSearchApp() {
1424
- alert('🔍 CloudSearch uygulaması açılıyor...');
1425
- }
1426
-
1427
- function openFileManager() {
1428
- alert('📁 Dosya yöneticisi açılıyor...');
1429
- }
1430
- </script>
1431
- </body>
1432
- </html>
1433
- """
1434
-
1435
- # Widget factory fonksiyonu
1436
- def create_html_widget(widget_type: str) -> Optional[FletHTMLWidget]:
1437
- """HTML widget oluştur"""
1438
- widgets = {
1439
- "notification": HTMLNotificationWidget,
1440
- "clock": HTMLClockWidget,
1441
- "control_center": HTMLControlCenterWidget,
1442
- "cloudsearch": HTMLCloudSearchWidget
1443
- }
1444
-
1445
- widget_class = widgets.get(widget_type)
1446
- if widget_class:
1447
- return widget_class()
1448
- return None