diff --git a/TransactionProcessor.Mobile.BusinessLogic.Tests/DatabaseTests/DatabaseContextTests.cs b/TransactionProcessor.Mobile.BusinessLogic.Tests/DatabaseTests/DatabaseContextTests.cs new file mode 100644 index 000000000..ff3d2cf45 --- /dev/null +++ b/TransactionProcessor.Mobile.BusinessLogic.Tests/DatabaseTests/DatabaseContextTests.cs @@ -0,0 +1,36 @@ +using TransactionProcessor.Mobile.BusinessLogic.Database; +using Shouldly; + +namespace TransactionProcessor.Mobile.BusinessLogic.Tests.DatabaseTests; + +public class DatabaseContextTests +{ + [Fact] + public async Task DatabaseContext_SaveApplicationOption_OptionCanBeReadBack() + { + Func logLevelFunc = () => LogLevel.Debug; + IDatabaseContext databaseContext = new DatabaseContext(":memory:", logLevelFunc); + + await databaseContext.InitialiseDatabase(); + await databaseContext.SaveApplicationOption("DarkThemeEnabled", "True"); + + String? optionValue = await databaseContext.GetApplicationOption("DarkThemeEnabled"); + + optionValue.ShouldBe("True"); + } + + [Fact] + public async Task DatabaseContext_SaveApplicationOption_ExistingValueIsUpdated() + { + Func logLevelFunc = () => LogLevel.Debug; + IDatabaseContext databaseContext = new DatabaseContext(":memory:", logLevelFunc); + + await databaseContext.InitialiseDatabase(); + await databaseContext.SaveApplicationOption("DarkThemeEnabled", "True"); + await databaseContext.SaveApplicationOption("DarkThemeEnabled", "False"); + + String? optionValue = await databaseContext.GetApplicationOption("DarkThemeEnabled"); + + optionValue.ShouldBe("False"); + } +} diff --git a/TransactionProcessor.Mobile.BusinessLogic.Tests/ViewModelTests/MyAccount/MyAccountPageViewModelTests.cs b/TransactionProcessor.Mobile.BusinessLogic.Tests/ViewModelTests/MyAccount/MyAccountPageViewModelTests.cs index 4f1f829be..705958529 100644 --- a/TransactionProcessor.Mobile.BusinessLogic.Tests/ViewModelTests/MyAccount/MyAccountPageViewModelTests.cs +++ b/TransactionProcessor.Mobile.BusinessLogic.Tests/ViewModelTests/MyAccount/MyAccountPageViewModelTests.cs @@ -25,6 +25,7 @@ public class MyAccountPageViewModelTests private readonly Mock DialogService; private readonly Mock Mediator; + private readonly Mock ApplicationThemeService; private readonly MyAccountPageViewModel ViewModel; @@ -37,24 +38,35 @@ public MyAccountPageViewModelTests() { this.DialogService = new Mock(); this.DeviceService = new Mock(); this.Mediator = new Mock(); + this.ApplicationThemeService = new Mock(); this.ViewModel = new MyAccountPageViewModel(this.NavigationService.Object, this.ApplicationCache.Object, - this.DialogService.Object, this.DeviceService.Object, - this.Mediator.Object, - this.NavigationParameterService.Object); + this.DialogService.Object, this.DeviceService.Object, + this.ApplicationThemeService.Object, + this.Mediator.Object, + this.NavigationParameterService.Object); } [Fact] public async Task MyAccountPageViewModel_Initialise_IsInitialised() { - + this.ApplicationThemeService.Setup(s => s.GetDarkThemeEnabled()).ReturnsAsync(true); this.Mediator.Setup(m => m.Send(It.IsAny(), It.IsAny())).ReturnsAsync(Result.Success( TestData.MerchantDetailsModel)); await this.ViewModel.Initialise(CancellationToken.None); this.ViewModel.MerchantName.ShouldBe(TestData.MerchantDetailsModel.MerchantName); this.ViewModel.LastLogin.ShouldBe(DateTime.Now, TimeSpan.FromSeconds(30)); + this.ViewModel.IsDarkThemeEnabled.ShouldBeTrue(); this.ApplicationCache.Verify(a => a.SetMerchantDetails(It.IsAny(), It.IsAny()), Times.Once); } + [Fact] + public async Task MyAccountPageViewModel_SetDarkTheme_ThemeStoredAndPropertyUpdated() { + await this.ViewModel.SetDarkTheme(true); + + this.ViewModel.IsDarkThemeEnabled.ShouldBeTrue(); + this.ApplicationThemeService.Verify(s => s.SetDarkTheme(true), Times.Once); + } + [Fact] public void MyAccountPageViewModel_OptionSelectedCommand_AccountInfo_Execute_IsExecuted() { this.ViewModel.OptionSelectedCommand.Execute(this.CreateItemSelected(MyAccountPageViewModel.AccountOptions.AccountInfo)); @@ -117,4 +129,4 @@ private ItemSelected CreateItemSelected(MyAccountPageViewModel.Acc } #endregion -} \ No newline at end of file +} diff --git a/TransactionProcessor.Mobile.BusinessLogic.Tests/ViewModelTests/Reports/ReportsPageViewModelTests.cs b/TransactionProcessor.Mobile.BusinessLogic.Tests/ViewModelTests/Reports/ReportsPageViewModelTests.cs index d6f8a5907..5cedf829d 100644 --- a/TransactionProcessor.Mobile.BusinessLogic.Tests/ViewModelTests/Reports/ReportsPageViewModelTests.cs +++ b/TransactionProcessor.Mobile.BusinessLogic.Tests/ViewModelTests/Reports/ReportsPageViewModelTests.cs @@ -89,7 +89,6 @@ public class ReportsSalesAnalysisPageViewModelTests{ private readonly Mock ApplicationCache; private readonly Mock DialogService; private readonly Mock DeviceService; - private readonly Mock Mediator; public ReportsSalesAnalysisPageViewModelTests(){ this.NavigationService = new Mock(); @@ -97,13 +96,11 @@ public ReportsSalesAnalysisPageViewModelTests(){ this.ApplicationCache = new Mock(); this.DialogService = new Mock(); this.DeviceService = new Mock(); - this.Mediator = new Mock(); this.ViewModel = new ReportsSalesAnalysisPageViewModel(this.NavigationService.Object, this.ApplicationCache.Object, this.DialogService.Object, this.DeviceService.Object, - this.Mediator.Object, this.NavigationParameterService.Object); } @@ -124,6 +121,15 @@ public async Task ReportsSalesAnalysisPageViewModel_ComparisonDatePickerSelected this.ViewModel.SalesAnalysisList.Count.ShouldBe(2); } + [Fact] + public void ReportsSalesAnalysisPageViewModel_ComparisonDatePickerSelectedIndexChangedCommand_WithoutSelectedItem_ReturnsEmptyList() + { + this.ViewModel.ComparisonDatePickerSelectedIndexChangedCommand.Execute(null); + + this.ViewModel.SalesAnalysisList.ShouldNotBeNull(); + this.ViewModel.SalesAnalysisList.ShouldBeEmpty(); + } + [Fact] public async Task ReportsSalesAnalysisPageViewModel_BackButtonCommand_HomePageIsShown() { @@ -141,7 +147,6 @@ public class ReportsBalanceAnalysisPageViewModelTests private Mock ApplicationCache; private Mock DialogService; private readonly Mock DeviceService; - private Mock Mediator; public ReportsBalanceAnalysisPageViewModelTests() { @@ -150,13 +155,11 @@ public ReportsBalanceAnalysisPageViewModelTests() this.ApplicationCache = new Mock(); this.DialogService = new Mock(); this.DeviceService = new Mock(); - this.Mediator = new Mock(); this.ViewModel = new ReportsBalanceAnalysisPageViewModel(this.NavigationService.Object, this.ApplicationCache.Object, this.DialogService.Object, this.DeviceService.Object, - this.Mediator.Object, this.NavigationParameterService.Object); } diff --git a/TransactionProcessor.Mobile.BusinessLogic/Database/ApplicationOption.cs b/TransactionProcessor.Mobile.BusinessLogic/Database/ApplicationOption.cs new file mode 100644 index 000000000..ea6bdc013 --- /dev/null +++ b/TransactionProcessor.Mobile.BusinessLogic/Database/ApplicationOption.cs @@ -0,0 +1,14 @@ +using System.Diagnostics.CodeAnalysis; +using SQLite; + +namespace TransactionProcessor.Mobile.BusinessLogic.Database +{ + [ExcludeFromCodeCoverage] + public class ApplicationOption + { + [PrimaryKey] + public String OptionName { get; set; } = String.Empty; + + public String OptionValue { get; set; } = String.Empty; + } +} diff --git a/TransactionProcessor.Mobile.BusinessLogic/Database/DatabaseContext.cs b/TransactionProcessor.Mobile.BusinessLogic/Database/DatabaseContext.cs index 8018d16d0..f656faaf1 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/Database/DatabaseContext.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/Database/DatabaseContext.cs @@ -38,6 +38,12 @@ public async Task CreateTransaction(TransactionRecord transactionRecord) return SQLite3.LastInsertRowid(this.Connection.Handle); } + public Task GetApplicationOption(String optionName) { + ApplicationOption option = this.Connection.Find(optionName); + + return Task.FromResult(option?.OptionValue); + } + public async Task> GetLogMessages(Int32 batchSize, Boolean isTrainingMode) { if (this.Connection == null) return new List(); @@ -55,6 +61,7 @@ public async Task> GetTransactions(Boolean isTrainingMod } public async Task InitialiseDatabase() { + this.Connection.CreateTable(); this.Connection.CreateTable(); this.Connection.CreateTable(); } @@ -83,10 +90,20 @@ public async Task RemoveUploadedMessages(List logMessagesToRemove) { } } + public Task SaveApplicationOption(String optionName, + String optionValue) { + this.Connection.InsertOrReplace(new ApplicationOption { + OptionName = optionName, + OptionValue = optionValue + }); + + return Task.CompletedTask; + } + public async Task UpdateTransaction(TransactionRecord transactionRecord) { this.Connection.Update(transactionRecord); } #endregion } -} \ No newline at end of file +} diff --git a/TransactionProcessor.Mobile.BusinessLogic/Database/IDatabaseContext.cs b/TransactionProcessor.Mobile.BusinessLogic/Database/IDatabaseContext.cs index 02590fbc7..9a432fb3c 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/Database/IDatabaseContext.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/Database/IDatabaseContext.cs @@ -4,6 +4,10 @@ public interface IDatabaseContext { Task InitialiseDatabase(); + Task GetApplicationOption(String optionName); + + Task SaveApplicationOption(String optionName, String optionValue); + Task CreateTransaction(TransactionRecord transactionRecord); Task UpdateTransaction(TransactionRecord transactionRecord); diff --git a/TransactionProcessor.Mobile.BusinessLogic/UIServices/IApplicationThemeService.cs b/TransactionProcessor.Mobile.BusinessLogic/UIServices/IApplicationThemeService.cs new file mode 100644 index 000000000..588c83591 --- /dev/null +++ b/TransactionProcessor.Mobile.BusinessLogic/UIServices/IApplicationThemeService.cs @@ -0,0 +1,10 @@ +namespace TransactionProcessor.Mobile.BusinessLogic.UIServices; + +public interface IApplicationThemeService +{ + Task ApplyConfiguredTheme(); + + Task GetDarkThemeEnabled(); + + Task SetDarkTheme(Boolean isEnabled); +} diff --git a/TransactionProcessor.Mobile.BusinessLogic/ViewModels/MyAccount/MyAccountPageViewModel.cs b/TransactionProcessor.Mobile.BusinessLogic/ViewModels/MyAccount/MyAccountPageViewModel.cs index 65128398a..cf5a1d405 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/ViewModels/MyAccount/MyAccountPageViewModel.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/ViewModels/MyAccount/MyAccountPageViewModel.cs @@ -21,8 +21,10 @@ public partial class MyAccountPageViewModel : ExtendedBaseViewModel private DateTime lastLogin; private readonly IMediator Mediator; + private readonly IApplicationThemeService ApplicationThemeService; private String merchantName; + private Boolean isDarkThemeEnabled; #endregion @@ -32,8 +34,10 @@ public MyAccountPageViewModel(INavigationService navigationService, IApplicationCache applicationCache, IDialogService dialogService, IDeviceService deviceService, + IApplicationThemeService applicationThemeService, IMediator mediator, INavigationParameterService navigationParameterService) : base(applicationCache, dialogService, navigationService, deviceService,navigationParameterService) { + this.ApplicationThemeService = applicationThemeService; this.Mediator = mediator; this.Title = "My Account"; } @@ -47,6 +51,11 @@ public DateTime LastLogin { set => this.SetProperty(ref this.lastLogin, value); } + public Boolean IsDarkThemeEnabled { + get => this.isDarkThemeEnabled; + set => this.SetProperty(ref this.isDarkThemeEnabled, value); + } + public String MerchantName { get => this.merchantName; set => this.SetProperty(ref this.merchantName, value); @@ -93,6 +102,13 @@ public async Task Initialise(CancellationToken cancellationToken) { this.ApplicationCache.SetMerchantDetails(merchantDetailsResult.Data, cacheEntryOptions); this.LastLogin = DateTime.Now; // TODO: might cache this in the application + this.IsDarkThemeEnabled = await this.ApplicationThemeService.GetDarkThemeEnabled(); + } + + public async Task SetDarkTheme(Boolean isEnabled) { + this.IsDarkThemeEnabled = isEnabled; + + await this.ApplicationThemeService.SetDarkTheme(isEnabled); } private async Task LogoutCommandExecute() { @@ -136,4 +152,4 @@ public enum AccountOptions #endregion } -} \ No newline at end of file +} diff --git a/TransactionProcessor.Mobile.BusinessLogic/ViewModels/Reports/ReportsSalesAnalysisPageViewModel.cs b/TransactionProcessor.Mobile.BusinessLogic/ViewModels/Reports/ReportsSalesAnalysisPageViewModel.cs index 8997a1fcb..b08b9a8d4 100644 --- a/TransactionProcessor.Mobile.BusinessLogic/ViewModels/Reports/ReportsSalesAnalysisPageViewModel.cs +++ b/TransactionProcessor.Mobile.BusinessLogic/ViewModels/Reports/ReportsSalesAnalysisPageViewModel.cs @@ -4,7 +4,6 @@ using LiveChartsCore.Kernel.Sketches; using LiveChartsCore.Measure; using LiveChartsCore.SkiaSharpView; -using MediatR; using System.Diagnostics.CodeAnalysis; using TransactionProcessor.Mobile.BusinessLogic.Common; using TransactionProcessor.Mobile.BusinessLogic.Services; @@ -14,15 +13,12 @@ namespace TransactionProcessor.Mobile.BusinessLogic.ViewModels.Reports; public partial class ReportsSalesAnalysisPageViewModel : ExtendedBaseViewModel { - - private readonly IMediator Mediator; public ReportsSalesAnalysisPageViewModel(INavigationService navigationService, IApplicationCache applicationCache, IDialogService dialogService, IDeviceService deviceService, - IMediator mediator, INavigationParameterService navigationParameterService) : base(applicationCache, dialogService, navigationService, deviceService, navigationParameterService) + INavigationParameterService navigationParameterService) : base(applicationCache, dialogService, navigationService, deviceService, navigationParameterService) { - this.Mediator = mediator; this.Title = "Sales Analysis"; } @@ -34,6 +30,12 @@ private async Task ComparisonDatePickerSelectedIndexChanged() private async Task GetApiData() { + if (this.SelectedItem is null) + { + this.SalesAnalysisList = new List(); + return; + } + // TODO: Initial api call to get data would be done here List salesAnalysisList = new List(); salesAnalysisList.Add(new SalesAnalysis("100.00 KES", "90.00 KES", "10%", "Sales Value", "Today's Sales", this.SelectedItem.DisplayText, "Variance:", "salesvalue.png")); @@ -84,21 +86,25 @@ public record ComparisonDate(DateTime DateTime, String DisplayText); [ExcludeFromCodeCoverage] public record SalesAnalysis(String TodaysValue, String ComparisonValue, String VarianceValue, String MainTitle, String TodaysTitle, String ComparisonTitle, String VarianceTitle, String Icon); -public class ReportsBalanceAnalysisPageViewModel : ExtendedBaseViewModel{ - private readonly IMediator Mediator; +public class ReportsBalanceAnalysisPageViewModel : ExtendedBaseViewModel +{ + private TooltipPosition tooltipPosition; + private List yAxes; + private List xAxes; + private ISeries[] series; + private TooltipFindingStrategy tooltipFindingStrategy; public ReportsBalanceAnalysisPageViewModel(INavigationService navigationService, IApplicationCache applicationCache, IDialogService dialogService, IDeviceService deviceService, - IMediator mediator, - INavigationParameterService navigationParameterService) : base(applicationCache, dialogService, navigationService, deviceService, navigationParameterService, Orientation.Landscape) + INavigationParameterService navigationParameterService) : base(applicationCache, dialogService, navigationService, deviceService, navigationParameterService) { - this.Mediator = mediator; this.Title = "Balance Analysis"; } - public async Task Initialise(CancellationToken cancellationToken){ + public override async Task Initialise(CancellationToken cancellationToken) + { await base.Initialise(cancellationToken); DateTimeAxis axis1 = new DateTimeAxis(TimeSpan.FromDays(1), (d) => d.ToString("dd/MM/yyyy")); @@ -134,15 +140,35 @@ public async Task Initialise(CancellationToken cancellationToken){ }; } - public TooltipPosition TooltipPosition{ get; set; } + public TooltipPosition TooltipPosition + { + get => this.tooltipPosition; + set => this.SetProperty(ref this.tooltipPosition, value); + } - public List YAxes{ get; set; } + public List YAxes + { + get => this.yAxes; + set => this.SetProperty(ref this.yAxes, value); + } - public List XAxes{ get; set; } + public List XAxes + { + get => this.xAxes; + set => this.SetProperty(ref this.xAxes, value); + } - public ISeries[] Series { get; set; } + public ISeries[] Series + { + get => this.series; + set => this.SetProperty(ref this.series, value); + } - public TooltipFindingStrategy TooltipFindingStrategy { get; set; } + public TooltipFindingStrategy TooltipFindingStrategy + { + get => this.tooltipFindingStrategy; + set => this.SetProperty(ref this.tooltipFindingStrategy, value); + } -} \ No newline at end of file +} diff --git a/TransactionProcessor.Mobile.UITests/Common/DockerHelper.cs b/TransactionProcessor.Mobile.UITests/Common/DockerHelper.cs index bff23fd3e..5eeb324ea 100644 --- a/TransactionProcessor.Mobile.UITests/Common/DockerHelper.cs +++ b/TransactionProcessor.Mobile.UITests/Common/DockerHelper.cs @@ -124,8 +124,11 @@ public override async Task StartContainersForScenarioRun(String scenarioName, Do this.Trace(this.LocalIPAddress); await base.StartContainersForScenarioRun(scenarioName, dockerServices); - var c = await this.StartContainer2(this.SetupConfigHostContainer,this.TestNetworks, (DockerServices)512); - this.ConfigHostPort = c.GetMappedPublicPort(ConfigHostDockerPort); + + var c = this.Containers.SingleOrDefault(c => c.Item1 == DockerServices.ConfigurationHost); + + //var c = await this.StartContainer2(this.SetupConfigHostContainer,this.TestNetworks, DockerServices.ConfigurationHost); + this.ConfigHostPort = c.Item2.GetMappedPublicPort(ConfigHostDockerPort); // Setup the base address resolvers diff --git a/TransactionProcessor.Mobile.UITests/Common/GenericSteps.cs b/TransactionProcessor.Mobile.UITests/Common/GenericSteps.cs index bce0dce10..a2bc83eb8 100644 --- a/TransactionProcessor.Mobile.UITests/Common/GenericSteps.cs +++ b/TransactionProcessor.Mobile.UITests/Common/GenericSteps.cs @@ -36,7 +36,7 @@ public async Task StartSystem(){ DockerServices dockerServices = DockerServices.EventStore | DockerServices.MessagingService | DockerServices.SecurityService | DockerServices.TestHost | DockerServices.SqlServer | DockerServices.TransactionProcessor | - DockerServices.TransactionProcessorAcl | (DockerServices)512; + DockerServices.TransactionProcessorAcl | DockerServices.ConfigurationHost; //dockerServices = DockerServices.EventStore | DockerServices.SqlServer | (DockerServices)512; diff --git a/TransactionProcessor.Mobile.UITests/Features/EndToEndTests.feature b/TransactionProcessor.Mobile.UITests/Features/EndToEndTests.feature index 2924feab9..20f2fe07f 100644 --- a/TransactionProcessor.Mobile.UITests/Features/EndToEndTests.feature +++ b/TransactionProcessor.Mobile.UITests/Features/EndToEndTests.feature @@ -82,8 +82,8 @@ Background: | Test Estate 1 | PataPawa PrePay | PataPawa PrePay Contract | Pre Pay Bill Pay | Percentage | Merchant Commission | 0.50 | Given I create the following merchants - | MerchantName | AddressLine1 | AddressLine2 | AddressLine3 | AddressLine4 | Town | Region | Country | ContactName | EmailAddress | EstateName | - | Test Merchant 1 | test address line 1 | test address line 2 | test address line 3 | test address line 4 | TestTown | Test Region | United Kingdom | Test Contact 1 | testcontact1@merchant1.co.uk | Test Estate 1 | + | MerchantName | AddressLine1 | AddressLine2 | AddressLine3 | AddressLine4 | Town | Region | PostalCode | Country | ContactName | EmailAddress | EstateName | + | Test Merchant 1 | test address line 1 | test address line 2 | test address line 3 | test address line 4 | TestTown | Test Region | TE57 1NG | United Kingdom | Test Contact 1 | testcontact1@merchant1.co.uk | Test Estate 1 | Given I have assigned the following operator to the merchants | OperatorName | MerchantName | MerchantNumber | TerminalNumber | EstateName | diff --git a/TransactionProcessor.Mobile.UITests/Features/EndToEndTests.feature.cs b/TransactionProcessor.Mobile.UITests/Features/EndToEndTests.feature.cs index 5f7d2e2ad..f520849fd 100644 --- a/TransactionProcessor.Mobile.UITests/Features/EndToEndTests.feature.cs +++ b/TransactionProcessor.Mobile.UITests/Features/EndToEndTests.feature.cs @@ -404,6 +404,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "AddressLine4", "Town", "Region", + "PostalCode", "Country", "ContactName", "EmailAddress", @@ -416,6 +417,7 @@ await testRunner.GivenAsync("I have a token to access the estate management and "test address line 4", "TestTown", "Test Region", + "TE57 1NG", "United Kingdom", "Test Contact 1", "testcontact1@merchant1.co.uk", diff --git a/TransactionProcessor.Mobile.UITests/Pages/Extenstions.cs b/TransactionProcessor.Mobile.UITests/Pages/Extenstions.cs index 189db81df..7754fb0e8 100644 --- a/TransactionProcessor.Mobile.UITests/Pages/Extenstions.cs +++ b/TransactionProcessor.Mobile.UITests/Pages/Extenstions.cs @@ -1,4 +1,5 @@ -using OpenQA.Selenium; +using System.Diagnostics; +using OpenQA.Selenium; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Windows; using Shared.IntegrationTesting; @@ -10,6 +11,19 @@ namespace TransactionProcessor.Mobile.UITests.Pages; public static class Extenstions { + private static IWebElement? TryScrollIntoView(AppiumDriver driver, string selector, string automationId) + { + try + { + return driver.FindElement(MobileBy.AndroidUIAutomator(selector)); + } + catch (WebDriverException ex) + { + Debug.WriteLine($"Unable to scroll to element [{automationId}]: {ex.Message}"); + return null; + } + } + /* // TODO: Mac & Windows Extensions // TODO: May need a platform switch @@ -130,6 +144,22 @@ await Retry.For(async () => } } + if (element == null && platform == "android") + { + string fullResourceId = $"{androidPackage}:id/{automationId}"; + + element = TryScrollIntoView(driver, + $"new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().resourceId(\"{fullResourceId}\"))", + automationId); + + if (element == null) + { + element = TryScrollIntoView(driver, + $"new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().description(\"{automationId}\"))", + automationId); + } + } + element.ShouldNotBeNull($"element not found. used automationId [{automationId}]"); } catch (WebDriverException ex) @@ -205,4 +235,4 @@ public static async Task GetPageSource(this AppiumDriver driver) { return driver.PageSource; } -} \ No newline at end of file +} diff --git a/TransactionProcessor.Mobile.UITests/TransactionProcessor.Mobile.UITests.csproj b/TransactionProcessor.Mobile.UITests/TransactionProcessor.Mobile.UITests.csproj index 17cced275..d8940fac9 100644 --- a/TransactionProcessor.Mobile.UITests/TransactionProcessor.Mobile.UITests.csproj +++ b/TransactionProcessor.Mobile.UITests/TransactionProcessor.Mobile.UITests.csproj @@ -9,30 +9,30 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - - + + + + - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - + + + + + - + diff --git a/TransactionProcessor.Mobile/App.xaml b/TransactionProcessor.Mobile/App.xaml index 1ab5229bc..366a963a7 100644 --- a/TransactionProcessor.Mobile/App.xaml +++ b/TransactionProcessor.Mobile/App.xaml @@ -3,12 +3,13 @@ xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:TransactionProcessor.Mobile" x:Class="TransactionProcessor.Mobile.App"> - - - - - - - - - + + + + + + + + + + diff --git a/TransactionProcessor.Mobile/App.xaml.cs b/TransactionProcessor.Mobile/App.xaml.cs index 678605e49..318875cba 100644 --- a/TransactionProcessor.Mobile/App.xaml.cs +++ b/TransactionProcessor.Mobile/App.xaml.cs @@ -8,6 +8,8 @@ using TransactionProcessor.Mobile.Pages.Transactions.BillPayment; using TransactionProcessor.Mobile.Pages.Transactions.MobileTopup; using TransactionProcessor.Mobile.Pages.Transactions.Voucher; +using TransactionProcessor.Mobile.BusinessLogic.UIServices; +using Microsoft.Maui.ApplicationModel; #if ANDROID using AndroidX.Core.View; @@ -47,9 +49,10 @@ void ApplyAutomationIdMapping( } #endif - public App() + public App(IApplicationThemeService applicationThemeService) { InitializeComponent(); + MainThread.BeginInvokeOnMainThread(async () => await applicationThemeService.ApplyConfiguredTheme()); #if ANDROID ApplyAutomationIdMapping(ViewHandler.ViewMapper); @@ -209,4 +212,4 @@ public override void OnInitializeAccessibilityNodeInfo(Android.Views.View host, #endif -} \ No newline at end of file +} diff --git a/TransactionProcessor.Mobile/AppShell.xaml b/TransactionProcessor.Mobile/AppShell.xaml index d8fe7a2a9..30490d028 100644 --- a/TransactionProcessor.Mobile/AppShell.xaml +++ b/TransactionProcessor.Mobile/AppShell.xaml @@ -10,7 +10,11 @@ xmlns:reports="clr-namespace:TransactionProcessor.Mobile.Pages.Reports" xmlns:myAccount="clr-namespace:TransactionProcessor.Mobile.Pages.MyAccount" xmlns:support="clr-namespace:TransactionProcessor.Mobile.Pages.Support" - Title="TransactionProcessor.Mobile"> + Title="TransactionProcessor.Mobile" + Shell.TabBarBackgroundColor="{DynamicResource shellTabBarBackgroundColor}" + Shell.TabBarForegroundColor="{DynamicResource shellTabBarForegroundColor}" + Shell.TabBarTitleColor="{DynamicResource shellTabBarForegroundColor}" + Shell.TabBarUnselectedColor="{DynamicResource shellTabBarUnselectedColor}"> (); builder.Services.AddSingleton(); builder.Services.AddSingleton(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); return builder; } @@ -351,4 +352,4 @@ protected override IHostnameVerifier GetSSLHostnameVerifier(HttpsURLConnection c } } #endif -} \ No newline at end of file +} diff --git a/TransactionProcessor.Mobile/Pages/AppHome/HomePage.xaml b/TransactionProcessor.Mobile/Pages/AppHome/HomePage.xaml index d6fad0a57..443128f3e 100644 --- a/TransactionProcessor.Mobile/Pages/AppHome/HomePage.xaml +++ b/TransactionProcessor.Mobile/Pages/AppHome/HomePage.xaml @@ -51,7 +51,7 @@ - +