private async void InitModelTree(EkCarTypeEnum?carType, string modelId)
        {
            Assure.CheckFlowState(carType != null || modelId != null, $"Either {nameof(carType)} or {nameof(modelId)} should not be null.");

            // free UI thread
            await ThreadHelper.RunInBackgroundThreadAsync(() =>
            {
                // build model tree
                var carModelTree = EkSettingsHelper.GetCarModelTree();
                if (carModelTree == null ||
                    carModelTree.Length == 0)
                {
                    return(Task.CompletedTask);
                }

                foreach (var ekCarGroup in carModelTree)
                {
                    var groupCategory            = new Category(ekCarGroup.CarType);
                    _allGroups[groupCategory.Id] = groupCategory;

                    foreach (var manufacturer in ekCarGroup.Manufacturers)
                    {
                        var manufacturerCategory = new Category(ekCarGroup.CarType, manufacturer)
                        {
                            ParentCategoryId = groupCategory.Id,
                        };
                        _allManufacturers[manufacturerCategory.Id] = manufacturerCategory;

                        foreach (var carModel in manufacturer.CarModels)
                        {
                            var modelCategory = new Category(carModel)
                            {
                                ParentCategoryId = manufacturerCategory.Id,
                            };
                            _allModels[modelCategory.Id] = modelCategory;
                        }
                    }
                }

                Category selectedCategory = null;

                if (modelId != null)
                {
                    selectedCategory = _allModels.GetValueOrDefault(modelId);
                }
                else if (carType != null)
                {
                    selectedCategory = _allGroups.GetValueOrDefault(carType.ToString());
                }

                if (selectedCategory == null)
                {
                    selectedCategory = _allGroups.Values.First();
                }

                SelectCategory(selectedCategory);

                return(Task.CompletedTask);
            });
        }
Exemple #2
0
        private UserControl GetErrorPageView(string errorMessage)
        {
            var errorPageView = _applicationViewProvider.GetErrorPageView(errorMessage);

            Assure.CheckFlowState(errorPageView != null, $"'{nameof(IKioskApplicationViewProvider)}.{nameof(IKioskApplicationViewProvider.GetErrorPageView)}' returned null.");
            return(errorPageView);
        }
Exemple #3
0
        private UserControl GetInitializationView(ComponentInitializationLog initializationLog)
        {
            var initizalitionView = _applicationViewProvider.GetInitializationView(initializationLog);

            Assure.CheckFlowState(initizalitionView != null, $"'{nameof(IKioskApplicationViewProvider)}.{nameof(IKioskApplicationViewProvider.GetInitializationView)}' returned null.");
            return(initizalitionView);
        }
Exemple #4
0
        public async Task ShowModalAsync(ModalArgs modalArgs)
        {
            Assure.ArgumentNotNull(modalArgs, nameof(modalArgs));
            CheckIfInitialized();

            try
            {
                await ThreadHelper.RunInUiThreadAsync(() =>
                {
                    var modalContext = new ModalContext();
                    var modalContent = modalArgs.ModalContentProvider(modalContext);
                    Assure.CheckFlowState(modalContent != null, $"'{nameof(ModalArgs)}.{nameof(ModalArgs.ModalContentProvider)}' has returned null.");

                    var modalContentContainer = _modalViewProvider.GetModalContentContainer(modalContent, () => modalContext.OnCloseModalRequest(), modalArgs.ModalTitle, modalArgs.CenterTitleHorizontally, modalArgs.ShowCancelButton);
                    Assure.CheckFlowState(modalContentContainer != null, $"'{nameof(IModalViewProvider)}.{nameof(IModalViewProvider.GetModalContentContainer)}' has returned null.");

                    _modalLayer.Children.Add(modalContentContainer);

                    modalContext.OnCloseModalRequest = () =>
                    {
                        _modalLayer.Children.Remove(modalContentContainer);
                        (modalContent as IDisposable)?.Dispose();
                    };
                    // check is closed on construction phase
                    if (modalContext.IsEarlyClosingRequested)
                    {
                        modalContext.OnCloseModalRequest();
                    }
                });
            }
            catch (Exception ex)
            {
                Log.Error(LogContextEnum.Application, $"'{nameof(ShowModalAsync)}' has failed.", ex);
            }
        }
