diff --git a/MainPage.xaml b/MainPage.xaml
index 3707378..bf2e7ef 100644
--- a/MainPage.xaml
+++ b/MainPage.xaml
@@ -30,7 +30,7 @@
-
+
diff --git a/MainPage.xaml.cs b/MainPage.xaml.cs
index e579eb0..0f1d4e3 100644
--- a/MainPage.xaml.cs
+++ b/MainPage.xaml.cs
@@ -1,4 +1,4 @@
-using System.ComponentModel;
+using System.ComponentModel;
using System.Runtime.CompilerServices;
using CommanderApp.Services;
@@ -141,6 +141,9 @@ public partial class MainPage : ContentPage, INotifyPropertyChanged
OnHomeClicked(this, EventArgs.Empty);
break;
}
+
+ // Всегда скроллим после любого действия с клавиатуры
+ ScrollToSelectedItem();
});
}
@@ -159,6 +162,9 @@ public partial class MainPage : ContentPage, INotifyPropertyChanged
var button = RightPanel.Children[e.RightSelectedIndex] as Button;
button?.Focus();
}
+
+ // Скроллим при изменении состояния
+ ScrollToSelectedItem();
}
private void SetInitialFocus()
@@ -178,6 +184,7 @@ public partial class MainPage : ContentPage, INotifyPropertyChanged
if (focused)
{
_panelManager.SetSelection(0, true);
+ ScrollToSelectedItem();
}
}
}
@@ -188,6 +195,55 @@ public partial class MainPage : ContentPage, INotifyPropertyChanged
}
}
+ // Простой и надежный метод скролла
+ private async void ScrollToSelectedItem()
+ {
+ try
+ {
+ await Task.Delay(50); // Небольшая задержка для стабильности
+
+ if (_panelManager.IsLeftPanelActive)
+ {
+ if (_panelManager.LeftSelectedIndex >= 0 && _panelManager.LeftSelectedIndex < LeftPanel.Children.Count)
+ {
+ // Вычисляем позицию для скролла
+ var itemHeight = 40; // Высота одного элемента
+ var scrollViewHeight = LeftScrollView.Height; // Высота видимой области
+ var visibleItems = (int)(scrollViewHeight / itemHeight); // Сколько элементов видно
+
+ // Вычисляем целевой скролл, чтобы элемент был в середине видимой области
+ var targetScrollY = Math.Max(0, (_panelManager.LeftSelectedIndex - visibleItems / 2) * itemHeight);
+
+ await LeftScrollView.ScrollToAsync(0, targetScrollY, true);
+
+ System.Diagnostics.Debug.WriteLine($"Left scroll: index={_panelManager.LeftSelectedIndex}, targetY={targetScrollY}");
+ }
+ }
+ else
+ {
+ if (_panelManager.RightSelectedIndex >= 0 && _panelManager.RightSelectedIndex < RightPanel.Children.Count)
+ {
+ // Вычисляем позицию для скролла
+ var itemHeight = 40; // Высота одного элемента
+ var scrollViewHeight = RightScrollView.Height; // Высота видимой области
+ var visibleItems = (int)(scrollViewHeight / itemHeight); // Сколько элементов видно
+
+ // Вычисляем целевой скролл, чтобы элемент был в середине видимой области
+ var targetScrollY = Math.Max(0, (_panelManager.RightSelectedIndex - visibleItems / 2) * itemHeight);
+
+ await RightScrollView.ScrollToAsync(0, targetScrollY, true);
+
+ System.Diagnostics.Debug.WriteLine($"Right scroll: index={_panelManager.RightSelectedIndex}, targetY={targetScrollY}");
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"Scroll error: {ex.Message}");
+ }
+ }
+
+ // Остальные методы без изменений...
private void OpenSelectedItem()
{
var item = _panelManager.SelectedItem;
@@ -302,6 +358,7 @@ public partial class MainPage : ContentPage, INotifyPropertyChanged
{
var firstButton = panel.Children[0] as Button;
firstButton?.Focus();
+ ScrollToSelectedItem();
});
}
}
@@ -327,29 +384,6 @@ public partial class MainPage : ContentPage, INotifyPropertyChanged
CornerRadius = 0
};
- // Устанавливаем тематический цвет текста
- // button.SetAppThemeColor(Button.TextColorProperty, Colors.Black, Colors.White);
-
- // Визуальные состояния для фокуса
- var visualStateGroups = new VisualStateGroupList();
- var commonStates = new VisualStateGroup { Name = "CommonStates" };
-
- var normalState = new VisualState { Name = "Normal" };
- normalState.Setters.Add(new Setter { Property = Button.BackgroundColorProperty, Value = NormalButtonColor });
-
- var focusedState = new VisualState { Name = "Focused" };
- focusedState.Setters.Add(new Setter { Property = Button.BackgroundColorProperty, Value = FocusedButtonColor });
-
- var pressedState = new VisualState { Name = "Pressed" };
- pressedState.Setters.Add(new Setter { Property = Button.BackgroundColorProperty, Value = NormalButtonColor });
-
- commonStates.States.Add(normalState);
- commonStates.States.Add(focusedState);
- commonStates.States.Add(pressedState);
- visualStateGroups.Add(commonStates);
-
- VisualStateManager.SetVisualStateGroups(button, visualStateGroups);
-
// Обработчик клика - выделение при клике, открытие при двойном клике
button.Clicked += (s, e) => HandleItemClick(button, item, isLeft);
@@ -387,6 +421,7 @@ public partial class MainPage : ContentPage, INotifyPropertyChanged
// Устанавливаем фокус на кнопку
button.Focus();
+ ScrollToSelectedItem();
}
// Если это двойной клик - открываем/запускаем
@@ -403,7 +438,7 @@ public partial class MainPage : ContentPage, INotifyPropertyChanged
}
}
- // Команды тулбара
+ // Команды тулбара (без изменений)
private async void OnCopyClicked(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("=== BUTTON: F5 Copy ===");
diff --git a/MockFileOperations.cs b/MockFileOperations.cs
deleted file mode 100644
index 59a4ab0..0000000
--- a/MockFileOperations.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-namespace CommanderApp.Services;
-
-public class MockFileOperations : IFileOperations
-{
- public List CopiedFiles { get; } = new();
- public List MovedFiles { get; } = new();
- public List DeletedItems { get; } = new();
- public List CreatedDirectories { get; } = new();
- public List OpenedFiles { get; } = new();
-
- public Task CopyAsync(string sourcePath, string targetPath, bool overwrite = true)
- {
- CopiedFiles.Add($"{sourcePath} -> {targetPath}");
- return Task.FromResult(true);
- }
-
- public Task MoveAsync(string sourcePath, string targetPath, bool overwrite = true)
- {
- MovedFiles.Add($"{sourcePath} -> {targetPath}");
- return Task.FromResult(true);
- }
-
- public Task DeleteAsync(string path)
- {
- DeletedItems.Add(path);
- return Task.FromResult(true);
- }
-
- public Task CreateDirectoryAsync(string path)
- {
- CreatedDirectories.Add(path);
- return Task.FromResult(true);
- }
-
- public Task OpenFileAsync(string filePath)
- {
- OpenedFiles.Add(filePath);
- return Task.FromResult(true);
- }
-
- public Task CopyDirectoryAsync(string sourceDir, string targetDir)
- {
- CopiedFiles.Add($"DIR: {sourceDir} -> {targetDir}");
- return Task.FromResult(true);
- }
-}
\ No newline at end of file
diff --git a/MockFileSystemItem.cs b/MockFileSystemItem.cs
deleted file mode 100644
index 6192aa7..0000000
--- a/MockFileSystemItem.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-namespace CommanderApp;
-
-public static class MockFileSystemItem
-{
- public static FileSystemItem CreateDirectory(string name, string path)
- {
- return new FileSystemItem
- {
- Name = name,
- FullName = path,
- IsDirectory = true
- };
- }
-
- public static FileSystemItem CreateFile(string name, string path)
- {
- return new FileSystemItem
- {
- Name = name,
- FullName = path,
- IsDirectory = false
- };
- }
-
- public static FileSystemItem CreateParentDirectory(string path)
- {
- return new FileSystemItem
- {
- Name = "..",
- FullName = path,
- IsDirectory = true
- };
- }
-}
\ No newline at end of file
diff --git a/MockFileSystemService.cs b/MockFileSystemService.cs
deleted file mode 100644
index 4b5a225..0000000
--- a/MockFileSystemService.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-namespace CommanderApp;
-
-public class MockFileSystemService : IFileSystemService
-{
- public string MockRootPath { get; set; } = "/mock/root";
-
- private readonly Dictionary> _mockDirectories = new();
-
- public MockFileSystemService()
- {
- // Инициализируем mock данными
- SetupMockData();
- }
-
- private void SetupMockData()
- {
- _mockDirectories["/mock/root"] = new List
- {
- new FileSystemItem { Name = "Documents", FullName = "/mock/root/Documents", IsDirectory = true },
- new FileSystemItem { Name = "Pictures", FullName = "/mock/root/Pictures", IsDirectory = true },
- new FileSystemItem { Name = "readme.txt", FullName = "/mock/root/readme.txt", IsDirectory = false },
- new FileSystemItem { Name = "..", FullName = "/mock", IsDirectory = true }
- };
-
- _mockDirectories["/mock/root/Documents"] = new List
- {
- new FileSystemItem { Name = "Project1", FullName = "/mock/root/Documents/Project1", IsDirectory = true },
- new FileSystemItem { Name = "Project2", FullName = "/mock/root/Documents/Project2", IsDirectory = true },
- new FileSystemItem { Name = "notes.txt", FullName = "/mock/root/Documents/notes.txt", IsDirectory = false },
- new FileSystemItem { Name = "..", FullName = "/mock/root", IsDirectory = true }
- };
-
- _mockDirectories["/mock/root/Pictures"] = new List
- {
- new FileSystemItem { Name = "vacation.jpg", FullName = "/mock/root/Pictures/vacation.jpg", IsDirectory = false },
- new FileSystemItem { Name = "..", FullName = "/mock/root", IsDirectory = true }
- };
- }
-
- public string GetRootPath()
- {
- return MockRootPath;
- }
-
- public IEnumerable GetDirectoryContents(string path)
- {
- if (_mockDirectories.ContainsKey(path))
- {
- return _mockDirectories[path];
- }
-
- // Если директории нет в mock данных, возвращаем пустой список с ".."
- var parent = GetParentPath(path);
- if (parent != null)
- {
- return new List
- {
- new FileSystemItem { Name = "..", FullName = parent, IsDirectory = true }
- };
- }
-
- return Enumerable.Empty();
- }
-
- // Метод для добавления mock данных в тестах
- public void AddMockDirectory(string path, List items)
- {
- _mockDirectories[path] = items;
- }
-
- private string GetParentPath(string path)
- {
- var separator = '/';
- var lastSeparator = path.LastIndexOf(separator);
- if (lastSeparator > 0)
- {
- return path.Substring(0, lastSeparator);
- }
- return null;
- }
-}
\ No newline at end of file
diff --git a/MockKeyboardService.cs b/MockKeyboardService.cs
deleted file mode 100644
index a960d78..0000000
--- a/MockKeyboardService.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace CommanderApp.Services;
-
-public class MockKeyboardService : IKeyboardService
-{
- public event EventHandler KeyPressed;
-
- public void SetupKeyboardHandling(ContentPage page)
- {
- // Mock implementation - does nothing
- }
-
- // Method to simulate key presses in tests
- public void SimulateKeyPress(string key)
- {
- KeyPressed?.Invoke(this, new KeyPressedEventArgs { Key = key, Platform = "Test" });
- }
-}
\ No newline at end of file
diff --git a/MockPanelManager.cs b/MockPanelManager.cs
deleted file mode 100644
index 59a1ff3..0000000
--- a/MockPanelManager.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using System.Collections.ObjectModel;
-
-namespace CommanderApp.Services;
-
-public class MockPanelManager : IPanelManager
-{
- public event EventHandler StateChanged;
-
- public bool IsLeftPanelActive { get; set; } = true;
- public FileSystemItem SelectedItem { get; set; }
- public string ActivePanelPath { get; set; } = "/mock/path";
- public string LeftPanelPath { get; set; } = "/left/path";
- public string RightPanelPath { get; set; } = "/right/path";
- public int LeftSelectedIndex { get; set; } = 0;
- public int RightSelectedIndex { get; set; } = -1;
-
- public ObservableCollection LeftItems { get; } = new();
- public ObservableCollection RightItems { get; } = new();
-
- public void SwitchToLeftPanel() => IsLeftPanelActive = true;
- public void SwitchToRightPanel() => IsLeftPanelActive = false;
-
- public void MoveSelection(int direction)
- {
- if (IsLeftPanelActive)
- LeftSelectedIndex = Math.Max(0, LeftSelectedIndex + direction);
- else
- RightSelectedIndex = Math.Max(0, RightSelectedIndex + direction);
- }
-
- public void SetSelection(int index, bool isLeftPanel)
- {
- if (isLeftPanel)
- LeftSelectedIndex = index;
- else
- RightSelectedIndex = index;
- }
-
- public void UpdatePanelPaths(string leftPath, string rightPath)
- {
- LeftPanelPath = leftPath;
- RightPanelPath = rightPath;
- }
-
- public void ClearSelection()
- {
- LeftSelectedIndex = -1;
- RightSelectedIndex = -1;
- }
-}
\ No newline at end of file
diff --git a/MockPathHelper.cs b/MockPathHelper.cs
deleted file mode 100644
index e4417cc..0000000
--- a/MockPathHelper.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace CommanderApp.Services;
-
-public class MockPathHelper : IPathHelper
-{
- public string MockHomePath { get; set; } = "/mock/home";
- public string MockRootPath { get; set; } = "/mock/root";
-
- public string GetUserHomePath() => MockHomePath;
- public string GetRootPath() => MockRootPath;
- public string CombinePaths(params string[] paths) => string.Join("/", paths);
- public string GetFileName(string path) => System.IO.Path.GetFileName(path);
- public string GetDirectoryName(string path) => System.IO.Path.GetDirectoryName(path) ?? string.Empty;
-}
\ No newline at end of file