clapp-pm 1.0.33__py3-none-any.whl → 1.0.34__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.
- {clapp_pm-1.0.33.data → clapp_pm-1.0.34.data}/data/version.json +1 -1
- {clapp_pm-1.0.33.dist-info → clapp_pm-1.0.34.dist-info}/METADATA +1 -1
- {clapp_pm-1.0.33.dist-info → clapp_pm-1.0.34.dist-info}/RECORD +31 -11
- publish_command.py +17 -9
- test-app/clapp-packages-repo/README.md +46 -0
- test-app/clapp-packages-repo/index.json +40 -0
- test-app/clapp-packages-repo/packages/cloud-finder/README.md +164 -0
- test-app/clapp-packages-repo/packages/cloud-finder/main.py +985 -0
- test-app/clapp-packages-repo/packages/cloud-finder/manifest.json +8 -0
- test-app/clapp-packages-repo/packages/cloud-finder/requirements.txt +2 -0
- test-app/clapp-packages-repo/packages/cloud-web-browser/README.md +160 -0
- test-app/clapp-packages-repo/packages/cloud-web-browser/cloud_browser.py +1031 -0
- test-app/clapp-packages-repo/packages/cloud-web-browser/manifest.json +13 -0
- test-app/clapp-packages-repo/packages/cloud-web-browser/requirements.txt +4 -0
- test-app/clapp-packages-repo/packages/test-app/README.md +51 -0
- test-app/clapp-packages-repo/packages/test-app/main.py +1 -0
- test-app/clapp-packages-repo/packages/test-app/manifest.json +1 -0
- test-app/clapp-packages-repo/packages/test-app-2/README.md +51 -0
- test-app/clapp-packages-repo/packages/test-app-2/main.py +55 -0
- test-app/clapp-packages-repo/packages/test-app-2/manifest.json +15 -0
- test-app/clapp-packages-repo/packages.json +40 -0
- test-app/main.py +1 -55
- test-app/manifest.json +1 -15
- test-app/packages/test-app/README.md +51 -0
- test-app/packages/test-app/main.py +1 -0
- test-app/packages/test-app/manifest.json +1 -0
- version.py +1 -1
- {clapp_pm-1.0.33.dist-info → clapp_pm-1.0.34.dist-info}/WHEEL +0 -0
- {clapp_pm-1.0.33.dist-info → clapp_pm-1.0.34.dist-info}/entry_points.txt +0 -0
- {clapp_pm-1.0.33.dist-info → clapp_pm-1.0.34.dist-info}/licenses/LICENSE +0 -0
- {clapp_pm-1.0.33.dist-info → clapp_pm-1.0.34.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,985 @@
|
|
1
|
+
import flet as ft
|
2
|
+
import os
|
3
|
+
import shutil
|
4
|
+
import subprocess
|
5
|
+
from pathlib import Path
|
6
|
+
from datetime import datetime
|
7
|
+
import mimetypes
|
8
|
+
import platform
|
9
|
+
import json
|
10
|
+
import threading
|
11
|
+
|
12
|
+
class FileHistory:
|
13
|
+
def __init__(self):
|
14
|
+
self.recent_files = []
|
15
|
+
self.favorites = []
|
16
|
+
self.load_history()
|
17
|
+
|
18
|
+
def add_recent(self, path):
|
19
|
+
if path not in self.recent_files:
|
20
|
+
self.recent_files.insert(0, path)
|
21
|
+
self.recent_files = self.recent_files[:10]
|
22
|
+
self.save_history()
|
23
|
+
|
24
|
+
def add_favorite(self, path):
|
25
|
+
if path not in self.favorites:
|
26
|
+
self.favorites.append(path)
|
27
|
+
self.save_history()
|
28
|
+
|
29
|
+
def remove_favorite(self, path):
|
30
|
+
if path in self.favorites:
|
31
|
+
self.favorites.remove(path)
|
32
|
+
self.save_history()
|
33
|
+
|
34
|
+
def load_history(self):
|
35
|
+
try:
|
36
|
+
with open('file_history.json', 'r', encoding='utf-8') as f:
|
37
|
+
data = json.load(f)
|
38
|
+
self.recent_files = data.get('recent', [])
|
39
|
+
self.favorites = data.get('favorites', [])
|
40
|
+
except (FileNotFoundError, json.JSONDecodeError):
|
41
|
+
# Dosya yoksa veya bozuksa varsayılan değerler kullan
|
42
|
+
self.recent_files = []
|
43
|
+
self.favorites = []
|
44
|
+
|
45
|
+
def save_history(self):
|
46
|
+
try:
|
47
|
+
with open('file_history.json', 'w', encoding='utf-8') as f:
|
48
|
+
json.dump({
|
49
|
+
'recent': self.recent_files,
|
50
|
+
'favorites': self.favorites
|
51
|
+
}, f, ensure_ascii=False, indent=2)
|
52
|
+
except Exception as e:
|
53
|
+
print(f"Geçmiş kaydetme hatası: {e}")
|
54
|
+
|
55
|
+
class CloudFinder:
|
56
|
+
def __init__(self):
|
57
|
+
self.current_path = str(Path.home())
|
58
|
+
self.selected_items = set()
|
59
|
+
self.clipboard = []
|
60
|
+
self.clipboard_mode = None # 'copy' or 'cut'
|
61
|
+
self.view_mode = "list" # "list" or "grid"
|
62
|
+
self.show_hidden = False
|
63
|
+
self.sort_by = "name" # "name", "size", "date", "type"
|
64
|
+
self.sort_reverse = False
|
65
|
+
self.search_term = ""
|
66
|
+
self.file_history = FileHistory()
|
67
|
+
self.drag_source = None
|
68
|
+
self.ctrl_pressed = False
|
69
|
+
self.shift_pressed = False
|
70
|
+
self.last_selected = None
|
71
|
+
|
72
|
+
def main(self, page: ft.Page):
|
73
|
+
self.page = page
|
74
|
+
page.title = "Cloud Finder"
|
75
|
+
page.theme_mode = ft.ThemeMode.LIGHT
|
76
|
+
page.padding = 0
|
77
|
+
page.spacing = 0
|
78
|
+
page.on_keyboard_event = self._handle_keyboard
|
79
|
+
|
80
|
+
# Ana container
|
81
|
+
self.main_container = ft.Container(
|
82
|
+
expand=True,
|
83
|
+
bgcolor="#FFFFFF",
|
84
|
+
content=ft.Column(
|
85
|
+
expand=True,
|
86
|
+
spacing=0,
|
87
|
+
controls=[
|
88
|
+
self._build_toolbar(),
|
89
|
+
self._build_sidebar_and_content()
|
90
|
+
]
|
91
|
+
)
|
92
|
+
)
|
93
|
+
|
94
|
+
page.add(self.main_container)
|
95
|
+
self._load_current_directory()
|
96
|
+
|
97
|
+
def _build_toolbar(self):
|
98
|
+
"""Üst toolbar'ı oluştur"""
|
99
|
+
return ft.Container(
|
100
|
+
height=50,
|
101
|
+
bgcolor="#E3F2FD",
|
102
|
+
border=ft.border.only(bottom=ft.border.BorderSide(1, "#E0E0E0")),
|
103
|
+
content=ft.Row(
|
104
|
+
alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
|
105
|
+
controls=[
|
106
|
+
# Sol taraf - navigasyon butonları
|
107
|
+
ft.Row(
|
108
|
+
controls=[
|
109
|
+
ft.IconButton(
|
110
|
+
icon="arrow_back",
|
111
|
+
icon_color="#1976D2",
|
112
|
+
tooltip="Geri",
|
113
|
+
on_click=self._go_back
|
114
|
+
),
|
115
|
+
ft.IconButton(
|
116
|
+
icon="arrow_forward",
|
117
|
+
icon_color="#1976D2",
|
118
|
+
tooltip="İleri",
|
119
|
+
on_click=self._go_forward
|
120
|
+
),
|
121
|
+
ft.IconButton(
|
122
|
+
icon="arrow_upward",
|
123
|
+
icon_color="#1976D2",
|
124
|
+
tooltip="Üst Klasör",
|
125
|
+
on_click=self._go_up
|
126
|
+
),
|
127
|
+
]
|
128
|
+
),
|
129
|
+
|
130
|
+
# Orta - yol gösterici ve arama
|
131
|
+
ft.Container(
|
132
|
+
expand=True,
|
133
|
+
margin=ft.margin.only(left=20, right=20),
|
134
|
+
content=ft.Row(
|
135
|
+
controls=[
|
136
|
+
ft.Text(
|
137
|
+
self.current_path,
|
138
|
+
size=14,
|
139
|
+
color="#424242",
|
140
|
+
weight=ft.FontWeight.W_500,
|
141
|
+
expand=True
|
142
|
+
),
|
143
|
+
ft.TextField(
|
144
|
+
hint_text="Dosya ara...",
|
145
|
+
width=200,
|
146
|
+
on_change=self._on_search_change,
|
147
|
+
on_submit=self._perform_search
|
148
|
+
)
|
149
|
+
]
|
150
|
+
)
|
151
|
+
),
|
152
|
+
|
153
|
+
# Sağ taraf - görünüm ve ayarlar
|
154
|
+
ft.Row(
|
155
|
+
controls=[
|
156
|
+
ft.IconButton(
|
157
|
+
icon="view_list" if self.view_mode == "list" else "grid_view",
|
158
|
+
icon_color="#1976D2",
|
159
|
+
tooltip="Görünüm Değiştir",
|
160
|
+
on_click=self._toggle_view
|
161
|
+
),
|
162
|
+
ft.IconButton(
|
163
|
+
icon="visibility_off" if self.show_hidden else "visibility",
|
164
|
+
icon_color="#1976D2",
|
165
|
+
tooltip="Gizli Dosyaları Göster/Gizle",
|
166
|
+
on_click=self._toggle_hidden
|
167
|
+
),
|
168
|
+
ft.PopupMenuButton(
|
169
|
+
icon="sort",
|
170
|
+
tooltip="Sıralama",
|
171
|
+
items=[
|
172
|
+
ft.PopupMenuItem(text="İsme Göre", on_click=lambda e: self._sort_by("name")),
|
173
|
+
ft.PopupMenuItem(text="Boyuta Göre", on_click=lambda e: self._sort_by("size")),
|
174
|
+
ft.PopupMenuItem(text="Tarihe Göre", on_click=lambda e: self._sort_by("date")),
|
175
|
+
ft.PopupMenuItem(text="Türe Göre", on_click=lambda e: self._sort_by("type")),
|
176
|
+
]
|
177
|
+
),
|
178
|
+
]
|
179
|
+
)
|
180
|
+
]
|
181
|
+
)
|
182
|
+
)
|
183
|
+
|
184
|
+
def _build_sidebar_and_content(self):
|
185
|
+
"""Sidebar ve ana içerik alanını oluştur"""
|
186
|
+
return ft.Row(
|
187
|
+
expand=True,
|
188
|
+
spacing=0,
|
189
|
+
controls=[
|
190
|
+
# Sidebar
|
191
|
+
ft.Container(
|
192
|
+
width=250,
|
193
|
+
bgcolor="#FAFAFA",
|
194
|
+
border=ft.border.only(right=ft.border.BorderSide(1, "#E0E0E0")),
|
195
|
+
content=ft.Column(
|
196
|
+
expand=True,
|
197
|
+
controls=[
|
198
|
+
# Favoriler
|
199
|
+
ft.Container(
|
200
|
+
padding=ft.padding.all(10),
|
201
|
+
content=ft.Text(
|
202
|
+
"Favoriler",
|
203
|
+
size=12,
|
204
|
+
weight=ft.FontWeight.W_600,
|
205
|
+
color="#757575"
|
206
|
+
)
|
207
|
+
),
|
208
|
+
ft.Container(
|
209
|
+
padding=ft.padding.only(left=10, right=10, bottom=10),
|
210
|
+
content=ft.Column(
|
211
|
+
controls=[
|
212
|
+
self._build_sidebar_item("🏠 Ana Sayfa", str(Path.home()), "home"),
|
213
|
+
self._build_sidebar_item("📁 Masaüstü", str(Path.home() / "Desktop"), "desktop_windows"),
|
214
|
+
self._build_sidebar_item("📄 Belgeler", str(Path.home() / "Documents"), "description"),
|
215
|
+
self._build_sidebar_item("🖼️ Resimler", str(Path.home() / "Pictures"), "image"),
|
216
|
+
self._build_sidebar_item("🎵 Müzik", str(Path.home() / "Music"), "music_note"),
|
217
|
+
self._build_sidebar_item("🎬 Videolar", str(Path.home() / "Videos"), "video_library"),
|
218
|
+
self._build_sidebar_item("📥 İndirilenler", str(Path.home() / "Downloads"), "download"),
|
219
|
+
]
|
220
|
+
)
|
221
|
+
),
|
222
|
+
|
223
|
+
ft.Divider(height=1, color="#E0E0E0"),
|
224
|
+
|
225
|
+
# Son Kullanılanlar
|
226
|
+
ft.Container(
|
227
|
+
padding=ft.padding.all(10),
|
228
|
+
content=ft.Text(
|
229
|
+
"Son Kullanılanlar",
|
230
|
+
size=12,
|
231
|
+
weight=ft.FontWeight.W_600,
|
232
|
+
color="#757575"
|
233
|
+
)
|
234
|
+
),
|
235
|
+
ft.Container(
|
236
|
+
padding=ft.padding.only(left=10, right=10, bottom=10),
|
237
|
+
content=ft.Column(
|
238
|
+
controls=[self._build_recent_item(path) for path in self.file_history.recent_files[:5]]
|
239
|
+
)
|
240
|
+
),
|
241
|
+
|
242
|
+
ft.Divider(height=1, color="#E0E0E0"),
|
243
|
+
|
244
|
+
# Cihazlar
|
245
|
+
ft.Container(
|
246
|
+
padding=ft.padding.all(10),
|
247
|
+
content=ft.Text(
|
248
|
+
"Cihazlar",
|
249
|
+
size=12,
|
250
|
+
weight=ft.FontWeight.W_600,
|
251
|
+
color="#757575"
|
252
|
+
)
|
253
|
+
),
|
254
|
+
ft.Container(
|
255
|
+
padding=ft.padding.only(left=10, right=10, bottom=10),
|
256
|
+
content=ft.Column(
|
257
|
+
controls=[
|
258
|
+
self._build_sidebar_item("💾 Bu Mac", "/", "computer"),
|
259
|
+
]
|
260
|
+
)
|
261
|
+
)
|
262
|
+
]
|
263
|
+
)
|
264
|
+
),
|
265
|
+
|
266
|
+
# Ana içerik alanı
|
267
|
+
ft.Container(
|
268
|
+
expand=True,
|
269
|
+
content=ft.Column(
|
270
|
+
expand=True,
|
271
|
+
controls=[
|
272
|
+
# Dosya işlemleri toolbar'ı
|
273
|
+
self._build_file_toolbar(),
|
274
|
+
|
275
|
+
# Dosya listesi
|
276
|
+
ft.Container(
|
277
|
+
expand=True,
|
278
|
+
content=self._build_file_list()
|
279
|
+
)
|
280
|
+
]
|
281
|
+
)
|
282
|
+
)
|
283
|
+
]
|
284
|
+
)
|
285
|
+
|
286
|
+
def _build_sidebar_item(self, text, path, icon):
|
287
|
+
"""Sidebar öğesi oluştur"""
|
288
|
+
return ft.Container(
|
289
|
+
margin=ft.margin.only(bottom=2),
|
290
|
+
content=ft.ListTile(
|
291
|
+
leading=ft.Icon(icon, size=16, color="#757575"),
|
292
|
+
title=ft.Text(
|
293
|
+
text,
|
294
|
+
size=12,
|
295
|
+
color="#424242"
|
296
|
+
),
|
297
|
+
dense=True,
|
298
|
+
on_click=lambda e: self._navigate_to_path(path)
|
299
|
+
)
|
300
|
+
)
|
301
|
+
|
302
|
+
def _build_recent_item(self, path):
|
303
|
+
"""Son kullanılan öğe oluştur"""
|
304
|
+
name = os.path.basename(path)
|
305
|
+
icon = "folder" if os.path.isdir(path) else self._get_file_icon(name)
|
306
|
+
return ft.Container(
|
307
|
+
margin=ft.margin.only(bottom=2),
|
308
|
+
content=ft.ListTile(
|
309
|
+
leading=ft.Icon(icon, size=16, color="#757575"),
|
310
|
+
title=ft.Text(
|
311
|
+
name,
|
312
|
+
size=12,
|
313
|
+
color="#424242"
|
314
|
+
),
|
315
|
+
subtitle=ft.Text(
|
316
|
+
path,
|
317
|
+
size=10,
|
318
|
+
color="#9E9E9E"
|
319
|
+
),
|
320
|
+
dense=True,
|
321
|
+
on_click=lambda e: self._navigate_to_path(path)
|
322
|
+
)
|
323
|
+
)
|
324
|
+
|
325
|
+
def _build_file_toolbar(self):
|
326
|
+
"""Dosya işlemleri toolbar'ı"""
|
327
|
+
return ft.Container(
|
328
|
+
height=40,
|
329
|
+
bgcolor="#FFFFFF",
|
330
|
+
border=ft.border.only(bottom=ft.border.BorderSide(1, "#E0E0E0")),
|
331
|
+
content=ft.Row(
|
332
|
+
alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
|
333
|
+
controls=[
|
334
|
+
# Sol taraf - dosya işlemleri
|
335
|
+
ft.Row(
|
336
|
+
controls=[
|
337
|
+
ft.IconButton(
|
338
|
+
icon="create_new_folder",
|
339
|
+
icon_color="#1976D2",
|
340
|
+
tooltip="Yeni Klasör",
|
341
|
+
on_click=self._create_new_folder
|
342
|
+
),
|
343
|
+
ft.IconButton(
|
344
|
+
icon="create",
|
345
|
+
icon_color="#1976D2",
|
346
|
+
tooltip="Yeni Dosya",
|
347
|
+
on_click=self._create_new_file
|
348
|
+
),
|
349
|
+
ft.IconButton(
|
350
|
+
icon="content_copy",
|
351
|
+
icon_color="#1976D2",
|
352
|
+
tooltip="Kopyala (Ctrl+C)",
|
353
|
+
on_click=self._copy_selected
|
354
|
+
),
|
355
|
+
ft.IconButton(
|
356
|
+
icon="content_cut",
|
357
|
+
icon_color="#1976D2",
|
358
|
+
tooltip="Kes (Ctrl+X)",
|
359
|
+
on_click=self._cut_selected
|
360
|
+
),
|
361
|
+
ft.IconButton(
|
362
|
+
icon="content_paste",
|
363
|
+
icon_color="#1976D2",
|
364
|
+
tooltip="Yapıştır (Ctrl+V)",
|
365
|
+
on_click=self._paste_items
|
366
|
+
),
|
367
|
+
ft.IconButton(
|
368
|
+
icon="delete",
|
369
|
+
icon_color="#D32F2F",
|
370
|
+
tooltip="Sil (Delete)",
|
371
|
+
on_click=self._delete_selected
|
372
|
+
),
|
373
|
+
]
|
374
|
+
),
|
375
|
+
|
376
|
+
# Sağ taraf - seçim bilgisi
|
377
|
+
ft.Container(
|
378
|
+
padding=ft.padding.only(right=10),
|
379
|
+
content=ft.Text(
|
380
|
+
f"{len(self.selected_items)} öğe seçili" if self.selected_items else "",
|
381
|
+
size=12,
|
382
|
+
color="#757575"
|
383
|
+
)
|
384
|
+
)
|
385
|
+
]
|
386
|
+
)
|
387
|
+
)
|
388
|
+
|
389
|
+
def _build_file_list(self):
|
390
|
+
"""Dosya listesi oluştur"""
|
391
|
+
if self.view_mode == "list":
|
392
|
+
self.file_list = ft.ListView(
|
393
|
+
expand=True,
|
394
|
+
spacing=2,
|
395
|
+
padding=ft.padding.all(10)
|
396
|
+
)
|
397
|
+
else:
|
398
|
+
self.file_list = ft.GridView(
|
399
|
+
expand=True,
|
400
|
+
runs_count=5,
|
401
|
+
max_extent=150,
|
402
|
+
child_aspect_ratio=1.0,
|
403
|
+
spacing=10,
|
404
|
+
run_spacing=10,
|
405
|
+
padding=ft.padding.all(10)
|
406
|
+
)
|
407
|
+
return self.file_list
|
408
|
+
|
409
|
+
def _load_current_directory(self):
|
410
|
+
"""Mevcut dizini yükle"""
|
411
|
+
try:
|
412
|
+
self._show_loading("Yükleniyor...")
|
413
|
+
self.file_list.controls.clear()
|
414
|
+
|
415
|
+
# Üst dizine git butonu
|
416
|
+
if self.current_path != "/":
|
417
|
+
self.file_list.controls.append(
|
418
|
+
self._build_file_item("..", "..", True, "folder_open")
|
419
|
+
)
|
420
|
+
|
421
|
+
# Dizin içeriğini listele
|
422
|
+
items = []
|
423
|
+
for item in os.listdir(self.current_path):
|
424
|
+
item_path = os.path.join(self.current_path, item)
|
425
|
+
|
426
|
+
# Gizli dosyaları filtrele
|
427
|
+
if not self.show_hidden and item.startswith('.'):
|
428
|
+
continue
|
429
|
+
|
430
|
+
try:
|
431
|
+
if os.path.isdir(item_path):
|
432
|
+
items.append((item, item_path, True, "folder"))
|
433
|
+
else:
|
434
|
+
items.append((item, item_path, False, self._get_file_icon(item)))
|
435
|
+
except PermissionError:
|
436
|
+
continue
|
437
|
+
|
438
|
+
# Arama filtresi uygula
|
439
|
+
if self.search_term:
|
440
|
+
items = self._filter_items(items)
|
441
|
+
|
442
|
+
# Sıralama uygula
|
443
|
+
items = self._sort_items(items)
|
444
|
+
|
445
|
+
# Görünüm moduna göre oluştur
|
446
|
+
for item in items:
|
447
|
+
if self.view_mode == "list":
|
448
|
+
self.file_list.controls.append(
|
449
|
+
self._build_file_item(item[0], item[1], item[2], item[3])
|
450
|
+
)
|
451
|
+
else:
|
452
|
+
self.file_list.controls.append(
|
453
|
+
self._build_grid_item(item[0], item[1], item[2], item[3])
|
454
|
+
)
|
455
|
+
|
456
|
+
self.file_list.update()
|
457
|
+
self._hide_loading()
|
458
|
+
|
459
|
+
except Exception as e:
|
460
|
+
self._show_notification(f"Hata: {e}", "#F44336")
|
461
|
+
|
462
|
+
def _build_file_item(self, name, path, is_dir, icon):
|
463
|
+
"""Dosya öğesi oluştur (liste görünümü)"""
|
464
|
+
return ft.Container(
|
465
|
+
bgcolor="#FFFFFF",
|
466
|
+
border=ft.border.all(1, "#FFFFFF"),
|
467
|
+
border_radius=ft.border_radius.all(4),
|
468
|
+
padding=ft.padding.all(8),
|
469
|
+
content=ft.ListTile(
|
470
|
+
leading=ft.Icon(icon, color="#1976D2" if is_dir else "#757575"),
|
471
|
+
title=ft.Text(
|
472
|
+
name,
|
473
|
+
size=14,
|
474
|
+
weight=ft.FontWeight.W_500,
|
475
|
+
color="#212121"
|
476
|
+
),
|
477
|
+
subtitle=ft.Text(
|
478
|
+
self._get_file_info(path),
|
479
|
+
size=12,
|
480
|
+
color="#757575"
|
481
|
+
),
|
482
|
+
trailing=ft.PopupMenuButton(
|
483
|
+
icon="more_vert",
|
484
|
+
tooltip="Daha fazla",
|
485
|
+
items=[
|
486
|
+
ft.PopupMenuItem(text="Aç", on_click=lambda e: self._open_file(path)),
|
487
|
+
ft.PopupMenuItem(text="Kopyala", on_click=lambda e: self._copy_item(path)),
|
488
|
+
ft.PopupMenuItem(text="Kes", on_click=lambda e: self._cut_item(path)),
|
489
|
+
ft.PopupMenuItem(text="Sil", on_click=lambda e: self._delete_item(path)),
|
490
|
+
ft.PopupMenuItem(text="Favorilere Ekle", on_click=lambda e: self._add_to_favorites(path)),
|
491
|
+
]
|
492
|
+
),
|
493
|
+
on_click=lambda e: self._on_file_click(path, is_dir),
|
494
|
+
on_long_press=lambda e: self._on_file_long_press(path),
|
495
|
+
selected=path in self.selected_items,
|
496
|
+
selected_color="#E3F2FD",
|
497
|
+
)
|
498
|
+
)
|
499
|
+
|
500
|
+
def _build_grid_item(self, name, path, is_dir, icon):
|
501
|
+
"""Dosya öğesi oluştur (grid görünümü)"""
|
502
|
+
return ft.Container(
|
503
|
+
bgcolor="#FFFFFF",
|
504
|
+
border=ft.border.all(1, "#E0E0E0"),
|
505
|
+
border_radius=ft.border_radius.all(8),
|
506
|
+
padding=ft.padding.all(10),
|
507
|
+
content=ft.Column(
|
508
|
+
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
|
509
|
+
controls=[
|
510
|
+
ft.Icon(
|
511
|
+
icon,
|
512
|
+
size=48,
|
513
|
+
color="#1976D2" if is_dir else "#757575"
|
514
|
+
),
|
515
|
+
ft.Text(
|
516
|
+
name,
|
517
|
+
size=12,
|
518
|
+
weight=ft.FontWeight.W_500,
|
519
|
+
color="#212121",
|
520
|
+
text_align=ft.TextAlign.CENTER,
|
521
|
+
max_lines=2,
|
522
|
+
overflow=ft.TextOverflow.ELLIPSIS
|
523
|
+
),
|
524
|
+
ft.Text(
|
525
|
+
self._get_file_info(path),
|
526
|
+
size=10,
|
527
|
+
color="#757575",
|
528
|
+
text_align=ft.TextAlign.CENTER
|
529
|
+
)
|
530
|
+
]
|
531
|
+
),
|
532
|
+
on_click=lambda e: self._on_file_click(path, is_dir),
|
533
|
+
on_long_press=lambda e: self._on_file_long_press(path),
|
534
|
+
)
|
535
|
+
|
536
|
+
def _get_file_icon(self, filename):
|
537
|
+
"""Dosya türüne göre ikon döndür"""
|
538
|
+
ext = Path(filename).suffix.lower()
|
539
|
+
icon_map = {
|
540
|
+
'.txt': 'description',
|
541
|
+
'.pdf': 'picture_as_pdf',
|
542
|
+
'.doc': 'description',
|
543
|
+
'.docx': 'description',
|
544
|
+
'.xls': 'table_chart',
|
545
|
+
'.xlsx': 'table_chart',
|
546
|
+
'.ppt': 'slides',
|
547
|
+
'.pptx': 'slides',
|
548
|
+
'.jpg': 'image',
|
549
|
+
'.jpeg': 'image',
|
550
|
+
'.png': 'image',
|
551
|
+
'.gif': 'image',
|
552
|
+
'.mp3': 'music_note',
|
553
|
+
'.mp4': 'video_file',
|
554
|
+
'.avi': 'video_file',
|
555
|
+
'.zip': 'archive',
|
556
|
+
'.rar': 'archive',
|
557
|
+
'.py': 'code',
|
558
|
+
'.js': 'code',
|
559
|
+
'.html': 'code',
|
560
|
+
'.css': 'code',
|
561
|
+
}
|
562
|
+
return icon_map.get(ext, 'insert_drive_file')
|
563
|
+
|
564
|
+
def _get_file_info(self, path):
|
565
|
+
"""Dosya bilgilerini al"""
|
566
|
+
try:
|
567
|
+
stat = os.stat(path)
|
568
|
+
size = stat.st_size
|
569
|
+
modified = datetime.fromtimestamp(stat.st_mtime)
|
570
|
+
|
571
|
+
if os.path.isdir(path):
|
572
|
+
return f"Klasör • {modified.strftime('%d.%m.%Y %H:%M')}"
|
573
|
+
else:
|
574
|
+
if size < 1024:
|
575
|
+
size_str = f"{size} B"
|
576
|
+
elif size < 1024 * 1024:
|
577
|
+
size_str = f"{size // 1024} KB"
|
578
|
+
else:
|
579
|
+
size_str = f"{size // (1024 * 1024)} MB"
|
580
|
+
|
581
|
+
return f"{size_str} • {modified.strftime('%d.%m.%Y %H:%M')}"
|
582
|
+
except:
|
583
|
+
return "Bilinmeyen"
|
584
|
+
|
585
|
+
def _on_file_click(self, path, is_dir):
|
586
|
+
"""Dosya tıklama olayı"""
|
587
|
+
if self.ctrl_pressed:
|
588
|
+
# Ctrl + tıklama - çoklu seçim
|
589
|
+
if path in self.selected_items:
|
590
|
+
self.selected_items.remove(path)
|
591
|
+
else:
|
592
|
+
self.selected_items.add(path)
|
593
|
+
self.last_selected = path
|
594
|
+
elif self.shift_pressed and self.last_selected:
|
595
|
+
# Shift + tıklama - aralık seçimi
|
596
|
+
self._select_range(self.last_selected, path)
|
597
|
+
else:
|
598
|
+
# Normal tıklama
|
599
|
+
if is_dir:
|
600
|
+
# Navigasyon geçmişini başlat
|
601
|
+
if not hasattr(self, 'navigation_history'):
|
602
|
+
self.navigation_history = []
|
603
|
+
self.current_history_index = -1
|
604
|
+
|
605
|
+
# Mevcut yolu geçmişe ekle
|
606
|
+
if self.current_path != path:
|
607
|
+
# Geçmişteki mevcut konumdan sonraki tüm geçmişi sil
|
608
|
+
self.navigation_history = self.navigation_history[:self.current_history_index + 1]
|
609
|
+
self.navigation_history.append(self.current_path)
|
610
|
+
self.current_history_index = len(self.navigation_history) - 1
|
611
|
+
|
612
|
+
self.current_path = path
|
613
|
+
self._load_current_directory()
|
614
|
+
else:
|
615
|
+
self._open_file(path)
|
616
|
+
self.file_history.add_recent(path)
|
617
|
+
|
618
|
+
self._load_current_directory()
|
619
|
+
|
620
|
+
def _on_file_long_press(self, path):
|
621
|
+
"""Dosya uzun basma olayı"""
|
622
|
+
if path in self.selected_items:
|
623
|
+
self.selected_items.remove(path)
|
624
|
+
else:
|
625
|
+
self.selected_items.add(path)
|
626
|
+
self._load_current_directory()
|
627
|
+
|
628
|
+
def _select_range(self, start_path, end_path):
|
629
|
+
"""İki dosya arasındaki tüm dosyaları seç"""
|
630
|
+
try:
|
631
|
+
# Mevcut dosya listesini al
|
632
|
+
current_items = []
|
633
|
+
for item in os.listdir(self.current_path):
|
634
|
+
item_path = os.path.join(self.current_path, item)
|
635
|
+
if not self.show_hidden and item.startswith('.'):
|
636
|
+
continue
|
637
|
+
try:
|
638
|
+
if os.path.exists(item_path):
|
639
|
+
current_items.append((item, item_path))
|
640
|
+
except PermissionError:
|
641
|
+
continue
|
642
|
+
|
643
|
+
# Dosyaları sırala
|
644
|
+
current_items.sort(key=lambda x: x[0].lower())
|
645
|
+
|
646
|
+
# Başlangıç ve bitiş indekslerini bul
|
647
|
+
start_index = -1
|
648
|
+
end_index = -1
|
649
|
+
|
650
|
+
for i, (name, path) in enumerate(current_items):
|
651
|
+
if path == start_path:
|
652
|
+
start_index = i
|
653
|
+
if path == end_path:
|
654
|
+
end_index = i
|
655
|
+
|
656
|
+
if start_index != -1 and end_index != -1:
|
657
|
+
# İndeksleri düzenle (küçük olan başlangıç olsun)
|
658
|
+
if start_index > end_index:
|
659
|
+
start_index, end_index = end_index, start_index
|
660
|
+
|
661
|
+
# Aralıktaki tüm dosyaları seç
|
662
|
+
for i in range(start_index, end_index + 1):
|
663
|
+
_, path = current_items[i]
|
664
|
+
self.selected_items.add(path)
|
665
|
+
|
666
|
+
self._show_notification(f"{end_index - start_index + 1} dosya seçildi", "#4CAF50")
|
667
|
+
|
668
|
+
except Exception as e:
|
669
|
+
self._show_notification(f"Aralık seçimi hatası: {e}", "#F44336")
|
670
|
+
|
671
|
+
def _navigate_to_path(self, path):
|
672
|
+
"""Belirtilen yola git"""
|
673
|
+
if os.path.exists(path):
|
674
|
+
# Navigasyon geçmişini başlat
|
675
|
+
if not hasattr(self, 'navigation_history'):
|
676
|
+
self.navigation_history = []
|
677
|
+
self.current_history_index = -1
|
678
|
+
|
679
|
+
# Mevcut yolu geçmişe ekle
|
680
|
+
if self.current_path != path:
|
681
|
+
# Geçmişteki mevcut konumdan sonraki tüm geçmişi sil
|
682
|
+
self.navigation_history = self.navigation_history[:self.current_history_index + 1]
|
683
|
+
self.navigation_history.append(self.current_path)
|
684
|
+
self.current_history_index = len(self.navigation_history) - 1
|
685
|
+
|
686
|
+
self.current_path = path
|
687
|
+
self._load_current_directory()
|
688
|
+
|
689
|
+
def _go_back(self, e):
|
690
|
+
"""Geri git"""
|
691
|
+
if not hasattr(self, 'navigation_history'):
|
692
|
+
self.navigation_history = []
|
693
|
+
self.current_history_index = -1
|
694
|
+
|
695
|
+
if self.current_history_index > 0:
|
696
|
+
self.current_history_index -= 1
|
697
|
+
self.current_path = self.navigation_history[self.current_history_index]
|
698
|
+
self._load_current_directory()
|
699
|
+
self._show_notification("Geri gidildi", "#4CAF50")
|
700
|
+
else:
|
701
|
+
self._show_notification("Geri gidilecek geçmiş yok", "#FF9800")
|
702
|
+
|
703
|
+
def _go_forward(self, e):
|
704
|
+
"""İleri git"""
|
705
|
+
if not hasattr(self, 'navigation_history'):
|
706
|
+
self.navigation_history = []
|
707
|
+
self.current_history_index = -1
|
708
|
+
|
709
|
+
if self.current_history_index < len(self.navigation_history) - 1:
|
710
|
+
self.current_history_index += 1
|
711
|
+
self.current_path = self.navigation_history[self.current_history_index]
|
712
|
+
self._load_current_directory()
|
713
|
+
self._show_notification("İleri gidildi", "#4CAF50")
|
714
|
+
else:
|
715
|
+
self._show_notification("İleri gidilecek geçmiş yok", "#FF9800")
|
716
|
+
|
717
|
+
def _go_up(self, e):
|
718
|
+
"""Üst dizine git"""
|
719
|
+
parent = os.path.dirname(self.current_path)
|
720
|
+
if parent != self.current_path:
|
721
|
+
self.current_path = parent
|
722
|
+
self._load_current_directory()
|
723
|
+
|
724
|
+
def _on_search_change(self, e):
|
725
|
+
"""Arama terimi değiştiğinde"""
|
726
|
+
self.search_term = e.control.value
|
727
|
+
self._load_current_directory()
|
728
|
+
|
729
|
+
def _perform_search(self, e):
|
730
|
+
"""Arama yap"""
|
731
|
+
self._load_current_directory()
|
732
|
+
|
733
|
+
def _toggle_view(self, e):
|
734
|
+
"""Görünüm değiştir"""
|
735
|
+
self.view_mode = "grid" if self.view_mode == "list" else "list"
|
736
|
+
self._load_current_directory()
|
737
|
+
|
738
|
+
def _toggle_hidden(self, e):
|
739
|
+
"""Gizli dosyaları göster/gizle"""
|
740
|
+
self.show_hidden = not self.show_hidden
|
741
|
+
self._load_current_directory()
|
742
|
+
|
743
|
+
def _sort_by(self, sort_type):
|
744
|
+
"""Sıralama türünü değiştir"""
|
745
|
+
if self.sort_by == sort_type:
|
746
|
+
self.sort_reverse = not self.sort_reverse
|
747
|
+
else:
|
748
|
+
self.sort_by = sort_type
|
749
|
+
self.sort_reverse = False
|
750
|
+
self._load_current_directory()
|
751
|
+
|
752
|
+
def _filter_items(self, items):
|
753
|
+
"""Arama filtresi uygula"""
|
754
|
+
filtered = []
|
755
|
+
for item in items:
|
756
|
+
if self.search_term.lower() in item[0].lower():
|
757
|
+
filtered.append(item)
|
758
|
+
return filtered
|
759
|
+
|
760
|
+
def _sort_items(self, items):
|
761
|
+
"""Dosyaları sırala"""
|
762
|
+
if self.sort_by == "name":
|
763
|
+
items.sort(key=lambda x: x[0].lower(), reverse=self.sort_reverse)
|
764
|
+
elif self.sort_by == "size":
|
765
|
+
items.sort(key=lambda x: os.path.getsize(x[1]) if os.path.exists(x[1]) else 0, reverse=self.sort_reverse)
|
766
|
+
elif self.sort_by == "date":
|
767
|
+
items.sort(key=lambda x: os.path.getmtime(x[1]) if os.path.exists(x[1]) else 0, reverse=self.sort_reverse)
|
768
|
+
elif self.sort_by == "type":
|
769
|
+
items.sort(key=lambda x: Path(x[0]).suffix.lower(), reverse=self.sort_reverse)
|
770
|
+
|
771
|
+
# Klasörleri önce göster
|
772
|
+
folders = [item for item in items if item[2]]
|
773
|
+
files = [item for item in items if not item[2]]
|
774
|
+
return folders + files
|
775
|
+
|
776
|
+
def _handle_keyboard(self, e: ft.KeyboardEvent):
|
777
|
+
"""Klavye olaylarını işle"""
|
778
|
+
try:
|
779
|
+
# Basit klavye kısayolları
|
780
|
+
if e.key == "Delete":
|
781
|
+
self._delete_selected()
|
782
|
+
elif e.key == "c" and hasattr(e, 'ctrl') and e.ctrl:
|
783
|
+
self._copy_selected()
|
784
|
+
elif e.key == "v" and hasattr(e, 'ctrl') and e.ctrl:
|
785
|
+
self._paste_items()
|
786
|
+
elif e.key == "x" and hasattr(e, 'ctrl') and e.ctrl:
|
787
|
+
self._cut_selected()
|
788
|
+
elif e.key == "a" and hasattr(e, 'ctrl') and e.ctrl:
|
789
|
+
self._select_all()
|
790
|
+
elif e.key == "Escape":
|
791
|
+
self.selected_items.clear()
|
792
|
+
self._load_current_directory()
|
793
|
+
except Exception as ex:
|
794
|
+
print(f"Klavye olayı hatası: {ex}")
|
795
|
+
|
796
|
+
def _select_all(self):
|
797
|
+
"""Tüm dosyaları seç"""
|
798
|
+
try:
|
799
|
+
self.selected_items.clear()
|
800
|
+
|
801
|
+
# Mevcut dizindeki tüm dosyaları al
|
802
|
+
for item in os.listdir(self.current_path):
|
803
|
+
item_path = os.path.join(self.current_path, item)
|
804
|
+
|
805
|
+
# Gizli dosyaları filtrele
|
806
|
+
if not self.show_hidden and item.startswith('.'):
|
807
|
+
continue
|
808
|
+
|
809
|
+
try:
|
810
|
+
if os.path.exists(item_path):
|
811
|
+
self.selected_items.add(item_path)
|
812
|
+
except PermissionError:
|
813
|
+
continue
|
814
|
+
|
815
|
+
self._load_current_directory()
|
816
|
+
self._show_notification(f"{len(self.selected_items)} dosya seçildi", "#4CAF50")
|
817
|
+
|
818
|
+
except Exception as e:
|
819
|
+
self._show_notification(f"Tümünü seçme hatası: {e}", "#F44336")
|
820
|
+
|
821
|
+
def _create_new_folder(self, e):
|
822
|
+
"""Yeni klasör oluştur"""
|
823
|
+
try:
|
824
|
+
folder_name = "Yeni Klasör"
|
825
|
+
counter = 1
|
826
|
+
while os.path.exists(os.path.join(self.current_path, folder_name)):
|
827
|
+
folder_name = f"Yeni Klasör ({counter})"
|
828
|
+
counter += 1
|
829
|
+
|
830
|
+
os.makedirs(os.path.join(self.current_path, folder_name))
|
831
|
+
self._load_current_directory()
|
832
|
+
self._show_notification(f"'{folder_name}' klasörü oluşturuldu", "#4CAF50")
|
833
|
+
except Exception as e:
|
834
|
+
self._show_notification(f"Klasör oluşturma hatası: {e}", "#F44336")
|
835
|
+
|
836
|
+
def _create_new_file(self, e):
|
837
|
+
"""Yeni dosya oluştur"""
|
838
|
+
try:
|
839
|
+
file_name = "Yeni Dosya.txt"
|
840
|
+
counter = 1
|
841
|
+
while os.path.exists(os.path.join(self.current_path, file_name)):
|
842
|
+
file_name = f"Yeni Dosya ({counter}).txt"
|
843
|
+
counter += 1
|
844
|
+
|
845
|
+
with open(os.path.join(self.current_path, file_name), 'w') as f:
|
846
|
+
f.write("")
|
847
|
+
|
848
|
+
self._load_current_directory()
|
849
|
+
self._show_notification(f"'{file_name}' dosyası oluşturuldu", "#4CAF50")
|
850
|
+
except Exception as e:
|
851
|
+
self._show_notification(f"Dosya oluşturma hatası: {e}", "#F44336")
|
852
|
+
|
853
|
+
def _copy_selected(self, e=None):
|
854
|
+
"""Seçili öğeleri kopyala"""
|
855
|
+
if self.selected_items:
|
856
|
+
self.clipboard = list(self.selected_items)
|
857
|
+
self.clipboard_mode = 'copy'
|
858
|
+
self._show_notification(f"{len(self.selected_items)} öğe kopyalandı", "#4CAF50")
|
859
|
+
|
860
|
+
def _cut_selected(self, e=None):
|
861
|
+
"""Seçili öğeleri kes"""
|
862
|
+
if self.selected_items:
|
863
|
+
self.clipboard = list(self.selected_items)
|
864
|
+
self.clipboard_mode = 'cut'
|
865
|
+
self._show_notification(f"{len(self.selected_items)} öğe kesildi", "#FF9800")
|
866
|
+
|
867
|
+
def _copy_item(self, path):
|
868
|
+
"""Tek dosyayı kopyala"""
|
869
|
+
self.selected_items = {path}
|
870
|
+
self._copy_selected()
|
871
|
+
|
872
|
+
def _cut_item(self, path):
|
873
|
+
"""Tek dosyayı kes"""
|
874
|
+
self.selected_items = {path}
|
875
|
+
self._cut_selected()
|
876
|
+
|
877
|
+
def _delete_item(self, path):
|
878
|
+
"""Tek dosyayı sil"""
|
879
|
+
self.selected_items = {path}
|
880
|
+
self._delete_selected()
|
881
|
+
|
882
|
+
def _paste_items(self, e=None):
|
883
|
+
"""Pano öğelerini yapıştır"""
|
884
|
+
if not self.clipboard:
|
885
|
+
return
|
886
|
+
|
887
|
+
success_count = 0
|
888
|
+
for source_path in self.clipboard:
|
889
|
+
try:
|
890
|
+
source_name = os.path.basename(source_path)
|
891
|
+
dest_path = os.path.join(self.current_path, source_name)
|
892
|
+
|
893
|
+
# Aynı isimde dosya varsa numara ekle
|
894
|
+
counter = 1
|
895
|
+
while os.path.exists(dest_path):
|
896
|
+
name, ext = os.path.splitext(source_name)
|
897
|
+
dest_path = os.path.join(self.current_path, f"{name} ({counter}){ext}")
|
898
|
+
counter += 1
|
899
|
+
|
900
|
+
if os.path.isdir(source_path):
|
901
|
+
shutil.copytree(source_path, dest_path)
|
902
|
+
else:
|
903
|
+
shutil.copy2(source_path, dest_path)
|
904
|
+
|
905
|
+
# Kesme işlemi ise kaynak dosyayı sil
|
906
|
+
if self.clipboard_mode == 'cut':
|
907
|
+
if os.path.isdir(source_path):
|
908
|
+
shutil.rmtree(source_path)
|
909
|
+
else:
|
910
|
+
os.remove(source_path)
|
911
|
+
|
912
|
+
success_count += 1
|
913
|
+
|
914
|
+
except Exception as e:
|
915
|
+
self._show_notification(f"Yapıştırma hatası: {e}", "#F44336")
|
916
|
+
|
917
|
+
self.clipboard.clear()
|
918
|
+
self.clipboard_mode = None
|
919
|
+
self.selected_items.clear()
|
920
|
+
self._load_current_directory()
|
921
|
+
|
922
|
+
if success_count > 0:
|
923
|
+
action = "yapıştırıldı" if self.clipboard_mode == 'copy' else "taşındı"
|
924
|
+
self._show_notification(f"{success_count} öğe {action}", "#4CAF50")
|
925
|
+
|
926
|
+
def _delete_selected(self, e=None):
|
927
|
+
"""Seçili öğeleri sil"""
|
928
|
+
if not self.selected_items:
|
929
|
+
return
|
930
|
+
|
931
|
+
success_count = 0
|
932
|
+
for path in self.selected_items:
|
933
|
+
try:
|
934
|
+
if os.path.isdir(path):
|
935
|
+
shutil.rmtree(path)
|
936
|
+
else:
|
937
|
+
os.remove(path)
|
938
|
+
success_count += 1
|
939
|
+
except Exception as e:
|
940
|
+
self._show_notification(f"Silme hatası: {e}", "#F44336")
|
941
|
+
|
942
|
+
self.selected_items.clear()
|
943
|
+
self._load_current_directory()
|
944
|
+
|
945
|
+
if success_count > 0:
|
946
|
+
self._show_notification(f"{success_count} öğe silindi", "#4CAF50")
|
947
|
+
|
948
|
+
def _add_to_favorites(self, path):
|
949
|
+
"""Favorilere ekle"""
|
950
|
+
self.file_history.add_favorite(path)
|
951
|
+
self._show_notification("Favorilere eklendi", "#4CAF50")
|
952
|
+
|
953
|
+
def _open_file(self, path):
|
954
|
+
"""Dosyayı varsayılan uygulamada aç"""
|
955
|
+
try:
|
956
|
+
if platform.system() == "Darwin": # macOS
|
957
|
+
subprocess.run(["open", path])
|
958
|
+
elif platform.system() == "Windows":
|
959
|
+
os.startfile(path)
|
960
|
+
else: # Linux
|
961
|
+
subprocess.run(["xdg-open", path])
|
962
|
+
except Exception as e:
|
963
|
+
self._show_notification(f"Dosya açma hatası: {e}", "#F44336")
|
964
|
+
|
965
|
+
def _show_notification(self, message, color="#4CAF50"):
|
966
|
+
"""Bildirim göster"""
|
967
|
+
# Basit bildirim - geliştirilecek
|
968
|
+
print(f"Bildirim: {message}")
|
969
|
+
|
970
|
+
def _show_loading(self, message="Yükleniyor..."):
|
971
|
+
"""Yükleme göstergesi göster"""
|
972
|
+
# Basit yükleme göstergesi
|
973
|
+
print(f"⏳ {message}")
|
974
|
+
|
975
|
+
def _hide_loading(self):
|
976
|
+
"""Yükleme göstergesini gizle"""
|
977
|
+
# Yükleme tamamlandı
|
978
|
+
print("✅ Yükleme tamamlandı")
|
979
|
+
|
980
|
+
def main():
|
981
|
+
app = CloudFinder()
|
982
|
+
ft.app(target=app.main)
|
983
|
+
|
984
|
+
if __name__ == "__main__":
|
985
|
+
main()
|