Exemple #5
0
        private UserControl GetMainPageView()
        {
            var mainPageView = _applicationViewProvider.GetMainPageView();

            Assure.CheckFlowState(mainPageView != null, $"'{nameof(IKioskApplicationViewProvider)}.{nameof(IKioskApplicationViewProvider.GetMainPageView)}' returned null.");
            return(mainPageView);
        }
        public async Task WriteAsync(byte[] messageBytes, CancellationToken?externalCancellationToken)
        {
            EnsureOpened();

            Assure.ArgumentNotNull(messageBytes, nameof(messageBytes));
            Assure.CheckFlowState(messageBytes.Length > 0, $"Passed '{nameof(messageBytes)}' is empty.");

            await _deviceIoPort.WriteAsync(messageBytes, externalCancellationToken);
        }
Exemple #7
0
        private KioskApplicationViews GetApplicationViews()
        {
            var applicationViews = _applicationViewProvider.GetApplicationViews();

            Assure.CheckFlowState(applicationViews != null, $"'{nameof(IKioskApplicationViewProvider)}.{nameof(IKioskApplicationViewProvider.GetApplicationViews)}' returned null.");
            Assure.CheckFlowState(applicationViews.ApplicationView != null, $"'{nameof(KioskApplicationViews)}.{nameof(KioskApplicationViews.ApplicationView)}' is null.");
            Assure.CheckFlowState(applicationViews.ModalLayer != null, $"'{nameof(KioskApplicationViews)}.{nameof(KioskApplicationViews.ModalLayer)}' is null.");
            return(applicationViews);
        }
Exemple #8
0
        private void CheckIfInitialized()
        {
            // design-mode support
            if (DesignMode.DesignModeEnabled &&
                _kioskLanguages == null)
            {
                Initialize(new[] { "uk", "ru", "en" });
            }

            Assure.CheckFlowState(_kioskLanguages != null, $"'{nameof(LanguageManager)}' is not initialized. Run '{nameof(Initialize)}' first.");
        }
        /// <summary>
        /// Special method to register contract directly.
        /// Should be used only by KioskApplicationBase.
        /// </summary>
        internal void RegisterContractInternal <TComponentContract>(string componentRole, ComponentContractInfo componentContractInfo)
        {
            Assure.ArgumentNotNull(componentRole, nameof(componentRole));
            Assure.ArgumentNotNull(componentContractInfo, nameof(componentContractInfo));

            var contactType = typeof(TComponentContract);

            Assure.CheckFlowState(contactType.IsInterface, $"{contactType.FullName} is not interface.");

            _componentsByRole[componentRole] = componentContractInfo.Component;
            AddContractInfo(contactType, componentContractInfo);
        }
