using System.Diagnostics;
using CORP_MAUI.Pages;
namespace CORP_MAUI;
public partial class AppShell : Shell
{
// Порог ширины для переключения на вертикальное меню (в пикселях)
private const double WideScreenThreshold = 768;
private bool _isDesktopMode;
private int _lastNonMenuTabIndex = 2; // По умолчанию - Лента
public AppShell()
{
try
{
Trace.WriteLine("=== APP SHELL 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));
Routing.RegisterRoute(nameof(MenuPage), typeof(MenuPage));
Routing.RegisterRoute(nameof(DepartmentsPage), typeof(DepartmentsPage));
Routing.RegisterRoute(nameof(ProfilePage), typeof(ProfilePage));
Routing.RegisterRoute(nameof(DocumentsPage), typeof(DocumentsPage));
// Подписываемся на навигацию для сохранения предыдущей вкладки
Navigating += OnShellNavigating;
Trace.WriteLine("[AppShell] ✅ AppShell инициализирован");
Trace.WriteLine("=== APP SHELL CONSTRUCTOR END ===");
// Устанавливаем начальный режим меню
UpdateLayoutMode();
// При запуске переключаемся на ленту (индекс 2), а не на меню (индекс 0)
if (MobileTabBar?.Items?.Count > 2)
{
CurrentItem = MobileTabBar.Items[2];
}
// Инициализация без ожидания (так await нельзя из синхронного конструктора)
_ = InitializeAsync();
}
catch (Exception ex)
{
Trace.WriteLine("=== APP SHELL 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");
}
}
///
/// Сохраняет индекс текущей вкладки перед переходом на меню
///
private void OnShellNavigating(object? sender, ShellNavigatingEventArgs e)
{
// Если переходим на MenuTabPage, сохраняем текущую вкладку
if (e.Target?.Location?.OriginalString?.Contains("MenuTab") == true)
{
// Сохраняем индекс текущей вкладки (не меню)
if (MobileTabBar != null)
{
for (int i = 1; i < MobileTabBar.Items.Count; i++)
{
if (MobileTabBar.Items[i] == MobileTabBar.CurrentItem)
{
_lastNonMenuTabIndex = i;
MenuPage.SetPreviousTabIndex(i);
Trace.WriteLine($"[AppShell] Сохранена предыдущая вкладка: {i}");
break;
}
}
}
}
}
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height);
UpdateLayoutMode(width);
}
///
/// Обновляет режим макета в зависимости от ширины экрана
/// На широких экранах: Flyout (вертикальное меню слева)
/// На узких экранах: TabBar (нижняя панель)
///
private void UpdateLayoutMode(double? width = null)
{
try
{
// Получаем текущую ширину окна
double currentWidth = width ?? 0;
// Если ширина не передана, пытаемся получить из разных источников
if (currentWidth <= 0)
{
// Пробуем получить из Window
var window = Application.Current?.Windows.FirstOrDefault();
if (window != null && window.Width > 0)
{
currentWidth = window.Width;
}
}
if (currentWidth <= 0)
{
// Пробуем получить из DeviceDisplay
var displayInfo = DeviceDisplay.MainDisplayInfo;
if (displayInfo.Width > 0 && displayInfo.Density > 0)
{
currentWidth = displayInfo.Width / displayInfo.Density;
}
}
// На Windows/Desktop по умолчанию считаем широким экраном если не удалось определить
if (currentWidth <= 0)
{
#if WINDOWS || MACCATALYST
currentWidth = 1200; // Предполагаем десктоп
#else
currentWidth = 400; // Предполагаем мобильное устройство
#endif
}
bool shouldBeDesktop = currentWidth >= WideScreenThreshold;
Trace.WriteLine($"[AppShell] UpdateLayoutMode: width={currentWidth}, threshold={WideScreenThreshold}, shouldBeDesktop={shouldBeDesktop}, currentMode={_isDesktopMode}");
// При первом запуске (_isDesktopMode = false) или при изменении режима
bool isFirstRun = !_isDesktopMode && shouldBeDesktop;
// Проверяем, нужно ли менять режим
if (shouldBeDesktop == _isDesktopMode && !isFirstRun)
{
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] >>> Переключение на десктопный режим (DesktopLayout)");
// Скрываем TabBar
MobileTabBar.IsVisible = false;
// Скрываем FlyoutItems (не используем Flyout)
DesktopFlyoutNews.IsVisible = false;
DesktopFlyoutEmployees.IsVisible = false;
DesktopFlyoutDepartments.IsVisible = false;
DesktopFlyoutChats.IsVisible = false;
DesktopFlyoutRequests.IsVisible = false;
DesktopFlyoutDocuments.IsVisible = false;
DesktopFlyoutProfile.IsVisible = false;
// Отключаем Flyout
FlyoutBehavior = FlyoutBehavior.Disabled;
// Переключаем MainPage на DesktopMainPage
if (Application.Current?.Windows.Count > 0)
{
Application.Current.Windows[0].Page = new DesktopMainPage();
}
Trace.WriteLine("[AppShell] ✅ Десктопный режим активирован");
}
catch (Exception ex)
{
Trace.WriteLine($"[AppShell] ❌ Ошибка SwitchToDesktopMode: {ex.Message}");
}
}
private void SwitchToMobileMode()
{
try
{
Trace.WriteLine("[AppShell] >>> Переключение на мобильный режим (TabBar)");
// Если текущая страница - DesktopMainPage, возвращаем AppShell
if (Application.Current?.Windows.Count > 0 && Application.Current.Windows[0].Page is DesktopMainPage)
{
Application.Current.Windows[0].Page = this;
}
// Скрываем FlyoutItems
DesktopFlyoutNews.IsVisible = false;
DesktopFlyoutEmployees.IsVisible = false;
DesktopFlyoutDepartments.IsVisible = false;
DesktopFlyoutChats.IsVisible = false;
DesktopFlyoutRequests.IsVisible = false;
DesktopFlyoutDocuments.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}");
}
}
}