Skip to content

Commit

Permalink
Merge branch 'master' into feature/migration-to-net8
Browse files Browse the repository at this point in the history
  • Loading branch information
wcoder committed Oct 29, 2023
2 parents 531e421 + 4fdd0da commit 4a73993
Show file tree
Hide file tree
Showing 13 changed files with 519 additions and 111 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Developed by Softeq Development Corporation
// http://www.softeq.com

using Xunit;
using CollectionHelper = Softeq.XToolkit.Common.Tests.Collections.ObservableKeyGroupsCollectionTest.ObservableKeyGroupsCollectionHelper;

namespace Softeq.XToolkit.Common.Tests.Collections.ObservableKeyGroupsCollectionTest;

public class ObservableKeyGroupsCollectionTestsCountChanged
{
[Fact]
public void AddGroups_KeysOnlyForbidEmptyGroupCorrectKeys_RaisesPropertyChangedForCount()
{
var collection = CollectionHelper.CreateFilledGroupsWithoutEmpty();
var pairs = CollectionHelper.PairNotContainedKeyWithItems;

Assert.PropertyChanged(collection, nameof(collection.Count), () =>
{
collection.AddGroups(pairs);
});
}

[Fact]
public void InsertGroups_KeysOnlyForbidEmptyGroupCorrectKeys_RaisesPropertyChangedForCount()
{
var collection = CollectionHelper.CreateFilledGroupsWithoutEmpty();
var pairs = CollectionHelper.PairNotContainedKeyWithItems;

Assert.PropertyChanged(collection, nameof(collection.Count), () =>
{
collection.InsertGroups(0, pairs);
});
}

[Fact]
public void ReplaceAllGroups_KeysOnlyAllowEmptyGroupCorrectKeys_RaisesPropertyChangedForCount()
{
var collection = CollectionHelper.CreateFilledGroupsWithEmpty();
var keys = CollectionHelper.KeysEmpty;

Assert.PropertyChanged(collection, nameof(collection.Count), () =>
{
collection.ReplaceAllGroups(keys);
});
}

[Fact]
public void ReplaceAllGroups_KeysOnlyAllowEmptyGroupEmptyCollection_RaisesPropertyChangedForCount()
{
var collection = CollectionHelper.CreateFilledGroupsWithEmpty();
var pairs = CollectionHelper.PairsEmpty;

Assert.PropertyChanged(collection, nameof(collection.Count), () =>
{
collection.ReplaceAllGroups(pairs);
});
}

[Fact]
public void RemoveGroups_KeysOnlyForbidEmptyGroupContainsKey_RaisesPropertyChangedForCount()
{
var collection = CollectionHelper.CreateFilledGroupsWithoutEmpty();

Assert.PropertyChanged(collection, nameof(collection.Count), () =>
{
collection.RemoveGroups(CollectionHelper.KeysOneFill);
});
}

[Fact]
public void Clear_FilledCollection_RaisesPropertyChangedForCount()
{
var collection = CollectionHelper.CreateFilledGroupsWithoutEmpty();

Assert.PropertyChanged(collection, nameof(collection.Count), () =>
{
collection.Clear();
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using Softeq.XToolkit.Common.Collections.EventArgs;
using Softeq.XToolkit.Common.Extensions;

Expand All @@ -21,7 +23,8 @@ namespace Softeq.XToolkit.Common.Collections
public sealed class ObservableKeyGroupsCollection<TKey, TValue>
: IObservableKeyGroupsCollection<TKey, TValue>,
INotifyKeyGroupCollectionChanged<TKey, TValue>,
INotifyCollectionChanged
INotifyCollectionChanged,
INotifyPropertyChanged
where TKey : notnull
where TValue : notnull
{
Expand All @@ -42,6 +45,7 @@ public ObservableKeyGroupsCollection(bool allowEmptyGroups = true)

public event NotifyCollectionChangedEventHandler? CollectionChanged;
public event EventHandler<NotifyKeyGroupCollectionChangedEventArgs<TKey, TValue>>? ItemsChanged;
public event PropertyChangedEventHandler? PropertyChanged;

public IList<TKey> Keys => _groups.Select(item => item.Key).ToList();

Expand Down Expand Up @@ -161,14 +165,11 @@ public void ReplaceAllGroups(IEnumerable<KeyValuePair<TKey, IList<TValue>>> item
_groups.Clear();

var insertedGroups = InsertGroupsWithoutNotify(0, items, _emptyGroupsDisabled);
if (insertedGroups == null)
{
return;
}
var insertedGroupKeys = insertedGroups?.Select(x => x.Key).ToList() ?? new List<TKey>();

var newItems = new Collection<(int, IReadOnlyList<TKey>)>
{
(0, insertedGroups.Select(x => x.Key).ToList())
(0, insertedGroupKeys)
};

OnChanged(
Expand Down Expand Up @@ -534,6 +535,8 @@ private void RaiseEvents(NotifyKeyGroupCollectionChangedEventArgs<TKey, TValue>
}

ItemsChanged?.Invoke(this, args);

NotifyCountIfNeeded(args);
}

private IEnumerable<Group>? InsertGroupsWithoutNotify(
Expand Down Expand Up @@ -697,6 +700,29 @@ private void DecrementIndex<T>(IList<KeyValuePair<T, int>> indexes)
}
}

private void NotifyCountIfNeeded(NotifyKeyGroupCollectionChangedEventArgs<TKey, TValue> args)
{
var isCountOfGroupsChanged = IsActionCanModifyGroup(args.Action);
if (isCountOfGroupsChanged)
{
OnPropertyChanged(nameof(Count));
}
}

private bool IsActionCanModifyGroup(NotifyCollectionChangedAction? action)
{
return action
is NotifyCollectionChangedAction.Add
or NotifyCollectionChangedAction.Remove
or NotifyCollectionChangedAction.Replace
or NotifyCollectionChangedAction.Reset;
}

private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

private class Group : List<TValue>, IGrouping<TKey, TValue>
{
public Group(KeyValuePair<TKey, IList<TValue>> keyValuePair)
Expand Down
76 changes: 38 additions & 38 deletions Softeq.XToolkit.Permissions.Droid/PermissionsManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
// http://www.softeq.com

using System;
using System.Diagnostics;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.Maui.Storage;
using BasePermission = Microsoft.Maui.ApplicationModel.Permissions.BasePermission;
using XToolkitPermissions = Softeq.XToolkit.Permissions.Permissions;
using XToolkitPermissionsDroid = Softeq.XToolkit.Permissions.Droid.Permissions;
using CustomPermissions = Softeq.XToolkit.Permissions.Permissions;
using PlatformCustomPermissions = Softeq.XToolkit.Permissions.Droid.Permissions;

namespace Softeq.XToolkit.Permissions.Droid
{
Expand All @@ -31,15 +31,15 @@ public virtual Task<PermissionStatus> CheckAsync<T>()
where T : BasePermission, new()
{
var permissionType = typeof(T);
if (permissionType == typeof(XToolkitPermissions.Notifications))
if (permissionType == typeof(CustomPermissions.Notifications))
{
return _permissionsService.CheckPermissionsAsync<XToolkitPermissionsDroid.Notifications>();
return _permissionsService.CheckPermissionsAsync<PlatformCustomPermissions.Notifications>();
}
else if (permissionType == typeof(XToolkitPermissions.Bluetooth))
else if (permissionType == typeof(CustomPermissions.Bluetooth))
{
return _permissionsService.CheckPermissionsAsync<XToolkitPermissionsDroid.Bluetooth>();
return _permissionsService.CheckPermissionsAsync<PlatformCustomPermissions.Bluetooth>();
}
else
else
{
return _permissionsService.CheckPermissionsAsync<T>();
}
Expand All @@ -50,15 +50,15 @@ public Task<PermissionStatus> CheckWithRequestAsync<T>()
where T : BasePermission, new()
{
var permissionType = typeof(T);
if (permissionType == typeof(XToolkitPermissions.Notifications))
if (permissionType == typeof(CustomPermissions.Notifications))
{
return CommonCheckWithRequestAsync<XToolkitPermissionsDroid.Notifications>();
return CommonCheckWithRequestAsync<PlatformCustomPermissions.Notifications>();
}
else if (permissionType == typeof(XToolkitPermissions.Bluetooth))
else if (permissionType == typeof(CustomPermissions.Bluetooth))
{
return CommonCheckWithRequestAsync<XToolkitPermissionsDroid.Bluetooth>();
return CommonCheckWithRequestAsync<PlatformCustomPermissions.Bluetooth>();
}
else
else
{
return CommonCheckWithRequestAsync<T>();
}
Expand All @@ -76,31 +76,31 @@ private void OpenSettings()
_permissionsService.OpenSettings();
}

private void RemoveOldKeys<T>()
where T : BasePermission, new()
{
var requestedKey = GetPermissionRequestedKey<T>();
private void RemoveOldKeys<T>()
where T : BasePermission, new()
{
var requestedKey = GetPermissionRequestedKey<T>();
if (Preferences.ContainsKey(requestedKey))
{
Preferences.Remove(requestedKey);
}

var deniedEverKey = GetPermissionDeniedEverKey<T>();
{
Preferences.Remove(requestedKey);
}

var deniedEverKey = GetPermissionDeniedEverKey<T>();
if (Preferences.ContainsKey(deniedEverKey))
{
Preferences.Remove(deniedEverKey);
}

string GetPermissionRequestedKey<TPermission>()
where TPermission : BasePermission
{
return $"{nameof(PermissionsManager)}_IsPermissionRequested_{typeof(T).Name}";
}

{
Preferences.Remove(deniedEverKey);
}

string GetPermissionRequestedKey<TPermission>()
where TPermission : BasePermission
{
return $"{nameof(PermissionsManager)}_IsPermissionRequested_{typeof(T).Name}";
}

string GetPermissionDeniedEverKey<T>()
where T : BasePermission
{
return $"{nameof(PermissionsManager)}_IsPermissionDeniedEver_{typeof(T).Name}";
where T : BasePermission
{
return $"{nameof(PermissionsManager)}_IsPermissionDeniedEver_{typeof(T).Name}";
}
}

Expand All @@ -115,7 +115,7 @@ private async Task<PermissionStatus> CommonCheckWithRequestAsync<T>()

RemoveOldKeys<T>();

// Timer are used for confirm a fact of showing a request of permission access popup
// Timer are used for confirm a fact of showing a request of permission access popup
// in another case user should see screen with settings for changing permission state
var timer = new Stopwatch();
timer.Start();
Expand All @@ -126,7 +126,7 @@ private async Task<PermissionStatus> CommonCheckWithRequestAsync<T>()
permissionStatus = await _permissionsService.RequestPermissionsAsync<T>().ConfigureAwait(false);
}

if (permissionStatus == PermissionStatus.Denied
if (permissionStatus == PermissionStatus.Denied
&& timer.Elapsed < _showPermissionDialogThreshold)
{
await OpenSettingsWithConfirmationAsync<T>().ConfigureAwait(false);
Expand All @@ -147,4 +147,4 @@ private async Task OpenSettingsWithConfirmationAsync<T>()
}
}
}
}
}
16 changes: 8 additions & 8 deletions Softeq.XToolkit.Permissions.iOS/Permissions/Bluetooth.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@

using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Reactive.Threading.Tasks;
using System.Threading.Tasks;
using CoreBluetooth;
using BasePlatformPermission = Microsoft.Maui.ApplicationModel.Permissions.BasePlatformPermission;
Expand All @@ -15,21 +12,24 @@ namespace Softeq.XToolkit.Permissions.iOS.Permissions
{
public class Bluetooth : BasePlatformPermission
{
/// <inheritdoc />
protected override Func<IEnumerable<string>> RequiredInfoPlistKeys =>
() => new string[] { "NSBluetoothAlwaysUsageDescription" };

/// <inheritdoc />
public override Task<EssentialsPermissionStatus> CheckStatusAsync()
{
EnsureDeclared();

return Task.FromResult(ParseAuthorization(CBManager.Authorization));
}

/// <inheritdoc />
public override async Task<EssentialsPermissionStatus> RequestAsync()
{
EnsureDeclared();

var status = await CheckStatusAsync();
var status = await CheckStatusAsync().ConfigureAwait(false);

if (status == EssentialsPermissionStatus.Granted)
{
Expand All @@ -39,7 +39,7 @@ public override async Task<EssentialsPermissionStatus> RequestAsync()
if (CBManager.Authorization == CBManagerAuthorization.NotDetermined)
{
var centralManagerDelegate = new CentralManagerDelegate();
await centralManagerDelegate.RequestAccessAsync();
await centralManagerDelegate.RequestAccessAsync().ConfigureAwait(false);
}

return ParseAuthorization(CBManager.Authorization);
Expand All @@ -61,7 +61,7 @@ private class CentralManagerDelegate : CBCentralManagerDelegate
{
private readonly CBCentralManager _centralManager;

private TaskCompletionSource<CBManagerState> _statusRequest =
private readonly TaskCompletionSource<CBManagerState> _statusRequest =
new TaskCompletionSource<CBManagerState>();

public CentralManagerDelegate()
Expand All @@ -71,7 +71,7 @@ public CentralManagerDelegate()

public async Task<CBManagerState> RequestAccessAsync()
{
var state = await _statusRequest.Task;
var state = await _statusRequest.Task.ConfigureAwait(false);
return state;
}

Expand All @@ -84,4 +84,4 @@ public override void UpdatedState(CBCentralManager centralManager)
}
}
}
}
}
Loading

0 comments on commit 4a73993

Please sign in to comment.