Exemple #10
0
        private async Task <SerialDevice> GetSerialDeviceAsync(string serialPortName)
        {
            Assure.CheckFlowState(!string.IsNullOrEmpty(serialPortName), $"Empty '{nameof(serialPortName)}'.");

            // ReSharper disable AssignNullToNotNullAttribute
            var aqsFilter = SerialDevice.GetDeviceSelector(serialPortName);
            // ReSharper restore AssignNullToNotNullAttribute
            var deviceInformation = (await DeviceInformation.FindAllAsync(aqsFilter)).FirstOrDefault();

            if (deviceInformation == null)
            {
                throw new DeviceIoPortInitializationException($"Serial device on '{serialPortName}' port was not found.");
            }

            var portOpenningTry = 0;

GetSerialDeviceTry:
            portOpenningTry++;

            var serialDevice = await SerialDevice.FromIdAsync(deviceInformation.Id);

            if (serialDevice != null)
            {
                return(serialDevice);
            }

            var deviceAccessStatus = DeviceAccessInformation.CreateFromId(deviceInformation.Id).CurrentStatus;

            switch (deviceAccessStatus)
            {
            case DeviceAccessStatus.DeniedByUser:
                throw new DeviceIoPortInitializationException($"Access to device on '{serialPortName}' port was blocked by the user.");

            case DeviceAccessStatus.DeniedBySystem:
                // This status is most likely caused by app permissions (did not declare the device in the app's package.appxmanifest)
                // This status does not cover the case where the device is already opened by another app.
                throw new DeviceIoPortInitializationException($"Access to device on '{serialPortName}' was blocked by the system.");

            default:
                // Sometimes serial port is not freed fast after previous Dispose. Retry.
                var message = $"Access to device on '{serialPortName}' was blocked with unknown error (try {portOpenningTry}). Possibly opened by another app.";
                if (portOpenningTry < MaxPortOpenningTries)
                {
                    Log.Error(LogContextEnum.Device, message);
                    await Task.Delay(PortOpenningTryDelay);

                    goto GetSerialDeviceTry;
                }
                throw new DeviceIoPortInitializationException(message);
            }
        }
Exemple #11
0
        // todo: request configuration periodically? (considering that kiosk will not be restarted long period of time)
        private async Task <(KioskConfiguration Configuration, bool IsLoadedFromCache)> GetKioskConfigurationAsync(ComponentOperationContext context)
        {
            var tryNumber = 0;

GetConfigurationTry:
            try
            {
                tryNumber++;

                var response = await ServerApiProxy.Current.GetKioskConfigurationAsync(new EmptyRequest());

                Assure.CheckFlowState(response.KioskConfiguration != null, $"Received '{nameof(KioskConfiguration)}' is null.");

                var kioskConfiguration = response.KioskConfiguration;

                // cache configuration for case of Internet absence
                await _persistentCacheManager.SaveAsync(kioskConfiguration, context);

                return(kioskConfiguration, false);
            }
            catch (Exception ex)
            {
                if (tryNumber == 1)
                {
                    context.Log.Error(LogContextEnum.Communication, $"Kiosk configuration request failed (try {tryNumber}).", ex);
                }

                if (tryNumber < GetInitialConfigurationMaxTries)
                {
                    await Task.Delay(GetInitialConfigurationNextTryDelay);

                    goto GetConfigurationTry;
                }

                // try to get cached configuration
                var cachedKioskConfiguration = await _persistentCacheManager.LoadAsync(context);

                if (cachedKioskConfiguration == null)
                {
                    throw;
                }

                context.Log.Warning(LogContextEnum.Component, "Kiosk configuration was loaded from cache.");
                return(cachedKioskConfiguration, true);
            }
        }
