232 lines
9.7 KiB
C#
232 lines
9.7 KiB
C#
using System.Diagnostics;
|
||
using CORP_MAUI.Pages;
|
||
|
||
namespace CORP_MAUI;
|
||
|
||
public partial class AppShell : Shell
|
||
{
|
||
// Порог ширины для переключения на вертикальное меню (в пикселях)
|
||
private const double WideScreenThreshold = 768;
|
||
private bool _isDesktopMode;
|
||
|
||
public AppShell()
|
||
{
|
||
try
|
||
{
|
||
Trace.WriteLine("=== APPSHELL CONSTRUCTOR START ===");
|
||
Trace.WriteLine("[AppShell] >>> Вызов InitializeComponent");
|
||
|
||
InitializeComponent();
|
||
|
||
Trace.WriteLine("[AppShell] >>> InitializeComponent завершен");
|
||
Trace.WriteLine("[AppShell] >>> Регистрация маршрутов");
|
||
|
||
// Регистрация маршрутов для навигации
|
||
Routing.RegisterRoute(nameof(ChatPage), typeof(ChatPage));
|
||
Routing.RegisterRoute(nameof(DepartmentDetailsPage), typeof(DepartmentDetailsPage));
|
||
Routing.RegisterRoute(nameof(EmployeeProfilePage), typeof(EmployeeProfilePage));
|
||
|
||
Trace.WriteLine("[AppShell] ✅ AppShell инициализирован");
|
||
Trace.WriteLine("=== APPSHELL CONSTRUCTOR END ===");
|
||
|
||
// Устанавливаем начальный режим меню
|
||
UpdateLayoutMode();
|
||
|
||
// Инициализация без ожидания (так await нельзя из синхронного конструктора)
|
||
_ = InitializeAsync();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Trace.WriteLine("=== APPSHELL CONSTRUCTOR ERROR ===");
|
||
Trace.WriteLine($"[AppShell] ❌ Тип ошибки: {ex.GetType().FullName}");
|
||
Trace.WriteLine($"[AppShell] ❌ Сообщение: {ex.Message}");
|
||
Trace.WriteLine($"[AppShell] ❌ StackTrace: {ex.StackTrace}");
|
||
if (ex.InnerException != null)
|
||
{
|
||
Trace.WriteLine($"[AppShell] ❌ InnerException: {ex.InnerException.Message}");
|
||
Trace.WriteLine($"[AppShell] ❌ InnerException StackTrace: {ex.InnerException.StackTrace}");
|
||
}
|
||
|
||
// Показываем ошибку в диалоге
|
||
Task.Run(async () =>
|
||
{
|
||
await Task.Delay(100);
|
||
await MainThread.InvokeOnMainThreadAsync(async () =>
|
||
{
|
||
Page? mainPage = Application.Current?.Windows.FirstOrDefault()?.Page;
|
||
if (mainPage != null)
|
||
{
|
||
await mainPage.DisplayAlert("Ошибка AppShell",
|
||
$"Ошибка инициализации AppShell:\n{ex.Message}\n\nStackTrace:\n{ex.StackTrace}", "OK");
|
||
}
|
||
});
|
||
});
|
||
|
||
throw;
|
||
}
|
||
}
|
||
|
||
private async Task InitializeAsync()
|
||
{
|
||
try
|
||
{
|
||
Trace.WriteLine("[AppShell] >>> Начало InitializeAsync");
|
||
|
||
// Инициализация сервисов (если они не инициализированы)
|
||
ServiceProvider.Initialize();
|
||
|
||
Trace.WriteLine($"[AppShell] IsAuthenticated: {ServiceProvider.ApiService.IsAuthenticated}");
|
||
|
||
// Проверяем, авторизован ли пользователь (токены загружаются автоматически в ApiService)
|
||
if (ServiceProvider.ApiService.IsAuthenticated)
|
||
{
|
||
// Получаем токен для WebSocket
|
||
string? accessToken = await SecureStorage.GetAsync("api.jwt_access");
|
||
|
||
Trace.WriteLine($"[AppShell] Access token exists: {!string.IsNullOrEmpty(accessToken)}");
|
||
Trace.WriteLine($"[AppShell] WebSocket connected: {ServiceProvider.WebSocketService.IsConnected}");
|
||
|
||
if (!string.IsNullOrEmpty(accessToken) && !ServiceProvider.WebSocketService.IsConnected)
|
||
{
|
||
Trace.WriteLine("[AppShell] >>> Подключение WebSocket из AppShell");
|
||
// Подключаем WebSocket только если его еще не подключен
|
||
await ServiceProvider.WebSocketService.ConnectAsync(accessToken);
|
||
Trace.WriteLine("[AppShell] ✅ WebSocket подключен из AppShell");
|
||
}
|
||
else if (ServiceProvider.WebSocketService.IsConnected)
|
||
{
|
||
Trace.WriteLine("[AppShell] WebSocket уже подключен, пропускаем");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Trace.WriteLine("[AppShell] ⚠️ Пользователь не авторизован");
|
||
}
|
||
|
||
Trace.WriteLine("[AppShell] ✅ InitializeAsync завершен");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Trace.WriteLine($"[AppShell] ❌ Ошибка InitializeAsync: {ex.Message}");
|
||
Trace.WriteLine($"[AppShell] StackTrace: {ex.StackTrace}");
|
||
|
||
await DisplayAlert("Ошибка", $"Ошибка инициализации: {ex.Message}", "OK");
|
||
}
|
||
}
|
||
|
||
protected override void OnSizeAllocated(double width, double height)
|
||
{
|
||
base.OnSizeAllocated(width, height);
|
||
UpdateLayoutMode(width);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Обновляет режим макета в зависимости от ширины экрана
|
||
/// На широких экранах: Flyout (вертикальное меню слева)
|
||
/// На узких экранах: TabBar (нижняя панель)
|
||
/// </summary>
|
||
private void UpdateLayoutMode(double? width = null)
|
||
{
|
||
try
|
||
{
|
||
// Получаем текущую ширину окна
|
||
double currentWidth = width ?? (Application.Current?.Windows.FirstOrDefault()?.Width ?? 0);
|
||
|
||
if (currentWidth <= 0)
|
||
{
|
||
// Если ширина не определена, используем DeviceDisplay
|
||
currentWidth = DeviceDisplay.MainDisplayInfo.Width / DeviceDisplay.MainDisplayInfo.Density;
|
||
}
|
||
|
||
bool shouldBeDesktop = currentWidth >= WideScreenThreshold;
|
||
|
||
Trace.WriteLine($"[AppShell] UpdateLayoutMode: width={currentWidth}, threshold={WideScreenThreshold}, shouldBeDesktop={shouldBeDesktop}, currentMode={_isDesktopMode}");
|
||
|
||
// Проверяем, нужно ли менять режим
|
||
if (shouldBeDesktop == _isDesktopMode)
|
||
{
|
||
return; // Режим не изменился
|
||
}
|
||
|
||
_isDesktopMode = shouldBeDesktop;
|
||
|
||
if (_isDesktopMode)
|
||
{
|
||
// Десктопный режим - показываем Flyout, скрываем TabBar
|
||
SwitchToDesktopMode();
|
||
}
|
||
else
|
||
{
|
||
// Мобильный режим - показываем TabBar, скрываем Flyout
|
||
SwitchToMobileMode();
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Trace.WriteLine($"[AppShell] ⚠️ Ошибка UpdateLayoutMode: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
private void SwitchToDesktopMode()
|
||
{
|
||
try
|
||
{
|
||
Trace.WriteLine("[AppShell] >>> Переключение на десктопный режим (Flyout)");
|
||
|
||
// Скрываем TabBar
|
||
MobileTabBar.IsVisible = false;
|
||
|
||
// Показываем FlyoutItems
|
||
DesktopFlyoutNews.IsVisible = true;
|
||
DesktopFlyoutEmployees.IsVisible = true;
|
||
DesktopFlyoutDepartments.IsVisible = true;
|
||
DesktopFlyoutRequests.IsVisible = true;
|
||
DesktopFlyoutProfile.IsVisible = true;
|
||
|
||
// Включаем Flyout в режим Locked (всегда видим)
|
||
FlyoutBehavior = FlyoutBehavior.Locked;
|
||
FlyoutIsPresented = true;
|
||
|
||
// Переходим на первый FlyoutItem
|
||
CurrentItem = DesktopFlyoutNews;
|
||
|
||
Trace.WriteLine("[AppShell] ✅ Десктопный режим активирован");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Trace.WriteLine($"[AppShell] ❌ Ошибка SwitchToDesktopMode: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
private void SwitchToMobileMode()
|
||
{
|
||
try
|
||
{
|
||
Trace.WriteLine("[AppShell] >>> Переключение на мобильный режим (TabBar)");
|
||
|
||
// Скрываем FlyoutItems
|
||
DesktopFlyoutNews.IsVisible = false;
|
||
DesktopFlyoutEmployees.IsVisible = false;
|
||
DesktopFlyoutDepartments.IsVisible = false;
|
||
DesktopFlyoutRequests.IsVisible = false;
|
||
DesktopFlyoutProfile.IsVisible = false;
|
||
|
||
// Отключаем Flyout
|
||
FlyoutBehavior = FlyoutBehavior.Disabled;
|
||
FlyoutIsPresented = false;
|
||
|
||
// Показываем TabBar
|
||
MobileTabBar.IsVisible = true;
|
||
|
||
// Переходим на TabBar
|
||
CurrentItem = MobileTabBar;
|
||
|
||
Trace.WriteLine("[AppShell] ✅ Мобильный режим активирован");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Trace.WriteLine($"[AppShell] ❌ Ошибка SwitchToMobileMode: {ex.Message}");
|
||
}
|
||
}
|
||
}
|