|
|
|
|
@ -1,5 +1,4 @@
|
|
|
|
|
// MainPage.xaml.cs
|
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
|
using Microsoft.Maui.Controls;
|
|
|
|
|
@ -10,15 +9,13 @@ public partial class MainPage : ContentPage, INotifyPropertyChanged
|
|
|
|
|
{
|
|
|
|
|
private readonly IFileSystemService _fileService;
|
|
|
|
|
|
|
|
|
|
public ObservableCollection<FileSystemItem> LeftItems { get; set; } = new();
|
|
|
|
|
public ObservableCollection<FileSystemItem> RightItems { get; set; } = new();
|
|
|
|
|
// Коллекции больше не нужны для привязки, но оставим для логики
|
|
|
|
|
public ObservableCollection<FileSystemItem> LeftItems { get; } = new();
|
|
|
|
|
public ObservableCollection<FileSystemItem> RightItems { get; } = new();
|
|
|
|
|
|
|
|
|
|
// --- Изменено: приватные поля + INotifyPropertyChanged ---
|
|
|
|
|
private string _leftPath = string.Empty;
|
|
|
|
|
private string _rightPath = string.Empty;
|
|
|
|
|
|
|
|
|
|
private Grid? _currentSelectedGrid; // только один выделенный элемент в интерфейсе
|
|
|
|
|
|
|
|
|
|
public string LeftPath
|
|
|
|
|
{
|
|
|
|
|
get => _leftPath;
|
|
|
|
|
@ -65,54 +62,94 @@ public partial class MainPage : ContentPage, INotifyPropertyChanged
|
|
|
|
|
private void LoadDirectory(string path, bool isLeft)
|
|
|
|
|
{
|
|
|
|
|
var items = _fileService.GetDirectoryContents(path).ToList();
|
|
|
|
|
var panel = isLeft ? LeftPanel : RightPanel;
|
|
|
|
|
var targetItems = isLeft ? LeftItems : RightItems;
|
|
|
|
|
var currentPathProperty = isLeft ? nameof(_currentLeftPath) : nameof(_currentRightPath);
|
|
|
|
|
|
|
|
|
|
// Очистка панели
|
|
|
|
|
panel.Clear();
|
|
|
|
|
targetItems.Clear();
|
|
|
|
|
|
|
|
|
|
// Заполнение
|
|
|
|
|
foreach (var item in items)
|
|
|
|
|
{
|
|
|
|
|
targetItems.Add(item);
|
|
|
|
|
|
|
|
|
|
var button = new Button
|
|
|
|
|
{
|
|
|
|
|
Text = item.DisplayText,
|
|
|
|
|
TextColor = Colors.Black,
|
|
|
|
|
Padding = new Thickness(10),
|
|
|
|
|
HeightRequest = 40,
|
|
|
|
|
BackgroundColor = Colors.Transparent,
|
|
|
|
|
BorderWidth = 0,
|
|
|
|
|
CommandParameter = item
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
button.Clicked += isLeft ? OnLeftItemActivated : OnRightItemActivated;
|
|
|
|
|
|
|
|
|
|
// Добавляем визуальные состояния
|
|
|
|
|
var normal = new VisualState { Name = "Normal" };
|
|
|
|
|
var focused = new VisualState { Name = "Focused" };
|
|
|
|
|
focused.Setters.Add(new Setter { Property = Button.BorderColorProperty, Value = Colors.Black });
|
|
|
|
|
focused.Setters.Add(new Setter { Property = Button.BorderWidthProperty, Value = 2 });
|
|
|
|
|
|
|
|
|
|
var pressed = new VisualState { Name = "Pressed" };
|
|
|
|
|
pressed.Setters.Add(new Setter { Property = Button.BackgroundColorProperty, Value = Color.FromArgb("#e0e0e0") });
|
|
|
|
|
|
|
|
|
|
var commonStates = new VisualStateGroup { Name = "CommonStates" };
|
|
|
|
|
commonStates.States.Add(normal);
|
|
|
|
|
commonStates.States.Add(focused);
|
|
|
|
|
commonStates.States.Add(pressed);
|
|
|
|
|
|
|
|
|
|
var groups = new VisualStateGroupList();
|
|
|
|
|
groups.Add(commonStates);
|
|
|
|
|
|
|
|
|
|
VisualStateManager.SetVisualStateGroups(button, groups);
|
|
|
|
|
|
|
|
|
|
panel.Add(button);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Обновление пути
|
|
|
|
|
if (isLeft)
|
|
|
|
|
{
|
|
|
|
|
LeftItems.Clear();
|
|
|
|
|
foreach (var item in items) LeftItems.Add(item);
|
|
|
|
|
_currentLeftPath = path;
|
|
|
|
|
LeftPath = path; // Теперь это вызовет обновление UI
|
|
|
|
|
LeftPath = path;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
RightItems.Clear();
|
|
|
|
|
foreach (var item in items) RightItems.Add(item);
|
|
|
|
|
_currentRightPath = path;
|
|
|
|
|
RightPath = path; // И это тоже
|
|
|
|
|
RightPath = path;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnLeftSelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
|
|
|
private void OnLeftItemActivated(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e.CurrentSelection.FirstOrDefault() is FileSystemItem item)
|
|
|
|
|
{
|
|
|
|
|
// Сохраняем выбор
|
|
|
|
|
_selectedLeftItem = item;
|
|
|
|
|
var button = (Button)sender;
|
|
|
|
|
var item = (FileSystemItem)button.CommandParameter;
|
|
|
|
|
|
|
|
|
|
// Если это ".." или папка — переходим
|
|
|
|
|
if (item.Name == ".." || item.IsDirectory)
|
|
|
|
|
{
|
|
|
|
|
LoadDirectory(item.FullName, true);
|
|
|
|
|
// После перехода — сбрасываем выбор, чтобы не осталось выделения в новой папке
|
|
|
|
|
_selectedLeftItem = null;
|
|
|
|
|
LeftPanel.SelectedItem = null;
|
|
|
|
|
}
|
|
|
|
|
// Если это файл — ничего не делаем, оставляем его выделенным
|
|
|
|
|
_selectedLeftItem = item;
|
|
|
|
|
_selectedRightItem = null;
|
|
|
|
|
|
|
|
|
|
if (item.IsDirectory)
|
|
|
|
|
{
|
|
|
|
|
LoadDirectory(item.FullName, true);
|
|
|
|
|
_selectedLeftItem = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnRightSelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
|
|
|
private void OnRightItemActivated(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e.CurrentSelection.FirstOrDefault() is FileSystemItem item)
|
|
|
|
|
{
|
|
|
|
|
_selectedRightItem = item;
|
|
|
|
|
var button = (Button)sender;
|
|
|
|
|
var item = (FileSystemItem)button.CommandParameter;
|
|
|
|
|
|
|
|
|
|
if (item.Name == ".." || item.IsDirectory)
|
|
|
|
|
{
|
|
|
|
|
LoadDirectory(item.FullName, false);
|
|
|
|
|
_selectedRightItem = null;
|
|
|
|
|
RightPanel.SelectedItem = null;
|
|
|
|
|
}
|
|
|
|
|
_selectedRightItem = item;
|
|
|
|
|
_selectedLeftItem = null;
|
|
|
|
|
|
|
|
|
|
if (item.IsDirectory)
|
|
|
|
|
{
|
|
|
|
|
LoadDirectory(item.FullName, false);
|
|
|
|
|
_selectedRightItem = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -153,7 +190,6 @@ public partial class MainPage : ContentPage, INotifyPropertyChanged
|
|
|
|
|
else
|
|
|
|
|
File.Delete(item.FullName);
|
|
|
|
|
|
|
|
|
|
// Обновляем обе панели (или только ту, откуда удалили)
|
|
|
|
|
LoadDirectory(_currentLeftPath, true);
|
|
|
|
|
LoadDirectory(_currentRightPath, false);
|
|
|
|
|
}
|
|
|
|
|
@ -164,7 +200,6 @@ public partial class MainPage : ContentPage, INotifyPropertyChanged
|
|
|
|
|
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());
|
|
|
|
|
|
|
|
|
|
@ -209,13 +244,11 @@ public partial class MainPage : ContentPage, INotifyPropertyChanged
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Определяем целевую директорию: противоположная панель
|
|
|
|
|
string destDir = (srcItem == _selectedLeftItem) ? _currentRightPath : _currentLeftPath;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
await operation(srcItem.FullName, destDir);
|
|
|
|
|
// Обновляем обе панели
|
|
|
|
|
LoadDirectory(_currentLeftPath, true);
|
|
|
|
|
LoadDirectory(_currentRightPath, false);
|
|
|
|
|
}
|
|
|
|
|
@ -225,81 +258,6 @@ public partial class MainPage : ContentPage, INotifyPropertyChanged
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnLeftItemTapped(object sender, TappedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
var grid = (Grid)sender;
|
|
|
|
|
var item = (FileSystemItem)grid.BindingContext;
|
|
|
|
|
|
|
|
|
|
// Сбрасываем выделение у предыдущего элемента (где бы он ни был)
|
|
|
|
|
if (_currentSelectedGrid != null)
|
|
|
|
|
{
|
|
|
|
|
_currentSelectedGrid.BackgroundColor = Colors.Transparent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Выделяем новый элемент
|
|
|
|
|
grid.BackgroundColor = Color.FromArgb("#d0e0ff");
|
|
|
|
|
_currentSelectedGrid = grid;
|
|
|
|
|
|
|
|
|
|
// Обновляем активный выбор
|
|
|
|
|
_selectedLeftItem = item;
|
|
|
|
|
_selectedRightItem = null; // сбрасываем выбор в правой панели
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnLeftItemDoubleTapped(object sender, TappedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
var grid = (Grid)sender;
|
|
|
|
|
var item = (FileSystemItem)grid.BindingContext;
|
|
|
|
|
|
|
|
|
|
if (item.IsDirectory)
|
|
|
|
|
{
|
|
|
|
|
LoadDirectory(item.FullName, isLeft: true);
|
|
|
|
|
// Сбрасываем выделение, так как панель обновляется
|
|
|
|
|
if (_currentSelectedGrid != null)
|
|
|
|
|
{
|
|
|
|
|
_currentSelectedGrid.BackgroundColor = Colors.Transparent;
|
|
|
|
|
_currentSelectedGrid = null;
|
|
|
|
|
}
|
|
|
|
|
_selectedLeftItem = null;
|
|
|
|
|
_selectedRightItem = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnRightItemTapped(object sender, TappedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
var grid = (Grid)sender;
|
|
|
|
|
var item = (FileSystemItem)grid.BindingContext;
|
|
|
|
|
|
|
|
|
|
if (_currentSelectedGrid != null)
|
|
|
|
|
{
|
|
|
|
|
_currentSelectedGrid.BackgroundColor = Colors.Transparent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
grid.BackgroundColor = Color.FromArgb("#d0e0ff");
|
|
|
|
|
_currentSelectedGrid = grid;
|
|
|
|
|
|
|
|
|
|
_selectedRightItem = item;
|
|
|
|
|
_selectedLeftItem = null; // сбрасываем выбор в левой панели
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnRightItemDoubleTapped(object sender, TappedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
var grid = (Grid)sender;
|
|
|
|
|
var item = (FileSystemItem)grid.BindingContext;
|
|
|
|
|
|
|
|
|
|
if (item.IsDirectory)
|
|
|
|
|
{
|
|
|
|
|
LoadDirectory(item.FullName, isLeft: false);
|
|
|
|
|
if (_currentSelectedGrid != null)
|
|
|
|
|
{
|
|
|
|
|
_currentSelectedGrid.BackgroundColor = Colors.Transparent;
|
|
|
|
|
_currentSelectedGrid = null;
|
|
|
|
|
}
|
|
|
|
|
_selectedLeftItem = null;
|
|
|
|
|
_selectedRightItem = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Реализация INotifyPropertyChanged ---
|
|
|
|
|
public new event PropertyChangedEventHandler? PropertyChanged;
|
|
|
|
|
|
|
|
|
|
protected virtual void NotifyPropertyChanged([CallerMemberName] string? propertyName = null)
|
|
|
|
|
|