Exemple #12
0
        /// <summary>
        /// Not thread-safe.
        /// </summary>
        public void AddStatePropertyListener <TProperty>(Func <TProperty, Task> propertyChangeHandler, bool runHandlerWithCurrentValue = true)
        {
            Assure.ArgumentNotNull(propertyChangeHandler, nameof(propertyChangeHandler));
            // not thread safe since await-s are used below (thread safe behavior would make the implementation more complicated)
            Assure.CheckFlowState(_listenerKey == null, "Listener was already added.");

            var componentState     = ComponentManager.Current.GetContractState(this);
            var componentStateType = componentState.GetType();
            var propertyInfo       = componentStateType.GetProperty(PropertyName);

            if (propertyInfo == null ||
                !propertyInfo.CanRead ||
                propertyInfo.PropertyType != typeof(TProperty))
            {
                throw new ComponentConfigurationException($"'{componentStateType.FullName}' doesn't contain public readable property '{PropertyName}' of type '{typeof(TProperty).FullName}'.");
            }

            // TBD: probably it's faster to read the value via compiled expressions
            TProperty ValueReader() => (TProperty)propertyInfo.GetValue(componentState);

            async Task StateChangeHandler(string propertyName)
            {
                if (propertyName == PropertyName)
                {
                    try
                    {
                        var value = ValueReader();
                        await propertyChangeHandler(value);
                    }
                    catch (Exception ex)
                    {
                        Log.Error(LogContextEnum.Component, $"Property change listener of link '{this}' failed.", ex);
                    }
                }
            }

            _listenerKey = componentState.AddStateListener(StateChangeHandler);

            if (runHandlerWithCurrentValue)
            {
                ThreadHelper.RunInNewThreadAsync(() => StateChangeHandler(PropertyName));
            }
        }
        internal StatePersistenceManager(string stateRecordName, Func <TState, TState> statePostProcessor, string kioskAppDataFolderName)
        {
            Assure.ArgumentNotNull(stateRecordName, nameof(stateRecordName));
            Assure.ArgumentNotNull(statePostProcessor, nameof(statePostProcessor));
            Assure.ArgumentNotNull(kioskAppDataFolderName, nameof(kioskAppDataFolderName));

            var recordNameBuilder = new StringBuilder(stateRecordName);

            foreach (var prohibitedRecordNameCharacter in ProhibitedRecordNameCharacters)
            {
                recordNameBuilder.Replace(prohibitedRecordNameCharacter, "");
            }

            _stateRecordName = recordNameBuilder.ToString();
            Assure.CheckFlowState(_stateRecordName.Length > 0, $"{nameof(stateRecordName)} '{stateRecordName}' is empty or consists only of prohibited symbols.");

            _statePostProcessor     = statePostProcessor;
            _kioskAppDataFolderName = kioskAppDataFolderName;
        }
        public async Task <TMessage[]> GetNextFromQueueAsync <TMessage>(
            string queueName,
            int messageCount,
            CancellationToken cancellationToken)
            where TMessage : class, new()
        {
            Assure.ArgumentNotNull(queueName, nameof(queueName));
            Assure.CheckFlowState(messageCount > 0 && messageCount <= 32, $"{nameof(messageCount)} should belong to interval (0..32].");

            var queueClient   = CreateQueueClient();
            var queue         = queueClient.GetQueueReference(queueName);
            var queueMessages = await queue.GetMessagesAsync(
                messageCount,
                null,
                null,
                null,
                cancellationToken);

            var messageList = new List <TMessage>();

            foreach (var queueMessage in queueMessages)
            {
                await queue.DeleteMessageAsync(
                    queueMessage.Id,
                    queueMessage.PopReceipt,
                    null,
                    null,
                    cancellationToken);

                try
                {
                    var message = JsonConvert.DeserializeObject <TMessage>(queueMessage.AsString);
                    messageList.Add(message);
                }
                catch (Exception ex)
                {
                    _logger.LogError(LoggingEvents.NotificationError, ex, $"Bad format of queue message '{queueMessage.Id}'.");
                }
            }

            return(messageList.ToArray());
        }
        private Task ShowInactivityConfirmationModal()
        {
            return(ModalManager.Current.ShowModalAsync(new ModalArgs(
                                                           "InactivityConfirmationModal_Question",
                                                           modalContext =>
            {
                lock (_inactivityProcessingLock)
                {
                    // check if tracking has been stopped in parallel
                    if (_inactivityBehavior == null)
                    {
                        throw new OperationCanceledException($"Inactivity modal has been interrupted by '{nameof(StopTracking)}'.");
                    }

                    _currentInactivityModalModel = new InactivityConfirmationModalModel(modalContext, _inactivityBehavior.ModalDurationSecs, OnConfirmationModalCountdownRunOut);
                    var modal = _inactivityViewProvider.GetInactivityConfirmationModalWithStartedCountdown(_currentInactivityModalModel);
                    Assure.CheckFlowState(modal != null, $"'{nameof(IInactivityViewProvider)}.{nameof(IInactivityViewProvider.GetInactivityConfirmationModalWithStartedCountdown)}' has returned null.");
                    return modal;
                }
            },
                                                           centerTitleHorizontally: true,
                                                           showCancelButton: false)));
        }
        private static string ReplaceSeparatorsWithSpaceAndSurroundWithSpace(string text)
        {
            Assure.CheckFlowState(!string.IsNullOrEmpty(text), $"{nameof(text)} is empty.");

            var resultBuilder = new StringBuilder(" ");

            // ReSharper disable PossibleNullReferenceException
            foreach (var textSymbol in text)
            // ReSharper restore PossibleNullReferenceException
            {
                if (char.IsLetterOrDigit(textSymbol))
                {
                    resultBuilder.Append(textSymbol);
                }
                else
                {
                    resultBuilder.Append(" ");
                }
            }

            resultBuilder.Append(" ");

            return(resultBuilder.ToString());
        }
