|
|
// MainPage.xaml.cs
|
|
|
using System.Collections.ObjectModel;
|
|
|
using Microsoft.Maui.Controls;
|
|
|
|
|
|
namespace CommanderApp;
|
|
|
|
|
|
public partial class MainPage : ContentPage
|
|
|
{
|
|
|
private readonly IFileSystemService _fileService;
|
|
|
public ObservableCollection<FileSystemItem> LeftItems { get; set; } = new();
|
|
|
public ObservableCollection<FileSystemItem> RightItems { get; set; } = new();
|
|
|
public string LeftPath { get; set; } = string.Empty;
|
|
|
public string RightPath { get; set; } = string.Empty;
|
|
|
|
|
|
private string _currentLeftPath;
|
|
|
private string _currentRightPath;
|
|
|
|
|
|
private FileSystemItem? _selectedLeftItem;
|
|
|
private FileSystemItem? _selectedRightItem;
|
|
|
|
|
|
public MainPage(IFileSystemService fileService)
|
|
|
{
|
|
|
InitializeComponent();
|
|
|
_fileService = fileService;
|
|
|
BindingContext = this;
|
|
|
|
|
|
var root = _fileService.GetRootPath();
|
|
|
LoadDirectory(root, true);
|
|
|
LoadDirectory(root, false);
|
|
|
}
|
|
|
|
|
|
private void LoadDirectory(string path, bool isLeft)
|
|
|
{
|
|
|
var items = _fileService.GetDirectoryContents(path).ToList();
|
|
|
|
|
|
if (isLeft)
|
|
|
{
|
|
|
LeftItems.Clear();
|
|
|
foreach (var item in items) LeftItems.Add(item);
|
|
|
_currentLeftPath = path;
|
|
|
LeftPath = path;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
RightItems.Clear();
|
|
|
foreach (var item in items) RightItems.Add(item);
|
|
|
_currentRightPath = path;
|
|
|
RightPath = path;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private void OnLeftSelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
|
{
|
|
|
if (e.CurrentSelection.FirstOrDefault() is FileSystemItem item)
|
|
|
{
|
|
|
// Сохраняем выбор
|
|
|
_selectedLeftItem = item;
|
|
|
|
|
|
// Если это ".." или папка — переходим
|
|
|
if (item.Name == ".." || item.IsDirectory)
|
|
|
{
|
|
|
LoadDirectory(item.FullName, true);
|
|
|
// После перехода — сбрасываем выбор, чтобы не осталось выделения в новой папке
|
|
|
_selectedLeftItem = null;
|
|
|
LeftPanel.SelectedItem = null;
|
|
|
}
|
|
|
// Если это файл — ничего не делаем, оставляем его выделенным
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private void OnRightSelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
|
{
|
|
|
if (e.CurrentSelection.FirstOrDefault() is FileSystemItem item)
|
|
|
{
|
|
|
_selectedRightItem = item;
|
|
|
|
|
|
if (item.Name == ".." || item.IsDirectory)
|
|
|
{
|
|
|
LoadDirectory(item.FullName, false);
|
|
|
_selectedRightItem = null;
|
|
|
RightPanel.SelectedItem = null;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private async void OnCopyClicked(object sender, EventArgs e)
|
|
|
{
|
|
|
await ProcessFileOperation(async (src, destDir) =>
|
|
|
{
|
|
|
if (Directory.Exists(src))
|
|
|
await CopyDirectory(src, Path.Combine(destDir, Path.GetFileName(src)));
|
|
|
else
|
|
|
File.Copy(src, Path.Combine(destDir, Path.GetFileName(src)), overwrite: true);
|
|
|
}, "Copy");
|
|
|
}
|
|
|
|
|
|
private async void OnMoveClicked(object sender, EventArgs e)
|
|
|
{
|
|
|
await ProcessFileOperation((src, destDir) =>
|
|
|
{
|
|
|
var dest = Path.Combine(destDir, Path.GetFileName(src));
|
|
|
if (Directory.Exists(src))
|
|
|
Directory.Move(src, dest);
|
|
|
else
|
|
|
File.Move(src, dest, overwrite: true);
|
|
|
return Task.CompletedTask;
|
|
|
}, "Move");
|
|
|
}
|
|
|
|
|
|
private async void OnDeleteClicked(object sender, EventArgs e)
|
|
|
{
|
|
|
var item = _selectedLeftItem ?? _selectedRightItem;
|
|
|
if (item == null) return;
|
|
|
|
|
|
var confirm = await DisplayAlert("Delete", $"Delete '{item.Name}'?", "Yes", "No");
|
|
|
if (confirm)
|
|
|
{
|
|
|
if (item.IsDirectory)
|
|
|
Directory.Delete(item.FullName, recursive: true);
|
|
|
else
|
|
|
File.Delete(item.FullName);
|
|
|
|
|
|
// Обновляем обе панели (или только ту, откуда удалили)
|
|
|
LoadDirectory(_currentLeftPath, true);
|
|
|
LoadDirectory(_currentRightPath, false);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private async void OnMkdirClicked(object sender, EventArgs e)
|
|
|
{
|
|
|
var result = await DisplayPromptAsync("New Folder", "Folder name:", "Create", "Cancel");
|
|
|
if (string.IsNullOrWhiteSpace(result)) return;
|
|
|
|
|
|
// Создаём в активной панели (выберем левую, если выделение слева, иначе правую)
|
|
|
string targetPath = (_selectedLeftItem != null || LeftItems.Count > 0) ? _currentLeftPath : _currentRightPath;
|
|
|
string newPath = Path.Combine(targetPath, result.Trim());
|
|
|
|
|
|
if (!Directory.Exists(newPath))
|
|
|
{
|
|
|
Directory.CreateDirectory(newPath);
|
|
|
LoadDirectory(_currentLeftPath, true);
|
|
|
LoadDirectory(_currentRightPath, false);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
await DisplayAlert("Error", "Folder already exists.", "OK");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private void OnExitClicked(object sender, EventArgs e)
|
|
|
{
|
|
|
Application.Current?.Quit();
|
|
|
}
|
|
|
|
|
|
private async Task CopyDirectory(string sourceDir, string targetDir)
|
|
|
{
|
|
|
Directory.CreateDirectory(targetDir);
|
|
|
|
|
|
foreach (var file in Directory.GetFiles(sourceDir))
|
|
|
{
|
|
|
await Task.Run(() => File.Copy(file, Path.Combine(targetDir, Path.GetFileName(file)), overwrite: true));
|
|
|
}
|
|
|
|
|
|
foreach (var dir in Directory.GetDirectories(sourceDir))
|
|
|
{
|
|
|
await CopyDirectory(dir, Path.Combine(targetDir, Path.GetFileName(dir)));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private async Task ProcessFileOperation(Func<string, string, Task> operation, string actionName)
|
|
|
{
|
|
|
var srcItem = _selectedLeftItem ?? _selectedRightItem;
|
|
|
if (srcItem == null)
|
|
|
{
|
|
|
await DisplayAlert("Error", "Select a file or folder first.", "OK");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// Определяем целевую директорию: противоположная панель
|
|
|
string destDir = (srcItem == _selectedLeftItem) ? _currentRightPath : _currentLeftPath;
|
|
|
|
|
|
try
|
|
|
{
|
|
|
await operation(srcItem.FullName, destDir);
|
|
|
// Обновляем обе панели
|
|
|
LoadDirectory(_currentLeftPath, true);
|
|
|
LoadDirectory(_currentRightPath, false);
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
await DisplayAlert("Error", $"{actionName} failed: {ex.Message}", "OK");
|
|
|
}
|
|
|
}
|
|
|
} |