diff --git a/src/App/Abstractions/Services/IAppSettingsService.cs b/src/App/Abstractions/Services/IAppSettingsService.cs index 2ffd60bd4..77b5736bc 100644 --- a/src/App/Abstractions/Services/IAppSettingsService.cs +++ b/src/App/Abstractions/Services/IAppSettingsService.cs @@ -9,6 +9,7 @@ namespace Bit.App.Abstractions DateTime LastCacheClear { get; set; } bool AutofillPersistNotification { get; set; } bool AutofillPasswordField { get; set; } + bool DisableWebsiteIcons { get; set; } string SecurityStamp { get; set; } string BaseUrl { get; set; } string WebVaultUrl { get; set; } diff --git a/src/App/Constants.cs b/src/App/Constants.cs index 2f243f01d..2cbbe8886 100644 --- a/src/App/Constants.cs +++ b/src/App/Constants.cs @@ -9,6 +9,7 @@ public const string SettingPinUnlockOn = "setting:pinUnlockOn"; public const string SettingLockSeconds = "setting:lockSeconds"; public const string SettingGaOptOut = "setting:googleAnalyticsOptOut"; + public const string SettingDisableWebsiteIcons = "setting:disableWebsiteIcons"; public const string SettingDisableTotpCopy = "setting:disableAutoCopyTotp"; public const string AutofillPersistNotification = "setting:persistNotification"; public const string AutofillPasswordField = "setting:autofillPasswordField"; diff --git a/src/App/Models/Page/VaultListPageModel.cs b/src/App/Models/Page/VaultListPageModel.cs index f0edc98d2..8390f6e3c 100644 --- a/src/App/Models/Page/VaultListPageModel.cs +++ b/src/App/Models/Page/VaultListPageModel.cs @@ -10,7 +10,7 @@ namespace Bit.App.Models.Page { public class Cipher { - public Cipher(Models.Cipher cipher) + public Cipher(Models.Cipher cipher, bool imageEnabled) { Id = cipher.Id; Shared = !string.IsNullOrWhiteSpace(cipher.OrganizationId); @@ -38,17 +38,17 @@ namespace Bit.App.Models.Page { Icon = "apple.png"; } - else if(!hostnameUri.Contains("://") && hostnameUri.Contains(".")) + else if(imageEnabled && !hostnameUri.Contains("://") && hostnameUri.Contains(".")) { hostnameUri = $"http://{hostnameUri}"; isWebsite = true; } - else if(true) + else if(imageEnabled) { isWebsite = hostnameUri.StartsWith("http") && hostnameUri.Contains("."); } - if(isWebsite && Uri.TryCreate(LoginUri, UriKind.Absolute, out Uri u)) + if(imageEnabled && isWebsite && Uri.TryCreate(LoginUri, UriKind.Absolute, out Uri u)) { Icon = "https://icons.bitwarden.com/" + u.Host + "/icon.png"; } @@ -122,8 +122,8 @@ namespace Bit.App.Models.Page public class AutofillCipher : Cipher { - public AutofillCipher(Models.Cipher cipher, bool fuzzy = false) - : base(cipher) + public AutofillCipher(Models.Cipher cipher, bool imageEnabled, bool fuzzy = false) + : base(cipher, imageEnabled) { Fuzzy = fuzzy; } diff --git a/src/App/Pages/Settings/SettingsFeaturesPage.cs b/src/App/Pages/Settings/SettingsFeaturesPage.cs index eb8d2e643..fddfddfc4 100644 --- a/src/App/Pages/Settings/SettingsFeaturesPage.cs +++ b/src/App/Pages/Settings/SettingsFeaturesPage.cs @@ -28,6 +28,8 @@ namespace Bit.App.Pages private Label CopyTotpLabel { get; set; } private ExtendedSwitchCell AnalyticsCell { get; set; } private Label AnalyticsLabel { get; set; } + private ExtendedSwitchCell WebsiteIconsCell { get; set; } + private Label WebsiteIconsLabel { get; set; } private ExtendedSwitchCell AutofillPersistNotificationCell { get; set; } private Label AutofillPersistNotificationLabel { get; set; } private ExtendedSwitchCell AutofillPasswordFieldCell { get; set; } @@ -37,13 +39,30 @@ namespace Bit.App.Pages private void Init() { + WebsiteIconsCell = new ExtendedSwitchCell + { + Text = AppResources.DisableWebsiteIcons, + On = _appSettings.DisableWebsiteIcons + }; + + var websiteIconsTable = new FormTableView(true) + { + Root = new TableRoot + { + new TableSection(" ") + { + WebsiteIconsCell + } + } + }; + CopyTotpCell = new ExtendedSwitchCell { Text = AppResources.DisableAutoTotpCopy, On = _settings.GetValueOrDefault(Constants.SettingDisableTotpCopy, false) }; - var totpTable = new FormTableView(true) + var totpTable = new FormTableView { Root = new TableRoot { @@ -81,9 +100,19 @@ namespace Bit.App.Pages Text = AppResources.DisableGADescription }; + WebsiteIconsLabel = new FormTableLabel(this) + { + Text = AppResources.DisableWebsiteIconsDescription + }; + StackLayout = new StackLayout { - Children = { totpTable, CopyTotpLabel, analyticsTable, AnalyticsLabel }, + Children = + { + websiteIconsTable, WebsiteIconsLabel, + totpTable, CopyTotpLabel, + analyticsTable, AnalyticsLabel + }, Spacing = 0 }; @@ -170,8 +199,9 @@ namespace Bit.App.Pages if(Device.RuntimePlatform == Device.iOS || Device.RuntimePlatform == Device.Windows) { - analyticsTable.RowHeight = -1; - analyticsTable.EstimatedRowHeight = 70; + analyticsTable.RowHeight = websiteIconsTable.RowHeight = totpTable.RowHeight = -1; + analyticsTable.EstimatedRowHeight = websiteIconsTable.EstimatedRowHeight = + totpTable.EstimatedRowHeight = 70; ToolbarItems.Add(new DismissModalToolBarItem(this, AppResources.Close)); } @@ -184,6 +214,7 @@ namespace Bit.App.Pages base.OnAppearing(); AnalyticsCell.OnChanged += AnalyticsCell_Changed; + WebsiteIconsCell.OnChanged += WebsiteIconsCell_Changed; CopyTotpCell.OnChanged += CopyTotpCell_OnChanged; StackLayout.LayoutChanged += Layout_LayoutChanged; @@ -200,6 +231,7 @@ namespace Bit.App.Pages base.OnDisappearing(); AnalyticsCell.OnChanged -= AnalyticsCell_Changed; + WebsiteIconsCell.OnChanged -= WebsiteIconsCell_Changed; CopyTotpCell.OnChanged -= CopyTotpCell_OnChanged; StackLayout.LayoutChanged -= Layout_LayoutChanged; @@ -214,6 +246,7 @@ namespace Bit.App.Pages private void Layout_LayoutChanged(object sender, EventArgs e) { AnalyticsLabel.WidthRequest = StackLayout.Bounds.Width - AnalyticsLabel.Bounds.Left * 2; + WebsiteIconsLabel.WidthRequest = StackLayout.Bounds.Width - WebsiteIconsLabel.Bounds.Left * 2; CopyTotpLabel.WidthRequest = StackLayout.Bounds.Width - CopyTotpLabel.Bounds.Left * 2; if(AutofillAlwaysLabel != null) @@ -233,6 +266,17 @@ namespace Bit.App.Pages } } + private void WebsiteIconsCell_Changed(object sender, ToggledEventArgs e) + { + var cell = sender as ExtendedSwitchCell; + if(cell == null) + { + return; + } + + _appSettings.DisableWebsiteIcons = cell.On; + } + private void AnalyticsCell_Changed(object sender, ToggledEventArgs e) { var cell = sender as ExtendedSwitchCell; diff --git a/src/App/Pages/Vault/VaultAutofillListCiphersPage.cs b/src/App/Pages/Vault/VaultAutofillListCiphersPage.cs index cfbc54ecb..c9c211247 100644 --- a/src/App/Pages/Vault/VaultAutofillListCiphersPage.cs +++ b/src/App/Pages/Vault/VaultAutofillListCiphersPage.cs @@ -22,6 +22,7 @@ namespace Bit.App.Pages private readonly IDeviceInfoService _deviceInfoService; private readonly IDeviceActionService _clipboardService; private readonly ISettingsService _settingsService; + private readonly IAppSettingsService _appSettingsService; private CancellationTokenSource _filterResultsCancellationTokenSource; private readonly string _name; @@ -46,6 +47,7 @@ namespace Bit.App.Pages _clipboardService = Resolver.Resolve(); _settingsService = Resolver.Resolve(); UserDialogs = Resolver.Resolve(); + _appSettingsService = Resolver.Resolve(); GoogleAnalyticsService = Resolver.Resolve(); Init(); @@ -159,13 +161,15 @@ namespace Bit.App.Pages { var cts = new CancellationTokenSource(); _filterResultsCancellationTokenSource?.Cancel(); + var websiteIconsEnabled = !_appSettingsService.DisableWebsiteIcons; Task.Run(async () => { var autofillGroupings = new List(); var ciphers = await _cipherService.GetAllAsync(Uri); - var normalLogins = ciphers?.Item1.Select(l => new VaultListPageModel.AutofillCipher(l, false)) + var normalLogins = ciphers?.Item1.Select(l => new VaultListPageModel.AutofillCipher( + l, websiteIconsEnabled, false)) .OrderBy(s => s.Name) .ThenBy(s => s.Subtitle) .ToList(); @@ -174,7 +178,8 @@ namespace Bit.App.Pages autofillGroupings.Add(new VaultListPageModel.AutofillGrouping(normalLogins, AppResources.MatchingItems)); } - var fuzzyLogins = ciphers?.Item2.Select(l => new VaultListPageModel.AutofillCipher(l, true)) + var fuzzyLogins = ciphers?.Item2.Select(l => new VaultListPageModel.AutofillCipher( + l, websiteIconsEnabled, true)) .OrderBy(s => s.Name) .ThenBy(s => s.LoginUsername) .ToList(); diff --git a/src/App/Pages/Vault/VaultListCiphersPage.cs b/src/App/Pages/Vault/VaultListCiphersPage.cs index 9748b94cd..bedc17a88 100644 --- a/src/App/Pages/Vault/VaultListCiphersPage.cs +++ b/src/App/Pages/Vault/VaultListCiphersPage.cs @@ -29,6 +29,7 @@ namespace Bit.App.Pages private readonly IPushNotificationService _pushNotification; private readonly IDeviceInfoService _deviceInfoService; private readonly ISettings _settings; + private readonly IAppSettingsService _appSettingsService; private readonly IGoogleAnalyticsService _googleAnalyticsService; private readonly bool _favorites; private CancellationTokenSource _filterResultsCancellationTokenSource; @@ -46,6 +47,7 @@ namespace Bit.App.Pages _pushNotification = Resolver.Resolve(); _deviceInfoService = Resolver.Resolve(); _settings = Resolver.Resolve(); + _appSettingsService = Resolver.Resolve(); _googleAnalyticsService = Resolver.Resolve(); var cryptoService = Resolver.Resolve(); @@ -309,6 +311,7 @@ namespace Bit.App.Pages } _filterResultsCancellationTokenSource?.Cancel(); + var websiteIconsEnabled = !_appSettingsService.DisableWebsiteIcons; Task.Run(async () => { @@ -325,7 +328,7 @@ namespace Bit.App.Pages .ToArray(); Ciphers = ciphers - .Select(s => new VaultListPageModel.Cipher(s)) + .Select(s => new VaultListPageModel.Cipher(s, websiteIconsEnabled)) .OrderBy(s => s.Name) .ThenBy(s => s.Subtitle) .ToArray(); diff --git a/src/App/Resources/AppResources.Designer.cs b/src/App/Resources/AppResources.Designer.cs index fd84fbd62..158fa30e0 100644 --- a/src/App/Resources/AppResources.Designer.cs +++ b/src/App/Resources/AppResources.Designer.cs @@ -925,6 +925,24 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Disable Website Icons. + /// + public static string DisableWebsiteIcons { + get { + return ResourceManager.GetString("DisableWebsiteIcons", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Website Icons provide a recognizable image next to each login item in your vault.. + /// + public static string DisableWebsiteIconsDescription { + get { + return ResourceManager.GetString("DisableWebsiteIconsDescription", resourceCulture); + } + } + /// /// Looks up a localized string similar to Downloading.... /// diff --git a/src/App/Resources/AppResources.resx b/src/App/Resources/AppResources.resx index a91275dcc..3bb41be62 100644 --- a/src/App/Resources/AppResources.resx +++ b/src/App/Resources/AppResources.resx @@ -1176,4 +1176,10 @@ Expiration + + Disable Website Icons + + + Website Icons provide a recognizable image next to each login item in your vault. + \ No newline at end of file diff --git a/src/App/Services/AppSettingsService.cs b/src/App/Services/AppSettingsService.cs index 6e49802e5..ec686c3a8 100644 --- a/src/App/Services/AppSettingsService.cs +++ b/src/App/Services/AppSettingsService.cs @@ -74,6 +74,18 @@ namespace Bit.App.Services } } + public bool DisableWebsiteIcons + { + get + { + return _settings.GetValueOrDefault(Constants.SettingDisableWebsiteIcons, false); + } + set + { + _settings.AddOrUpdateValue(Constants.SettingDisableWebsiteIcons, value); + } + } + public string SecurityStamp { get