Exemple #17
0
        private ComponentBase CreateComponentInstance(ComponentConfiguration componentConfiguration)
        {
            try
            {
                Assure.ArgumentNotNull(componentConfiguration, nameof(componentConfiguration));
                Assure.ArgumentNotNull(componentConfiguration.ComponentName, nameof(componentConfiguration.ComponentName));
                Assure.ArgumentNotNull(componentConfiguration.ComponentRole, nameof(componentConfiguration.ComponentRole));
                Assure.CheckFlowState(_supportedComponentTypes != null, $"{nameof(ComponentManager)} is not initialized.");

                // ReSharper disable PossibleNullReferenceException
                var componentTypeNames = _supportedComponentTypes.Keys
                                         // ReSharper restore PossibleNullReferenceException
                                         .Where(x => x.EndsWith(componentConfiguration.ComponentName))
                                         .ToArray();
                if (componentTypeNames.Length > 1)
                {
                    throw new ComponentConfigurationException($"More than 1 app component type matches to component name '{componentConfiguration.ComponentName}': {string.Join(", ", componentTypeNames)}.");
                }

                if (componentTypeNames.Length == 0)
                {
                    throw new ComponentConfigurationException($"There is no app component type that matches to component name '{componentConfiguration.ComponentName}'.");
                }

                var    componentType = _supportedComponentTypes[componentTypeNames[0]];
                object componentInstance;
                try
                {
                    componentInstance = Activator.CreateInstance(componentType);
                }
                catch (Exception ex)
                {
                    throw new ComponentConfigurationException($"Instantiation of '{componentType.FullName}' failed with '{ex.Message}'.");
                }

                if (!(componentInstance is ComponentBase typedComponentInstance))
                {
                    throw new ComponentConfigurationException($"Component type '{componentType.FullName}' doesn't inherit {nameof(ComponentBase)}.");
                }

                var contractStateType = typeof(ComponentState);
                // get all properties including private and explicit interface implementations
                // it's done on component level since it's much simpler than to check an hierarchy of contact interfaces
                // TBD: move all checks to contract registration - check entire hierarchy of contact interfaces
                var componentProperties = componentType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
                foreach (var componentProperty in componentProperties)
                {
                    var isOperationOrState = false;
                    // check if operation property
                    if (componentProperty.PropertyType.IsConstructedGenericType &&
                        componentProperty.PropertyType.GetGenericTypeDefinition() == typeof(ComponentOperation <,>))
                    {
                        isOperationOrState = true;
                        var operationValue = componentProperty.GetValue(typedComponentInstance);
                        if (operationValue == null)
                        {
                            throw new ComponentConfigurationException($"Component operation '{componentType.FullName}'.{componentProperty.Name} is null after instantiation.");
                        }
                    }

                    // check if state property
                    if (contractStateType.IsAssignableFrom(componentProperty.PropertyType))
                    {
                        isOperationOrState = true;
                        var contractStateValue = componentProperty.GetValue(typedComponentInstance);
                        if (contractStateValue == null)
                        {
                            throw new ComponentConfigurationException($"Component contract state '{componentType.FullName}'.{componentProperty.Name} is null after instantiation.");
                        }

                        var statePropertyName = componentProperty.Name;
                        if (statePropertyName != ContractStatePropertyName
                            // for explicit contract implementations
                            && !statePropertyName.EndsWith("." + ContractStatePropertyName))
                        {
                            throw new ComponentConfigurationException($"Component contract state '{componentType.FullName}'.{componentProperty.Name} is not named '{ContractStatePropertyName}' (required by convention).");
                        }
                    }

                    if (isOperationOrState)
                    {
                        if (componentProperty.CanWrite)
                        {
                            throw new ComponentConfigurationException($"Component operation/state '{componentType.FullName}'.{componentProperty.Name} must be readonly.");
                        }
                    }
                }

                typedComponentInstance.ComponentRole = componentConfiguration.ComponentRole;
                typedComponentInstance.ComponentName = componentConfiguration.ComponentName;
                return(typedComponentInstance);
            }
            catch (Exception ex)
            {
                Log.Error(LogContextEnum.Configuration, $"Component '{componentConfiguration?.ComponentRole} ({componentConfiguration?.ComponentName})' instantiation failed.", ex);
                return(null);
            }
        }
