corp-app/CORP-MAUI/AppShell.xaml.cs

312 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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");
}
}
/// <summary>
/// Сохраняет индекс текущей вкладки перед переходом на меню
/// </summary>
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);
}
/// <summary>
/// Обновляет режим макета в зависимости от ширины экрана
/// На широких экранах: Flyout (вертикальное меню слева)
/// На узких экранах: TabBar (нижняя панель)
/// </summary>
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}");
}
}
}