скролл

main
Пилипенко Андрей Борисович 3 weeks ago
parent f7ad317c67
commit a7cbcd821e

@ -30,7 +30,7 @@
<ScrollView x:Name="LeftScrollView"
Grid.Row="2" Grid.Column="0"
BackgroundColor="White">
<VerticalStackLayout x:Name="LeftPanel" Spacing="0"/>
<VerticalStackLayout x:Name="LeftPanel" Spacing="0"/>
</ScrollView>
<!-- Правая панель -->

@ -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 ===");

@ -1,46 +0,0 @@
namespace CommanderApp.Services;
public class MockFileOperations : IFileOperations
{
public List<string> CopiedFiles { get; } = new();
public List<string> MovedFiles { get; } = new();
public List<string> DeletedItems { get; } = new();
public List<string> CreatedDirectories { get; } = new();
public List<string> OpenedFiles { get; } = new();
public Task<bool> CopyAsync(string sourcePath, string targetPath, bool overwrite = true)
{
CopiedFiles.Add($"{sourcePath} -> {targetPath}");
return Task.FromResult(true);
}
public Task<bool> MoveAsync(string sourcePath, string targetPath, bool overwrite = true)
{
MovedFiles.Add($"{sourcePath} -> {targetPath}");
return Task.FromResult(true);
}
public Task<bool> DeleteAsync(string path)
{
DeletedItems.Add(path);
return Task.FromResult(true);
}
public Task<bool> CreateDirectoryAsync(string path)
{
CreatedDirectories.Add(path);
return Task.FromResult(true);
}
public Task<bool> OpenFileAsync(string filePath)
{
OpenedFiles.Add(filePath);
return Task.FromResult(true);
}
public Task<bool> CopyDirectoryAsync(string sourceDir, string targetDir)
{
CopiedFiles.Add($"DIR: {sourceDir} -> {targetDir}");
return Task.FromResult(true);
}
}

@ -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
};
}
}

@ -1,81 +0,0 @@
namespace CommanderApp;
public class MockFileSystemService : IFileSystemService
{
public string MockRootPath { get; set; } = "/mock/root";
private readonly Dictionary<string, List<FileSystemItem>> _mockDirectories = new();
public MockFileSystemService()
{
// Инициализируем mock данными
SetupMockData();
}
private void SetupMockData()
{
_mockDirectories["/mock/root"] = new List<FileSystemItem>
{
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<FileSystemItem>
{
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<FileSystemItem>
{
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<FileSystemItem> GetDirectoryContents(string path)
{
if (_mockDirectories.ContainsKey(path))
{
return _mockDirectories[path];
}
// Если директории нет в mock данных, возвращаем пустой список с ".."
var parent = GetParentPath(path);
if (parent != null)
{
return new List<FileSystemItem>
{
new FileSystemItem { Name = "..", FullName = parent, IsDirectory = true }
};
}
return Enumerable.Empty<FileSystemItem>();
}
// Метод для добавления mock данных в тестах
public void AddMockDirectory(string path, List<FileSystemItem> 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;
}
}

@ -1,17 +0,0 @@
namespace CommanderApp.Services;
public class MockKeyboardService : IKeyboardService
{
public event EventHandler<KeyPressedEventArgs> 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" });
}
}

@ -1,50 +0,0 @@
using System.Collections.ObjectModel;
namespace CommanderApp.Services;
public class MockPanelManager : IPanelManager
{
public event EventHandler<PanelStateChangedEventArgs> 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<FileSystemItem> LeftItems { get; } = new();
public ObservableCollection<FileSystemItem> 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;
}
}

@ -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;
}
Loading…
Cancel
Save