Exemple #18
0
        protected override async Task <ComponentInitializeResponse> InitializeAsync(ComponentInitializeRequest request, ComponentOperationContext context)
        {
            State.KioskAppVersion = VersionHelper.AppVersionString;

            // app configuration
            var _appConfiguration = await AppDataStorage.Current.LoadRecordAsync <KioskAppConfiguration>(
                KioskFolderNames.AppData_Configuration,
                KioskFileNames.KioskAppConfigurationWithoutExtension,
                true,
                CancellationToken.None);

            Assure.CheckFlowState(_appConfiguration.ServerUri != null, $"'{nameof(KioskFileNames.KioskAppConfigurationWithoutExtension)}.{nameof(KioskAppConfiguration.ServerUri)}' is null.");

            State.ServerUri = _appConfiguration.ServerUri;

            // serial key
            string serialKey;

            try
            {
                var kioskPublicFolder = await StorageHelper.GetKioskRootFolderAsync();

                var storageFile = await kioskPublicFolder.GetFileAsync(KioskFileNames.Key);

                serialKey = await FileIO.ReadTextAsync(storageFile, UnicodeEncoding.Utf8);
            }
            catch (FileNotFoundException)
            {
                Status.SetSelfStatus(ComponentStatusCodeEnum.Error, $"'{KioskFileNames.Key}' was not found.");
                return(ComponentInitializeResponse.GetError());
            }

            // init server API proxy
            ServerApiProxy.Current.Initialize(State.ServerUri, serialKey);

            // get kiosk configuration
            var loadedConfiguration = await GetKioskConfigurationAsync(context);

            var kioskConfiguration = loadedConfiguration.Configuration;

            Assure.CheckFlowState(kioskConfiguration != null, "Loaded kiosk configuration is null.");

            // state properties
            State.KioskConfiguration = kioskConfiguration;
            // ReSharper disable PossibleNullReferenceException
            State.KioskId = kioskConfiguration.KioskId;
            // ReSharper restore PossibleNullReferenceException
            State.SupportPhone = kioskConfiguration.SupportPhone;
            State.KioskAddress = kioskConfiguration.KioskAddress;

            // init languages
            LanguageManager.Current.Initialize(kioskConfiguration.LanguageCodes);

            if (loadedConfiguration.IsLoadedFromCache)
            {
                Status.SetSelfStatus(ComponentStatusCodeEnum.Warning, "Loaded from cache.");
            }
            else
            {
                Status.SetSelfStatus(ComponentStatusCodeEnum.Ok, null);
            }

            return(ComponentInitializeResponse.GetSuccess());
        }
