| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848 |
- using TransportMauiApp.Models;
- using TransportMauiApp.Services;
- using Microsoft.Maui.Controls.Shapes;
- namespace TransportMauiApp;
- public partial class MainPage : ContentPage
- {
- private readonly DatabaseService _database = new();
- private readonly VerticalStackLayout _content = new() { Spacing = 14 };
- private readonly List<Button> _sectionButtons = [];
- private UserSession? _session;
- private bool CanEdit => _session?.IsAdministrator == true;
- private List<Driver> _drivers = [];
- private List<AppTransport> _transports = [];
- private List<TransitRoute> _routes = [];
- private List<TransportFlight> _flights = [];
- public MainPage()
- {
- InitializeComponent();
- Title = "Учет транспорта";
- ShowLogin();
- }
- private void ShowLogin()
- {
- var loginEntry = CreateEntry("Логин");
- var passwordEntry = CreateEntry("Пароль");
- passwordEntry.IsPassword = true;
- var statusLabel = new Label
- {
- TextColor = Colors.Firebrick,
- FontSize = 14,
- IsVisible = false
- };
- var loginButton = new Button
- {
- Text = "Войти",
- HeightRequest = 46,
- BackgroundColor = Color.FromArgb("#1D4ED8"),
- TextColor = Colors.White,
- CornerRadius = 8
- };
- loginButton.Clicked += async (_, _) =>
- {
- statusLabel.IsVisible = false;
- loginButton.IsEnabled = false;
- try
- {
- var login = loginEntry.Text?.Trim() ?? string.Empty;
- var password = passwordEntry.Text ?? string.Empty;
- var session = await _database.AuthenticateAsync(login, password);
- if (session is null)
- {
- statusLabel.Text = "Неверный логин или пароль.";
- statusLabel.IsVisible = true;
- return;
- }
- _session = session;
- await LoadLookupsAsync();
- ShowWorkspace();
- }
- catch (Exception ex)
- {
- statusLabel.Text = $"Ошибка подключения: {ex.Message}";
- statusLabel.IsVisible = true;
- }
- finally
- {
- loginButton.IsEnabled = true;
- }
- };
- Content = new Grid
- {
- Padding = new Thickness(22),
- Children =
- {
- new Border
- {
- StrokeThickness = 1,
- Stroke = Color.FromArgb("#D7DEE8"),
- BackgroundColor = Colors.White,
- StrokeShape = new RoundRectangle { CornerRadius = 8 },
- MaximumWidthRequest = 460,
- VerticalOptions = LayoutOptions.Center,
- HorizontalOptions = LayoutOptions.Center,
- Padding = new Thickness(24),
- Content = new VerticalStackLayout
- {
- Spacing = 14,
- Children =
- {
- new Label
- {
- Text = "Авторизация",
- FontSize = 26,
- FontAttributes = FontAttributes.Bold,
- TextColor = Color.FromArgb("#172033")
- },
- loginEntry,
- passwordEntry,
- loginButton,
- statusLabel
- }
- }
- }
- }
- };
- }
- private void ShowWorkspace()
- {
- _sectionButtons.Clear();
- _content.Children.Clear();
- var header = new Grid
- {
- ColumnDefinitions =
- {
- new ColumnDefinition(GridLength.Star),
- new ColumnDefinition(GridLength.Auto)
- },
- RowDefinitions =
- {
- new RowDefinition(GridLength.Auto),
- new RowDefinition(GridLength.Auto)
- },
- ColumnSpacing = 12
- };
- header.Add(new Label
- {
- Text = "Учет транспорта",
- FontSize = 26,
- FontAttributes = FontAttributes.Bold,
- TextColor = Color.FromArgb("#172033")
- }, 0, 0);
- var logoutButton = new Button
- {
- Text = "Выйти",
- BackgroundColor = Color.FromArgb("#EEF2F7"),
- TextColor = Color.FromArgb("#172033"),
- CornerRadius = 8
- };
- logoutButton.Clicked += (_, _) =>
- {
- _session = null;
- ShowLogin();
- };
- header.Add(logoutButton, 1, 0);
- header.Add(new Label
- {
- Text = $"Пользователь: {_session?.Login} | Роль: {_session?.DisplayRole} | Режим: {(CanEdit ? "полный доступ" : "только чтение")}",
- FontSize = 14,
- TextColor = Color.FromArgb("#526070")
- }, 0, 1);
- var tabs = new HorizontalStackLayout
- {
- Spacing = 8,
- Children =
- {
- CreateSectionButton("Водители", ShowDriversSection),
- CreateSectionButton("Транспорт", ShowTransportsSection),
- CreateSectionButton("Маршруты", ShowRoutesSection),
- CreateSectionButton("Рейсы", ShowFlightsSection),
- CreateSectionButton("Информация о рейсах", ShowFlightInfoSection)
- }
- };
- Content = new ScrollView
- {
- Content = new VerticalStackLayout
- {
- Padding = new Thickness(20),
- Spacing = 16,
- Children =
- {
- header,
- new ScrollView { Orientation = ScrollOrientation.Horizontal, Content = tabs },
- _content
- }
- }
- };
- ShowDriversSection();
- }
- private Button CreateSectionButton(string text, Action action)
- {
- var button = new Button
- {
- Text = text,
- CornerRadius = 8,
- Padding = new Thickness(14, 8),
- BackgroundColor = Colors.White,
- BorderColor = Color.FromArgb("#D7DEE8"),
- BorderWidth = 1,
- TextColor = Color.FromArgb("#172033")
- };
- button.Clicked += (_, _) =>
- {
- foreach (var tab in _sectionButtons)
- {
- tab.BackgroundColor = Colors.White;
- tab.TextColor = Color.FromArgb("#172033");
- }
- button.BackgroundColor = Color.FromArgb("#1D4ED8");
- button.TextColor = Colors.White;
- action();
- };
- _sectionButtons.Add(button);
- return button;
- }
- private async Task LoadLookupsAsync()
- {
- _drivers = [.. await _database.GetDriversAsync()];
- _transports = [.. await _database.GetTransportsAsync()];
- _routes = [.. await _database.GetRoutesAsync()];
- _flights = [.. await _database.GetFlightsAsync()];
- }
- private async void ShowDriversSection()
- {
- await LoadDriversSectionAsync();
- }
- private async Task LoadDriversSectionAsync()
- {
- _content.Children.Clear();
- await RunSafelyAsync(async () =>
- {
- _drivers = [.. await _database.GetDriversAsync()];
- var recordsCount = await _database.GetDriversCountAsync();
- var list = CreateCollectionView(_drivers);
- var nameEntry = CreateEntry("Имя");
- var surnameEntry = CreateEntry("Фамилия");
- var patronimicEntry = CreateEntry("Отчество");
- Driver? selected = null;
- list.SelectionChanged += (_, e) =>
- {
- selected = e.CurrentSelection.FirstOrDefault() as Driver;
- if (selected is null)
- {
- return;
- }
- nameEntry.Text = selected.Name;
- surnameEntry.Text = selected.Surname;
- patronimicEntry.Text = selected.Patronimic;
- };
- _content.Children.Add(CreateSectionTitle("Водители", recordsCount));
- _content.Children.Add(list);
- if (CanEdit)
- {
- _content.Children.Add(CreateForm(
- [nameEntry, surnameEntry, patronimicEntry],
- CreateCrudButtons(
- add: async () =>
- {
- if (!ValidateRequired(nameEntry, surnameEntry, patronimicEntry))
- {
- await DisplayAlertAsync("Проверка", "Заполните все поля.", "OK");
- return;
- }
- await _database.AddDriverAsync(new Driver
- {
- Name = nameEntry.Text!.Trim(),
- Surname = surnameEntry.Text!.Trim(),
- Patronimic = patronimicEntry.Text!.Trim()
- });
- ClearEntries(nameEntry, surnameEntry, patronimicEntry);
- await LoadDriversSectionAsync();
- },
- update: async () =>
- {
- if (selected is null || !ValidateRequired(nameEntry, surnameEntry, patronimicEntry))
- {
- await DisplayAlertAsync("Проверка", "Выберите запись и заполните все поля.", "OK");
- return;
- }
- selected.Name = nameEntry.Text!.Trim();
- selected.Surname = surnameEntry.Text!.Trim();
- selected.Patronimic = patronimicEntry.Text!.Trim();
- await _database.UpdateDriverAsync(selected);
- await LoadDriversSectionAsync();
- },
- delete: async () =>
- {
- if (selected is null)
- {
- await DisplayAlertAsync("Проверка", "Выберите запись.", "OK");
- return;
- }
- await _database.DeleteDriverAsync(selected.DriverId);
- await LoadDriversSectionAsync();
- })));
- }
- });
- }
- private async void ShowTransportsSection()
- {
- await LoadTransportsSectionAsync();
- }
- private async Task LoadTransportsSectionAsync()
- {
- _content.Children.Clear();
- await RunSafelyAsync(async () =>
- {
- await LoadLookupsAsync();
- var recordsCount = await _database.GetTransportsCountAsync();
- var list = CreateCollectionView(_transports);
- var branchEntry = CreateEntry("Филиал");
- var modelEntry = CreateEntry("Модель");
- var plateEntry = CreateEntry("Госномер");
- var driverPicker = CreatePicker("Водитель", _drivers);
- AppTransport? selected = null;
- list.SelectionChanged += (_, e) =>
- {
- selected = e.CurrentSelection.FirstOrDefault() as AppTransport;
- if (selected is null)
- {
- return;
- }
- branchEntry.Text = selected.Branch;
- modelEntry.Text = selected.Model;
- plateEntry.Text = selected.LicensePlateNumber;
- driverPicker.SelectedItem = _drivers.FirstOrDefault(driver => driver.DriverId == selected.DriverId);
- };
- _content.Children.Add(CreateSectionTitle("Транспорт", recordsCount));
- _content.Children.Add(list);
- if (CanEdit)
- {
- var assignButton = new Button
- {
- Text = "Назначить водителя процедурой",
- BackgroundColor = Color.FromArgb("#0F766E"),
- TextColor = Colors.White,
- CornerRadius = 8
- };
- assignButton.Clicked += async (_, _) =>
- {
- if (selected is null || driverPicker.SelectedItem is not Driver driver)
- {
- await DisplayAlertAsync("Проверка", "Выберите транспорт и водителя.", "OK");
- return;
- }
- await RunSafelyAsync(async () =>
- {
- await _database.AssignDriverToTransportAsync(selected.TransportId, driver.DriverId);
- await LoadTransportsSectionAsync();
- });
- };
- _content.Children.Add(CreateForm(
- [branchEntry, modelEntry, plateEntry, driverPicker],
- CreateCrudButtons(
- add: async () =>
- {
- if (!ValidateRequired(branchEntry, modelEntry, plateEntry))
- {
- await DisplayAlertAsync("Проверка", "Заполните филиал, модель и госномер.", "OK");
- return;
- }
- await _database.AddTransportAsync(new AppTransport
- {
- Branch = branchEntry.Text!.Trim(),
- Model = modelEntry.Text!.Trim(),
- LicensePlateNumber = plateEntry.Text!.Trim(),
- DriverId = (driverPicker.SelectedItem as Driver)?.DriverId
- });
- await LoadTransportsSectionAsync();
- },
- update: async () =>
- {
- if (selected is null || !ValidateRequired(branchEntry, modelEntry, plateEntry))
- {
- await DisplayAlertAsync("Проверка", "Выберите запись и заполните обязательные поля.", "OK");
- return;
- }
- selected.Branch = branchEntry.Text!.Trim();
- selected.Model = modelEntry.Text!.Trim();
- selected.LicensePlateNumber = plateEntry.Text!.Trim();
- selected.DriverId = (driverPicker.SelectedItem as Driver)?.DriverId;
- await _database.UpdateTransportAsync(selected);
- await LoadTransportsSectionAsync();
- },
- delete: async () =>
- {
- if (selected is null)
- {
- await DisplayAlertAsync("Проверка", "Выберите запись.", "OK");
- return;
- }
- await _database.DeleteTransportAsync(selected.TransportId);
- await LoadTransportsSectionAsync();
- },
- extra: assignButton)));
- }
- });
- }
- private async void ShowRoutesSection()
- {
- await LoadRoutesSectionAsync();
- }
- private async Task LoadRoutesSectionAsync()
- {
- _content.Children.Clear();
- await RunSafelyAsync(async () =>
- {
- _routes = [.. await _database.GetRoutesAsync()];
- var recordsCount = await _database.GetRoutesCountAsync();
- var list = CreateCollectionView(_routes);
- var routeNameEntry = CreateEntry("Название маршрута");
- TransitRoute? selected = null;
- list.SelectionChanged += (_, e) =>
- {
- selected = e.CurrentSelection.FirstOrDefault() as TransitRoute;
- routeNameEntry.Text = selected?.RouteName;
- };
- _content.Children.Add(CreateSectionTitle("Маршруты", recordsCount));
- _content.Children.Add(list);
- if (CanEdit)
- {
- _content.Children.Add(CreateForm(
- [routeNameEntry],
- CreateCrudButtons(
- add: async () =>
- {
- if (!ValidateRequired(routeNameEntry))
- {
- await DisplayAlertAsync("Проверка", "Введите название маршрута.", "OK");
- return;
- }
- await _database.AddRouteAsync(new TransitRoute { RouteName = routeNameEntry.Text!.Trim() });
- await LoadRoutesSectionAsync();
- },
- update: async () =>
- {
- if (selected is null || !ValidateRequired(routeNameEntry))
- {
- await DisplayAlertAsync("Проверка", "Выберите запись и заполните название.", "OK");
- return;
- }
- selected.RouteName = routeNameEntry.Text!.Trim();
- await _database.UpdateRouteAsync(selected);
- await LoadRoutesSectionAsync();
- },
- delete: async () =>
- {
- if (selected is null)
- {
- await DisplayAlertAsync("Проверка", "Выберите запись.", "OK");
- return;
- }
- await _database.DeleteRouteAsync(selected.RouteId);
- await LoadRoutesSectionAsync();
- })));
- }
- });
- }
- private async void ShowFlightsSection()
- {
- await LoadFlightsSectionAsync();
- }
- private async Task LoadFlightsSectionAsync()
- {
- _content.Children.Clear();
- await RunSafelyAsync(async () =>
- {
- await LoadLookupsAsync();
- var recordsCount = await _database.GetFlightsCountAsync();
- var list = CreateCollectionView(_flights);
- var durationEntry = CreateEntry("Длительность HH:mm:ss");
- var transportPicker = CreatePicker("Транспорт", _transports);
- var routePicker = CreatePicker("Маршрут", _routes);
- TransportFlight? selected = null;
- list.SelectionChanged += (_, e) =>
- {
- selected = e.CurrentSelection.FirstOrDefault() as TransportFlight;
- if (selected is null)
- {
- return;
- }
- durationEntry.Text = selected.Duration.ToString(@"hh\:mm\:ss");
- transportPicker.SelectedItem = _transports.FirstOrDefault(transport => transport.TransportId == selected.TransportId);
- routePicker.SelectedItem = _routes.FirstOrDefault(route => route.RouteId == selected.RouteId);
- };
- _content.Children.Add(CreateSectionTitle("Рейсы", recordsCount));
- _content.Children.Add(list);
- if (CanEdit)
- {
- _content.Children.Add(CreateForm(
- [durationEntry, transportPicker, routePicker],
- CreateCrudButtons(
- add: async () =>
- {
- var flight = await CreateFlightFromFormAsync(durationEntry, transportPicker, routePicker);
- if (flight is null)
- {
- return;
- }
- await _database.AddFlightAsync(flight);
- await LoadFlightsSectionAsync();
- },
- update: async () =>
- {
- var flight = await CreateFlightFromFormAsync(durationEntry, transportPicker, routePicker);
- if (selected is null || flight is null)
- {
- await DisplayAlertAsync("Проверка", "Выберите рейс и заполните поля.", "OK");
- return;
- }
- flight.FlightId = selected.FlightId;
- await _database.UpdateFlightAsync(flight);
- await LoadFlightsSectionAsync();
- },
- delete: async () =>
- {
- if (selected is null)
- {
- await DisplayAlertAsync("Проверка", "Выберите запись.", "OK");
- return;
- }
- await _database.DeleteFlightAsync(selected.FlightId);
- await LoadFlightsSectionAsync();
- })));
- }
- });
- }
- private async void ShowFlightInfoSection()
- {
- _content.Children.Clear();
- await RunSafelyAsync(async () =>
- {
- await LoadLookupsAsync();
- var routePicker = CreatePicker("Фильтр по маршруту", _routes);
- var flightInfo = await _database.GetFlightInfoAsync();
- var recordsCount = await _database.GetFlightInfoCountAsync();
- var list = CreateCollectionView(flightInfo);
- var allButton = new Button
- {
- Text = "Все рейсы",
- BackgroundColor = Color.FromArgb("#1D4ED8"),
- TextColor = Colors.White,
- CornerRadius = 8
- };
- allButton.Clicked += async (_, _) =>
- {
- await RunSafelyAsync(async () => list.ItemsSource = await _database.GetFlightInfoAsync());
- };
- var byRouteButton = new Button
- {
- Text = "По выбранному маршруту",
- BackgroundColor = Color.FromArgb("#0F766E"),
- TextColor = Colors.White,
- CornerRadius = 8
- };
- byRouteButton.Clicked += async (_, _) =>
- {
- if (routePicker.SelectedItem is not TransitRoute route)
- {
- await DisplayAlertAsync("Проверка", "Выберите маршрут.", "OK");
- return;
- }
- await RunSafelyAsync(async () => list.ItemsSource = await _database.GetFlightsByRouteAsync(route.RouteId));
- };
- _content.Children.Add(CreateSectionTitle("Информация о рейсах", recordsCount));
- _content.Children.Add(new Border
- {
- StrokeThickness = 1,
- Stroke = Color.FromArgb("#D7DEE8"),
- BackgroundColor = Colors.White,
- StrokeShape = new RoundRectangle { CornerRadius = 8 },
- Padding = new Thickness(12),
- Content = new VerticalStackLayout
- {
- Spacing = 10,
- Children =
- {
- routePicker,
- new HorizontalStackLayout
- {
- Spacing = 8,
- Children = { allButton, byRouteButton }
- }
- }
- }
- });
- _content.Children.Add(list);
- });
- }
- private async Task<TransportFlight?> CreateFlightFromFormAsync(Entry durationEntry, Picker transportPicker, Picker routePicker)
- {
- if (!TimeSpan.TryParse(durationEntry.Text, out var duration) || duration <= TimeSpan.Zero)
- {
- await DisplayAlertAsync("Проверка", "Длительность должна быть больше 00:00:00 в формате HH:mm:ss.", "OK");
- return null;
- }
- if (transportPicker.SelectedItem is not AppTransport transport || routePicker.SelectedItem is not TransitRoute route)
- {
- await DisplayAlertAsync("Проверка", "Выберите транспорт и маршрут.", "OK");
- return null;
- }
- return new TransportFlight
- {
- Duration = duration,
- TransportId = transport.TransportId,
- RouteId = route.RouteId
- };
- }
- private static Border CreateSectionTitle(string text, int recordsCount)
- {
- return new Border
- {
- StrokeThickness = 0,
- BackgroundColor = Color.FromArgb("#E8EEF6"),
- StrokeShape = new RoundRectangle { CornerRadius = 8 },
- Padding = new Thickness(14, 10),
- Content = new Label
- {
- Text = $"{text}: {recordsCount} {GetRecordsWord(recordsCount)}",
- FontSize = 20,
- FontAttributes = FontAttributes.Bold,
- TextColor = Color.FromArgb("#172033")
- }
- };
- }
- private static string GetRecordsWord(int count)
- {
- var lastTwoDigits = count % 100;
- if (lastTwoDigits is >= 11 and <= 14)
- {
- return "записей";
- }
- return (count % 10) switch
- {
- 1 => "запись",
- >= 2 and <= 4 => "записи",
- _ => "записей"
- };
- }
- private static Entry CreateEntry(string placeholder)
- {
- return new Entry
- {
- Placeholder = placeholder,
- BackgroundColor = Colors.White,
- TextColor = Color.FromArgb("#172033"),
- PlaceholderColor = Color.FromArgb("#7B8794")
- };
- }
- private static Picker CreatePicker<T>(string title, IReadOnlyList<T> items)
- {
- return new Picker
- {
- Title = title,
- ItemsSource = items.ToList(),
- BackgroundColor = Colors.White,
- TextColor = Color.FromArgb("#172033"),
- TitleColor = Color.FromArgb("#7B8794")
- };
- }
- private static CollectionView CreateCollectionView<T>(IEnumerable<T> items)
- {
- return new CollectionView
- {
- ItemsSource = items.ToList(),
- SelectionMode = SelectionMode.Single,
- EmptyView = "Нет данных",
- MinimumHeightRequest = 220,
- ItemTemplate = new DataTemplate(() =>
- {
- var label = new Label
- {
- FontSize = 15,
- TextColor = Color.FromArgb("#172033"),
- LineBreakMode = LineBreakMode.WordWrap
- };
- label.SetBinding(Label.TextProperty, ".");
- return new Border
- {
- StrokeThickness = 1,
- Stroke = Color.FromArgb("#D7DEE8"),
- BackgroundColor = Colors.White,
- StrokeShape = new RoundRectangle { CornerRadius = 8 },
- Margin = new Thickness(0, 0, 0, 8),
- Padding = new Thickness(12),
- Content = label
- };
- })
- };
- }
- private static Border CreateForm(IReadOnlyList<View> fields, HorizontalStackLayout buttons)
- {
- var stack = new VerticalStackLayout { Spacing = 10 };
- foreach (var field in fields)
- {
- stack.Children.Add(field);
- }
- stack.Children.Add(buttons);
- return new Border
- {
- StrokeThickness = 1,
- Stroke = Color.FromArgb("#D7DEE8"),
- BackgroundColor = Colors.White,
- StrokeShape = new RoundRectangle { CornerRadius = 8 },
- Padding = new Thickness(12),
- Content = stack
- };
- }
- private HorizontalStackLayout CreateCrudButtons(Func<Task> add, Func<Task> update, Func<Task> delete, Button? extra = null)
- {
- var layout = new HorizontalStackLayout { Spacing = 8 };
- layout.Children.Add(CreateActionButton("Добавить", "#1D4ED8", add));
- layout.Children.Add(CreateActionButton("Сохранить", "#0F766E", update));
- layout.Children.Add(CreateActionButton("Удалить", "#B42318", delete));
- if (extra is not null)
- {
- layout.Children.Add(extra);
- }
- return layout;
- }
- private Button CreateActionButton(string text, string color, Func<Task> action)
- {
- var button = new Button
- {
- Text = text,
- BackgroundColor = Color.FromArgb(color),
- TextColor = Colors.White,
- CornerRadius = 8
- };
- button.Clicked += async (_, _) =>
- {
- if (!CanEdit)
- {
- await DisplayAlertAsync("Доступ запрещен", "Менеджер может только читать данные.", "OK");
- return;
- }
- await RunSafelyAsync(action);
- };
- return button;
- }
- private static bool ValidateRequired(params Entry[] entries)
- {
- foreach (var entry in entries)
- {
- if (string.IsNullOrWhiteSpace(entry.Text))
- {
- return false;
- }
- }
- return true;
- }
- private static void ClearEntries(params Entry[] entries)
- {
- foreach (var entry in entries)
- {
- entry.Text = string.Empty;
- }
- }
- private async Task RunSafelyAsync(Func<Task> action)
- {
- try
- {
- await action();
- }
- catch (Exception ex)
- {
- await DisplayAlertAsync("Ошибка", ex.Message, "OK");
- }
- }
- }
|