diff --git a/ServiceBusManager.UnitTests/ConnectViewModelTests.cs b/ServiceBusManager.UnitTests/ConnectViewModelTests.cs index 2bdfe80..4f5e02d 100644 --- a/ServiceBusManager.UnitTests/ConnectViewModelTests.cs +++ b/ServiceBusManager.UnitTests/ConnectViewModelTests.cs @@ -7,7 +7,7 @@ public async Task OnParameterSetTest() { //Arrange var connectionService = Substitute.For(); - var featureService = Substitute.For(); + var featureService = Substitute.For(); var logService = Substitute.For(); var viewModel = new ConnectViewModel(connectionService, featureService, logService); @@ -26,7 +26,7 @@ public async Task OnParameterSetTest_InvalidValue() { //Arrange var connectionService = Substitute.For(); - var featureService = Substitute.For(); + var featureService = Substitute.For(); var logService = Substitute.For(); var viewModel = new ConnectViewModel(connectionService, featureService, logService); @@ -51,7 +51,7 @@ public async Task OnAppearingTest() new Models.ConnectionInfo() })); - var featureService = Substitute.For(); + var featureService = Substitute.For(); var logService = Substitute.For(); var viewModel = new ConnectViewModel(connectionService, featureService, logService); @@ -71,7 +71,7 @@ public async Task OnAppearing_NoSavedConnectionsTest() var connectionService = Substitute.For(); connectionService.Get().Returns(Task.FromResult(new List())); - var featureService = Substitute.For(); + var featureService = Substitute.For(); var logService = Substitute.For(); var viewModel = new ConnectViewModel(connectionService, featureService, logService); @@ -91,7 +91,7 @@ public void OpenConnectionCommandTest() //Arrange var connectionService = Substitute.For(); - var featureService = Substitute.For(); + var featureService = Substitute.For(); var logService = Substitute.For(); TinyNavigation.Current = Substitute.For(); @@ -115,7 +115,7 @@ public void SaveAndConnectToNewCommandTest() //Arrange var connectionService = Substitute.For(); - var featureService = Substitute.For(); + var featureService = Substitute.For(); var logService = Substitute.For(); TinyNavigation.Current = Substitute.For(); @@ -144,7 +144,7 @@ public void ConnectToNewCommandTest() //Arrange var connectionService = Substitute.For(); - var featureService = Substitute.For(); + var featureService = Substitute.For(); var logService = Substitute.For(); TinyNavigation.Current = Substitute.For(); @@ -172,7 +172,7 @@ public void ValidateSaveTest() //Arrange var connectionService = Substitute.For(); - var featureService = Substitute.For(); + var featureService = Substitute.For(); var logService = Substitute.For(); var viewModel = new ConnectViewModel(connectionService, featureService, logService); @@ -193,7 +193,7 @@ public void ValidateConnectTest() //Arrange var connectionService = Substitute.For(); - var featureService = Substitute.For(); + var featureService = Substitute.For(); var logService = Substitute.For(); var viewModel = new ConnectViewModel(connectionService, featureService, logService); @@ -214,7 +214,7 @@ public async Task RemoveCommandTest() //Arrange var connectionService = Substitute.For(); - var featureService = Substitute.For(); + var featureService = Substitute.For(); var logService = Substitute.For(); diff --git a/ServiceBusManager/Constants.cs b/ServiceBusManager/Constants.cs index d00026a..a5b6c41 100644 --- a/ServiceBusManager/Constants.cs +++ b/ServiceBusManager/Constants.cs @@ -2,10 +2,7 @@ public static class Constants { - public static class Features - { - public const string Premium = nameof(Premium); - } + public const string Premium = nameof(Premium); public static class Products { diff --git a/ServiceBusManager/MauiProgram.cs b/ServiceBusManager/MauiProgram.cs index 1bc40ad..a27b2ce 100644 --- a/ServiceBusManager/MauiProgram.cs +++ b/ServiceBusManager/MauiProgram.cs @@ -58,7 +58,7 @@ public static MauiApp CreateMauiApp() private static void RegisterServices(this MauiAppBuilder builder) { builder.Services.AddSingleton(); - builder.Services.AddSingleton(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); diff --git a/ServiceBusManager/Platforms/MacCatalyst/AppDelegate.cs b/ServiceBusManager/Platforms/MacCatalyst/AppDelegate.cs index 4ad0cbd..7cc0bd6 100644 --- a/ServiceBusManager/Platforms/MacCatalyst/AppDelegate.cs +++ b/ServiceBusManager/Platforms/MacCatalyst/AppDelegate.cs @@ -1,4 +1,6 @@ -using BackgroundTasks; +using System.Threading.Tasks; +using AVFoundation; +using BackgroundTasks; using Foundation; using Microsoft.Maui.Controls.Compatibility.Platform.iOS; using ServiceBusManager.Platforms.MacCatalyst; @@ -10,33 +12,37 @@ namespace ServiceBusManager; [Register("AppDelegate")] public class AppDelegate : MauiUIApplicationDelegate { + private const string BgProcessingIdentifier = "se.hindrikes.azservicebus.fetch"; + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); public override bool FinishedLaunching(UIKit.UIApplication application, NSDictionary launchOptions) { base.FinishedLaunching(application, launchOptions); - + var service = Resolver.Resolve(); try { UNUserNotificationCenter.Current.Delegate = new UserNotificationCenterDelegate(); - // Check we're at least v10.14 - if (NSProcessInfo.ProcessInfo.IsOperatingSystemAtLeastVersion(new NSOperatingSystemVersion(10, 14, 0))) - { - // Request notification permissions from the user - UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert | - UNAuthorizationOptions.Badge | - UNAuthorizationOptions.Sound, (approved, err) => + // Request notification permissions from the user + UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert | + UNAuthorizationOptions.Badge | + UNAuthorizationOptions.Sound, async (approved, err) => + { + if (service != null) { - - }); - } - - CheckFeature(); + if (err != null) + { + await service!.LogException(new Exception(err.ToString())); + } + } + }); + + //CheckPremium(); } catch (Exception ex) { - var service = Resolver.Resolve(); + if (service != null) { @@ -44,54 +50,105 @@ public override bool FinishedLaunching(UIKit.UIApplication application, NSDictio } } + _ = Task.Run(async () => + { + var premiumService = Resolver.Resolve(); + + while (true) + { +#if DEBUG + await Task.Delay(10000); +#else + await Task.Delay(300000); +#endif + + if (premiumService!.HasPremium()) + { + await service!.LogEvent("StartingAsyncTask"); + + await CheckForDeadLetters(); + } + } + }); + return true; } - - private bool CheckFeature() + public override void DidEnterBackground(UIApplication application) { - var service = Resolver.Resolve(); + base.DidEnterBackground(application); - if (service == null) + var service = Resolver.Resolve(); + + if (service != null) { - throw new ArgumentNullException("Add IFeatureService to IoC"); + service.LogEvent(nameof(DidEnterBackground)); } + } + + private async static Task CheckForDeadLetters() + { + var log = Resolver.Resolve(); - if (service.HasFeature(Constants.Features.Premium)) + try { + var dateTime = DateTimeOffset.UtcNow; + + var service = Resolver.Resolve(); - BGTaskScheduler.Shared.Register("se.hindrikes.azservicebus.fetch", null, async (task) => + if (service == null) { - var log = Resolver.Resolve(); + return false; + } - if (log != null) - { - await log.LogEvent("BackgroundFetchStarting"); - } + var compareDate = Preferences.Get("LastDeadLetter", dateTime.DateTime); - var dateTime = DateTimeOffset.UtcNow; + var count = await service.CheckNewDeadLetters(new DateTimeOffset(compareDate)); - var service = Resolver.Resolve(); + Preferences.Set("LastDeadLetter", dateTime.DateTime); + if (count > 0) + { + SendNotification(count); + } - if (service == null) - { - task.SetTaskCompleted(false); - return; - } + return true; + } + catch (Exception ex) + { + if (log != null) + { + await log.LogException(ex); + } + } + + return false; + } + + private bool CheckPremium() + { + var service = Resolver.Resolve(); + + if (service == null) + { + throw new ArgumentNullException("Add IFeatureService to IoC"); + } - var compareDate = Preferences.Get("LastDeadLetter", dateTime.DateTime); + if (service.HasPremium()) + { - var count = await service.CheckNewDeadLetters(new DateTimeOffset(compareDate)); + var result = BGTaskScheduler.Shared.Register(BgProcessingIdentifier, null, async (task) => + { + var log = Resolver.Resolve(); - if (count > 0) + if (log != null) { - SendNotification(count); + await log.LogEvent("BackgroundFetchStarting"); } - Preferences.Set("LastDeadLetter", dateTime.DateTime); + var result = await CheckForDeadLetters(); - task.SetTaskCompleted(true); + task.SetTaskCompleted(result); if (log != null) { @@ -99,25 +156,24 @@ private bool CheckFeature() } - ScheduleAppRefresh(); + ScheduleBackgroundCheck(); }); - ScheduleAppRefresh(); + ScheduleBackgroundCheck(); return true; } else { - service.FeatureChanged += Service_FeatureChanged; + service.PremiumChanged += Service_FeatureChanged; } return false; } - - private void ScheduleAppRefresh() + //e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"se.hindrikes.azservicebus.fetch"] + private void ScheduleBackgroundCheck() { - var request = new BGProcessingTaskRequest("se.hindrikes.azservicebus.fetch"); - request.EarliestBeginDate = DateTime.Now.AddSeconds(30).ToNSDate(); + var request = new BGProcessingTaskRequest(BgProcessingIdentifier); request.RequiresNetworkConnectivity = true; request.RequiresExternalPower = false; @@ -133,28 +189,28 @@ private void ScheduleAppRefresh() if (log != null) { - log.LogEvent(nameof(ScheduleAppRefresh)); + log.LogEvent(nameof(ScheduleBackgroundCheck)); } } private void Service_FeatureChanged(object? sender, EventArgs e) { - var service = Resolver.Resolve(); + var service = Resolver.Resolve(); - if (CheckFeature()) + if (CheckPremium()) { if (service == null) { throw new ArgumentNullException("Add IFeatureService to IoC"); } - service.FeatureChanged -= Service_FeatureChanged; + service.PremiumChanged -= Service_FeatureChanged; } } - private void SendNotification(int badgeNumber) + private static void SendNotification(int badgeNumber) { var shouldSend = Preferences.Default.Get("Notifications", false); @@ -180,7 +236,8 @@ private void SendNotification(int badgeNumber) { if (err != null) { - // Do something with error... + var log = Resolver.Resolve(); + log!.LogException(new Exception(err.ToString())); } }); #endif diff --git a/ServiceBusManager/Platforms/MacCatalyst/Info.plist b/ServiceBusManager/Platforms/MacCatalyst/Info.plist index 464cd93..743999c 100644 --- a/ServiceBusManager/Platforms/MacCatalyst/Info.plist +++ b/ServiceBusManager/Platforms/MacCatalyst/Info.plist @@ -27,7 +27,7 @@ Assets.xcassets/appicon.appiconset UIBackgroundModes - process + processing LSApplicationCategoryType public.app-category.developer-tools @@ -36,10 +36,10 @@ CFBundleDisplayName AzServiceBus BGTaskSchedulerPermittedIdentifiers - - se.hindrikes.azservicebus.fetch - -ITSAppUsesNonExemptEncryption + + se.hindrikes.azservicebus.fetch + + ITSAppUsesNonExemptEncryption diff --git a/ServiceBusManager/ServiceBusManager.csproj b/ServiceBusManager/ServiceBusManager.csproj index 4c3b74e..1abbeba 100644 --- a/ServiceBusManager/ServiceBusManager.csproj +++ b/ServiceBusManager/ServiceBusManager.csproj @@ -24,7 +24,7 @@ 43681C5C-733E-4899-B69F-32C627F37BA2 1.0 - 17 + 22 14.2 14.0 21.0 @@ -51,7 +51,7 @@ Apple Development: Created via API (C65YK5VCL5) AzServiceBusDebug - True + False @@ -83,7 +83,7 @@ - + \ No newline at end of file diff --git a/ServiceBusManager/Services/FeatureService.cs b/ServiceBusManager/Services/FeatureService.cs deleted file mode 100644 index b39f52d..0000000 --- a/ServiceBusManager/Services/FeatureService.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; -namespace ServiceBusManager.Services -{ - public sealed class FeatureService : IFeatureService - { - private Dictionary? features; - - public FeatureService() - { - } - - public event EventHandler FeatureChanged; - - public void AddFeature(string featureName) - { - if(features == null) - { - LoadFeatures(); - } - - if(features!.ContainsKey(featureName)) - { - features[featureName] = DateTime.MaxValue; - return; - } - - features.Add(featureName, DateTime.MaxValue); - - SaveFeatures(); - } - - public void AddFeature(string featureName, DateTime validTo) - { - if (features == null) - { - LoadFeatures(); - } - - if (features!.ContainsKey(featureName)) - { - features[featureName] = validTo; - return; - } - - features.Add(featureName, validTo); - - SaveFeatures(); - } - - public bool HasFeature(string featureName) - { - if (features == null) - { - LoadFeatures(); - } - - if(features!.ContainsKey(featureName)) - { - var validTo = features[featureName]; - - if(validTo >= DateTime.Now) - { - return true; - } - } - - return false; - } - - private void LoadFeatures() - { - var path = Path.Combine(FileSystem.Current.AppDataDirectory, "appfeatures.json"); - - if (File.Exists(path)) - { - var json = File.ReadAllText(path); - - features = JsonSerializer.Deserialize>(json); - - return; - } - - features = new(); - } - - private void SaveFeatures() - { - var path = Path.Combine(FileSystem.Current.AppDataDirectory, "appfeatures.json"); - - var json = JsonSerializer.Serialize(features); - - File.WriteAllText(path, json); - - FeatureChanged?.Invoke(this, EventArgs.Empty); - } - } -} - diff --git a/ServiceBusManager/Services/IFeatureService.cs b/ServiceBusManager/Services/IFeatureService.cs deleted file mode 100644 index ad680f2..0000000 --- a/ServiceBusManager/Services/IFeatureService.cs +++ /dev/null @@ -1,12 +0,0 @@ - -namespace ServiceBusManager.Services; - -public interface IFeatureService -{ - bool HasFeature(string featureName); - void AddFeature(string featureName); - void AddFeature(string featureName, DateTime validTo); - - event EventHandler FeatureChanged; -} - diff --git a/ServiceBusManager/Services/IPremiumService.cs b/ServiceBusManager/Services/IPremiumService.cs new file mode 100644 index 0000000..fb550d7 --- /dev/null +++ b/ServiceBusManager/Services/IPremiumService.cs @@ -0,0 +1,12 @@ + +namespace ServiceBusManager.Services; + +public interface IPremiumService +{ + bool HasPremium(); + void AddPremium(); + void AddPremium(DateTime validTo); + + event EventHandler? PremiumChanged; +} + diff --git a/ServiceBusManager/Services/PremiumService.cs b/ServiceBusManager/Services/PremiumService.cs new file mode 100644 index 0000000..a60682c --- /dev/null +++ b/ServiceBusManager/Services/PremiumService.cs @@ -0,0 +1,42 @@ +using System; +namespace ServiceBusManager.Services +{ + public sealed class PremiumService : IPremiumService + { + public PremiumService() + { + } + + public event EventHandler? PremiumChanged; + + public void AddPremium() + { + Preferences.Default.Set(Constants.Premium, DateTime.MaxValue); + + PremiumChanged?.Invoke(this, EventArgs.Empty); + } + + public void AddPremium(DateTime validTo) + { + Preferences.Default.Set(Constants.Premium, validTo); + + PremiumChanged?.Invoke(this, EventArgs.Empty); + } + + public bool HasPremium() + { + if (Preferences.ContainsKey(Constants.Premium)) + { + var validTo = Preferences.Default.Get(Constants.Premium, DateTime.MinValue); + + if (validTo >= DateTime.Now) + { + return true; + } + } + + return false; + } + } +} + diff --git a/ServiceBusManager/ViewModels/ConnectViewModel.cs b/ServiceBusManager/ViewModels/ConnectViewModel.cs index be0c507..af38b18 100644 --- a/ServiceBusManager/ViewModels/ConnectViewModel.cs +++ b/ServiceBusManager/ViewModels/ConnectViewModel.cs @@ -6,9 +6,9 @@ namespace ServiceBusManager.ViewModels; public sealed partial class ConnectViewModel : ViewModel { private readonly IConnectionService connectionService; - private readonly IFeatureService featureService; + private readonly IPremiumService featureService; - public ConnectViewModel(IConnectionService connectionService, IFeatureService featureService, ILogService logService) : base(logService) + public ConnectViewModel(IConnectionService connectionService, IPremiumService featureService, ILogService logService) : base(logService) { this.connectionService = connectionService; this.featureService = featureService; @@ -94,7 +94,7 @@ private async Task SaveAndConnectToNew() { if (connectionString == SecretKeys.PremiumKey) { - featureService.AddFeature(Constants.Features.Premium); + featureService.AddPremium(); return; } diff --git a/ServiceBusManager/ViewModels/PremiumViewModel.cs b/ServiceBusManager/ViewModels/PremiumViewModel.cs index 570d6dc..79e764b 100644 --- a/ServiceBusManager/ViewModels/PremiumViewModel.cs +++ b/ServiceBusManager/ViewModels/PremiumViewModel.cs @@ -6,9 +6,9 @@ namespace ServiceBusManager.ViewModels; public sealed partial class PremiumViewModel : ViewModel { - public PremiumViewModel(IFeatureService featureService, ILogService logService) : base(logService) + public PremiumViewModel(IPremiumService featureService, ILogService logService) : base(logService) { - this.featureService = featureService; + this.premiumService = featureService; } public override async Task Initialize() @@ -45,6 +45,11 @@ public override async Task Initialize() IsBusy = false; } + private async Task Load() + { + + } + [ObservableProperty] private string? lifePrice; @@ -53,7 +58,7 @@ public override async Task Initialize() [ObservableProperty] private string? monthPrice; - private readonly IFeatureService featureService; + private readonly IPremiumService premiumService; [RelayCommand] private async Task BuyLifetime() @@ -69,7 +74,7 @@ private async Task BuyLifetime() if (result != null && result.State == PurchaseState.Purchased) { - featureService.AddFeature(Constants.Features.Premium); + premiumService.AddPremium(); await Finalize(result.TransactionIdentifier); } @@ -96,7 +101,7 @@ private async Task BuyMonthly() if (result != null && result.State == PurchaseState.Purchased) { - featureService.AddFeature(Constants.Features.Premium, DateTime.Now.AddMonths(1)); + premiumService.AddPremium(DateTime.Now.AddMonths(1)); await Finalize(result.TransactionIdentifier); } @@ -123,7 +128,7 @@ private async Task BuyYearly() if (result != null && result.State == PurchaseState.Purchased) { - featureService.AddFeature(Constants.Features.Premium, DateTime.Now.AddYears(1)); + premiumService.AddPremium(DateTime.Now.AddYears(1)); await Finalize(result.TransactionIdentifier); } @@ -159,12 +164,12 @@ private async Task RestorePurchase() { if(purchase.ProductId == Constants.Products.Monthly && purchase.TransactionDateUtc < DateTime.UtcNow.AddMonths(1)) { - featureService.AddFeature(Constants.Features.Premium, purchase.TransactionDateUtc.AddMonths(1)); + premiumService.AddPremium(purchase.TransactionDateUtc.AddMonths(1)); return true; } else if (purchase.ProductId == Constants.Products.Yearly && purchase.TransactionDateUtc < DateTime.UtcNow.AddYears(1)) { - featureService.AddFeature(Constants.Features.Premium, purchase.TransactionDateUtc.AddYears(1)); + premiumService.AddPremium(purchase.TransactionDateUtc.AddYears(1)); return true; } @@ -179,7 +184,7 @@ private async Task RestorePurchase() if (purchase != null && purchase.ProductId == Constants.Products.Lifetime) { - featureService.AddFeature(Constants.Features.Premium); + premiumService.AddPremium(); return true; } } diff --git a/ServiceBusManager/ViewModels/ViewModel.cs b/ServiceBusManager/ViewModels/ViewModel.cs index 9494e0a..0f37944 100644 --- a/ServiceBusManager/ViewModels/ViewModel.cs +++ b/ServiceBusManager/ViewModels/ViewModel.cs @@ -6,7 +6,7 @@ namespace ServiceBusManager.ViewModels; public partial class ViewModel : TinyViewModel { private readonly ILogService logService; - private IFeatureService? featureService; + private IPremiumService? premiumService; private static Dictionary Actions { get; } = new Dictionary(); private static Dictionary> ParameterActions { get; } = new Dictionary>(); @@ -23,15 +23,15 @@ public override async Task Initialize() { await base.Initialize(); - var service = Resolver.Resolve(); + var service = Resolver.Resolve(); if (service == null) { throw new NullReferenceException("IFeatureService need to be added to IoC container"); } - featureService = service; + premiumService = service; - service.FeatureChanged += (sender, args) => CheckPremium(); + service.PremiumChanged += (sender, args) => CheckPremium(); if (!hasPremium.HasValue) { @@ -43,7 +43,7 @@ private void CheckPremium() { _ = Task.Run(() => { - hasPremium = featureService?.HasFeature(Constants.Features.Premium); + hasPremium = premiumService?.HasPremium(); MainThread.BeginInvokeOnMainThread(() => { OnPropertyChanged(nameof(HasPremium)); diff --git a/ServiceBusManager/Views/AboutView.xaml b/ServiceBusManager/Views/AboutView.xaml index bbb534d..a4d6a9e 100644 --- a/ServiceBusManager/Views/AboutView.xaml +++ b/ServiceBusManager/Views/AboutView.xaml @@ -23,7 +23,7 @@