Exemple #19
0
        private async Task StartKioskApplicationAsync()
        {
            try
            {
                // block updates during initialization
                await KioskAppNotReadyForUpdateSign.SetAsync();

                State.ApplicationState = KioskApplicationStateEnum.Initializing;

                _applicationViewProvider = GetApplicationViewProvider();
                Assure.CheckFlowState(_applicationViewProvider != null, $"'{nameof(GetApplicationViewProvider)}' returned null.");

                // set initialization view
                SetWindowView(GetInitializationView(ComponentManager.Current.InitializationLog));

#if !DEBUG
                await Task.Delay(ApplicationInitializationDelay);
#endif

                // register itself as component
                ComponentManager.Current.RegisterContractInternal <IKioskApplicationContract>(
                    "KioskApplication",
                    new ComponentContractInfo(this, Status, State));

                // register supported components
                var supportedComponentTypes = new List <Type>()
                {
                    // default components
                    typeof(KioskAppSettings),
                    typeof(ServerSyncService),
                };
                var supportedAppComponentTypes = GetSupportedAppComponents();
                if (supportedAppComponentTypes != null)
                {
                    supportedComponentTypes.AddRange(supportedAppComponentTypes);
                }

                ComponentManager.Current.Initialize(supportedComponentTypes);

                // init app settings component
                await ComponentManager.Current.RegisterAndInitializeAsync(
                    new ComponentConfiguration()
                {
                    ComponentRole = CoreComponentRoles.KioskAppSettings,
                    ComponentName = nameof(KioskAppSettings),
                    Settings      = null,
                });

                var kioskAppSettingsComponent = ComponentManager.Current.GetComponent <IKioskAppSettingsContract>(CoreComponentRoles.KioskAppSettings);
                if (!kioskAppSettingsComponent.Status.IsOperational())
                {
                    throw new KioskAppInitializationException($"{kioskAppSettingsComponent.FullName}: {kioskAppSettingsComponent.Status.Message}");
                }

                // init core components
                await ComponentManager.Current.RegisterAndInitializeAsync(
                    new ComponentConfiguration()
                {
                    ComponentRole = CoreComponentRoles.ServerSyncService,
                    ComponentName = nameof(ServerSyncService),
                    Settings      = null,
                });

                // register app specific components
                await ComponentManager.Current.RegisterAndInitializeAsync(kioskAppSettingsComponent.State.KioskConfiguration.AppComponents);

                // component initialization is completed - prepare and run app UI
                // application view
                var applicationViews = GetApplicationViews();
                SetWindowView(applicationViews.ApplicationView);

                // initialize common UI managers
                ModalManager.Current.Initialize(applicationViews.ModalLayer, GetModalViewProvider());

                // initialize inactivity behavior
                InactivityManager.Current.Initialize(applicationViews.ApplicationView, GetInactivityViewProvider());

                await GotoMainPageAsync();

                await OnLaunchedAsync();
            }
            catch (Exception ex)
            {
                Log.Error(LogContextEnum.Application, "Initialization.", ex);

                // allow updates if initialization fails
                await KioskAppNotReadyForUpdateSign.UnsetAsync();

                State.ApplicationState = KioskApplicationStateEnum.Error;

                // todo: doesn't show ex.Message (should be shown in admin/service panel - KioskOperability 'Operability' component)
                SetWindowView(GetErrorPageView(ex.Message));
            }
        }
 private void CheckIfInitialized()
 {
     Assure.CheckFlowState(_inactivityViewProvider != null, $"'{nameof(InactivityManager)}' is not initialized. Run '{nameof(Initialize)}' first.");
 }