mirror of
https://github.com/bitwarden/android.git
synced 2024-12-25 18:38:27 +03:00
[SG-912] Modify the mobile app to retrieve the user's avatar color (#2284)
* [SG-912] Modify the mobile app to retrieve the user's avatar color (#2277) * work: baseline * fix: dont use profile for store * fiix: use userid in key * fix: lookup on AccountView list create * fix my own bad advice + tweaks * Autosync the updated translations (#2279) * fix my own bad advice + tweaks * fiix: use userid in key * [PS-1352] Fix ignore diacritics in search (#2044) * Fix ignore diacritics in search This change updates the search function to ignore diacritical marks in search results. Marks are stripped from both the search input and results. * Removed logs, added null or whitespace validation and improved formatting * [PS-2145] add rainsee browser series support (#2272) * fix: lookup on AccountView list create * Autosync the updated translations (#2279) * fix my own bad advice + tweaks * fix: single state grab is cool
This commit is contained in:
parent
4f4953206e
commit
6102a0c115
11 changed files with 43 additions and 10 deletions
|
@ -14,7 +14,7 @@ namespace Bit.App.Controls
|
||||||
{
|
{
|
||||||
AccountView = accountView;
|
AccountView = accountView;
|
||||||
AvatarImageSource = ServiceContainer.Resolve<IAvatarImageSourcePool>("avatarImageSourcePool")
|
AvatarImageSource = ServiceContainer.Resolve<IAvatarImageSourcePool>("avatarImageSourcePool")
|
||||||
?.GetOrCreateAvatar(AccountView.UserId, AccountView.Name, AccountView.Email);
|
?.GetOrCreateAvatar(AccountView.UserId, AccountView.Name, AccountView.Email, AccountView.AvatarColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccountView AccountView
|
public AccountView AccountView
|
||||||
|
|
|
@ -13,6 +13,7 @@ namespace Bit.App.Controls
|
||||||
{
|
{
|
||||||
private readonly string _text;
|
private readonly string _text;
|
||||||
private readonly string _id;
|
private readonly string _id;
|
||||||
|
private readonly string _color;
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
{
|
{
|
||||||
|
@ -23,7 +24,7 @@ namespace Bit.App.Controls
|
||||||
|
|
||||||
if (obj is AvatarImageSource avatar)
|
if (obj is AvatarImageSource avatar)
|
||||||
{
|
{
|
||||||
return avatar._id == _id && avatar._text == _text;
|
return avatar._id == _id && avatar._text == _text && avatar._color == _color;
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.Equals(obj);
|
return base.Equals(obj);
|
||||||
|
@ -31,7 +32,7 @@ namespace Bit.App.Controls
|
||||||
|
|
||||||
public override int GetHashCode() => _id?.GetHashCode() ?? _text?.GetHashCode() ?? -1;
|
public override int GetHashCode() => _id?.GetHashCode() ?? _text?.GetHashCode() ?? -1;
|
||||||
|
|
||||||
public AvatarImageSource(string userId = null, string name = null, string email = null)
|
public AvatarImageSource(string userId = null, string name = null, string email = null, string color = null)
|
||||||
{
|
{
|
||||||
_id = userId;
|
_id = userId;
|
||||||
_text = name;
|
_text = name;
|
||||||
|
@ -39,6 +40,7 @@ namespace Bit.App.Controls
|
||||||
{
|
{
|
||||||
_text = email;
|
_text = email;
|
||||||
}
|
}
|
||||||
|
_color = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Func<CancellationToken, Task<Stream>> Stream => GetStreamAsync;
|
public override Func<CancellationToken, Task<Stream>> Stream => GetStreamAsync;
|
||||||
|
@ -71,7 +73,7 @@ namespace Bit.App.Controls
|
||||||
chars = upperCaseText = _text.ToUpper();
|
chars = upperCaseText = _text.ToUpper();
|
||||||
}
|
}
|
||||||
|
|
||||||
var bgColor = CoreHelpers.StringToColor(_id ?? upperCaseText, "#33ffffff");
|
var bgColor = _color ?? CoreHelpers.StringToColor(_id ?? upperCaseText, "#33ffffff");
|
||||||
var textColor = CoreHelpers.TextColorFromBgColor(bgColor);
|
var textColor = CoreHelpers.TextColorFromBgColor(bgColor);
|
||||||
var size = 50;
|
var size = 50;
|
||||||
|
|
||||||
|
|
|
@ -5,19 +5,19 @@ namespace Bit.App.Controls
|
||||||
{
|
{
|
||||||
public interface IAvatarImageSourcePool
|
public interface IAvatarImageSourcePool
|
||||||
{
|
{
|
||||||
AvatarImageSource GetOrCreateAvatar(string userId, string name, string email);
|
AvatarImageSource GetOrCreateAvatar(string userId, string name, string email, string color);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AvatarImageSourcePool : IAvatarImageSourcePool
|
public class AvatarImageSourcePool : IAvatarImageSourcePool
|
||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<string, AvatarImageSource> _cache = new ConcurrentDictionary<string, AvatarImageSource>();
|
private readonly ConcurrentDictionary<string, AvatarImageSource> _cache = new ConcurrentDictionary<string, AvatarImageSource>();
|
||||||
|
|
||||||
public AvatarImageSource GetOrCreateAvatar(string userId, string name, string email)
|
public AvatarImageSource GetOrCreateAvatar(string userId, string name, string email, string color)
|
||||||
{
|
{
|
||||||
var key = $"{userId}{name}{email}";
|
var key = $"{userId}{name}{email}{color}";
|
||||||
if (!_cache.TryGetValue(key, out var avatar))
|
if (!_cache.TryGetValue(key, out var avatar))
|
||||||
{
|
{
|
||||||
avatar = new AvatarImageSource(userId, name, email);
|
avatar = new AvatarImageSource(userId, name, email, color);
|
||||||
if (!_cache.TryAdd(key, avatar)
|
if (!_cache.TryAdd(key, avatar)
|
||||||
&&
|
&&
|
||||||
!_cache.TryGetValue(key, out avatar)) // If add fails another thread created the avatar in between the first try get and the try add.
|
!_cache.TryGetValue(key, out avatar)) // If add fails another thread created the avatar in between the first try get and the try add.
|
||||||
|
|
|
@ -129,8 +129,8 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
if (useCurrentActiveAccount)
|
if (useCurrentActiveAccount)
|
||||||
{
|
{
|
||||||
return new AvatarImageSource(await _stateService.GetActiveUserIdAsync(),
|
var user = await _stateService.GetActiveUserCustomDataAsync(a => (a?.Profile?.UserId, a?.Profile?.Name, a?.Profile?.Email, a?.Profile?.AvatarColor));
|
||||||
await _stateService.GetNameAsync(), await _stateService.GetEmailAsync());
|
return new AvatarImageSource(user.UserId, user.Name, user.Email, user.AvatarColor);
|
||||||
}
|
}
|
||||||
return new AvatarImageSource();
|
return new AvatarImageSource();
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,6 +108,10 @@ namespace Bit.App.Pages
|
||||||
else if (message.Command == "syncCompleted")
|
else if (message.Command == "syncCompleted")
|
||||||
{
|
{
|
||||||
await Task.Delay(500);
|
await Task.Delay(500);
|
||||||
|
if (_vm.MainPage)
|
||||||
|
{
|
||||||
|
_vm.AvatarImageSource = await GetAvatarImageSourceAsync();
|
||||||
|
}
|
||||||
Device.BeginInvokeOnMainThread(() =>
|
Device.BeginInvokeOnMainThread(() =>
|
||||||
{
|
{
|
||||||
IsBusy = false;
|
IsBusy = false;
|
||||||
|
|
|
@ -163,5 +163,9 @@ namespace Bit.Core.Abstractions
|
||||||
Task<bool> GetShouldConnectToWatchAsync(string userId = null);
|
Task<bool> GetShouldConnectToWatchAsync(string userId = null);
|
||||||
Task SetShouldConnectToWatchAsync(bool shouldConnect, string userId = null);
|
Task SetShouldConnectToWatchAsync(bool shouldConnect, string userId = null);
|
||||||
Task<bool> GetLastUserShouldConnectToWatchAsync();
|
Task<bool> GetLastUserShouldConnectToWatchAsync();
|
||||||
|
Task SetAvatarColorAsync(string value, string userId = null);
|
||||||
|
Task<string> GetAvatarColorAsync(string userId = null);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ namespace Bit.Core.Models.Domain
|
||||||
KdfIterations = copy.KdfIterations;
|
KdfIterations = copy.KdfIterations;
|
||||||
EmailVerified = copy.EmailVerified;
|
EmailVerified = copy.EmailVerified;
|
||||||
HasPremiumPersonally = copy.HasPremiumPersonally;
|
HasPremiumPersonally = copy.HasPremiumPersonally;
|
||||||
|
AvatarColor = copy.AvatarColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string UserId;
|
public string UserId;
|
||||||
|
@ -55,6 +56,7 @@ namespace Bit.Core.Models.Domain
|
||||||
public string Name;
|
public string Name;
|
||||||
public string Stamp;
|
public string Stamp;
|
||||||
public string OrgIdentifier;
|
public string OrgIdentifier;
|
||||||
|
public string AvatarColor;
|
||||||
public KdfType? KdfType;
|
public KdfType? KdfType;
|
||||||
public int? KdfIterations;
|
public int? KdfIterations;
|
||||||
public bool? EmailVerified;
|
public bool? EmailVerified;
|
||||||
|
|
|
@ -19,5 +19,6 @@ namespace Bit.Core.Models.Response
|
||||||
public bool ForcePasswordReset { get; set; }
|
public bool ForcePasswordReset { get; set; }
|
||||||
public List<ProfileOrganizationResponse> Organizations { get; set; }
|
public List<ProfileOrganizationResponse> Organizations { get; set; }
|
||||||
public bool UsesKeyConnector { get; set; }
|
public bool UsesKeyConnector { get; set; }
|
||||||
|
public string AvatarColor { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace Bit.Core.Models.View
|
||||||
UserId = a.Profile?.UserId;
|
UserId = a.Profile?.UserId;
|
||||||
Email = a.Profile?.Email;
|
Email = a.Profile?.Email;
|
||||||
Name = a.Profile?.Name;
|
Name = a.Profile?.Name;
|
||||||
|
AvatarColor = a.Profile?.AvatarColor;
|
||||||
if (!string.IsNullOrWhiteSpace(a.Settings?.EnvironmentUrls?.WebVault))
|
if (!string.IsNullOrWhiteSpace(a.Settings?.EnvironmentUrls?.WebVault))
|
||||||
{
|
{
|
||||||
Hostname = CoreHelpers.GetHostname(a.Settings?.EnvironmentUrls?.WebVault);
|
Hostname = CoreHelpers.GetHostname(a.Settings?.EnvironmentUrls?.WebVault);
|
||||||
|
@ -37,5 +38,6 @@ namespace Bit.Core.Models.View
|
||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Hostname { get; set; }
|
public string Hostname { get; set; }
|
||||||
|
public string AvatarColor { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1305,6 +1305,23 @@ namespace Bit.Core.Services
|
||||||
var key = Constants.PasswordlessLoginNotificationKey;
|
var key = Constants.PasswordlessLoginNotificationKey;
|
||||||
await SetValueAsync(key, value, options);
|
await SetValueAsync(key, value, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task SetAvatarColorAsync(string value, string userId = null)
|
||||||
|
{
|
||||||
|
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||||
|
await GetDefaultStorageOptionsAsync());
|
||||||
|
var account = await GetAccountAsync(reconciledOptions);
|
||||||
|
account.Profile.AvatarColor = value;
|
||||||
|
await SaveAccountAsync(account, reconciledOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> GetAvatarColorAsync(string userId = null)
|
||||||
|
{
|
||||||
|
return (await GetAccountAsync(
|
||||||
|
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultStorageOptionsAsync())
|
||||||
|
))?.Profile?.AvatarColor;
|
||||||
|
}
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
|
|
||||||
private async Task<T> GetValueAsync<T>(string key, StorageOptions options)
|
private async Task<T> GetValueAsync<T>(string key, StorageOptions options)
|
||||||
|
|
|
@ -335,6 +335,7 @@ namespace Bit.Core.Services
|
||||||
await _organizationService.ReplaceAsync(organizations);
|
await _organizationService.ReplaceAsync(organizations);
|
||||||
await _stateService.SetEmailVerifiedAsync(response.EmailVerified);
|
await _stateService.SetEmailVerifiedAsync(response.EmailVerified);
|
||||||
await _stateService.SetNameAsync(response.Name);
|
await _stateService.SetNameAsync(response.Name);
|
||||||
|
await _stateService.SetAvatarColorAsync(response.AvatarColor);
|
||||||
await _keyConnectorService.SetUsesKeyConnector(response.UsesKeyConnector);
|
await _keyConnectorService.SetUsesKeyConnector(response.UsesKeyConnector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue