mirror of
https://github.com/bitwarden/android.git
synced 2024-12-25 18:38:27 +03:00
Improve Theming (#1707)
* Improved theming logic and performance, also fixed some issues regarding changing the theme after vault timeout and fixed theme applying on password generator/history * Removed messenger from theme update, and now the navigation stack is traversed and each IThemeDirtablePage gets theme updated * Improved code on update theme on pages
This commit is contained in:
parent
939db8ebe0
commit
74e90da662
16 changed files with 264 additions and 84 deletions
|
@ -1,25 +1,24 @@
|
||||||
using Android.App;
|
using System;
|
||||||
using Android.Content.PM;
|
|
||||||
using Android.Runtime;
|
|
||||||
using Android.OS;
|
|
||||||
using Bit.Core;
|
|
||||||
using System.Linq;
|
|
||||||
using Bit.App.Abstractions;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Bit.Core.Abstractions;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System;
|
using System.Linq;
|
||||||
using Android.Content;
|
|
||||||
using Bit.Droid.Utilities;
|
|
||||||
using Bit.Droid.Receivers;
|
|
||||||
using Bit.App.Models;
|
|
||||||
using Bit.Core.Enums;
|
|
||||||
using Android.Nfc;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Android.App;
|
||||||
|
using Android.Content;
|
||||||
|
using Android.Content.PM;
|
||||||
|
using Android.Nfc;
|
||||||
|
using Android.OS;
|
||||||
|
using Android.Runtime;
|
||||||
using AndroidX.Core.Content;
|
using AndroidX.Core.Content;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Models;
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
|
using Bit.Core;
|
||||||
|
using Bit.Core.Abstractions;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
using Bit.Droid.Receivers;
|
||||||
|
using Bit.Droid.Utilities;
|
||||||
using ZXing.Net.Mobile.Android;
|
using ZXing.Net.Mobile.Android;
|
||||||
using Android.Util;
|
|
||||||
|
|
||||||
namespace Bit.Droid
|
namespace Bit.Droid
|
||||||
{
|
{
|
||||||
|
@ -120,6 +119,9 @@ namespace Bit.Droid
|
||||||
base.OnResume();
|
base.OnResume();
|
||||||
Xamarin.Essentials.Platform.OnResume();
|
Xamarin.Essentials.Platform.OnResume();
|
||||||
AppearanceAdjustments();
|
AppearanceAdjustments();
|
||||||
|
|
||||||
|
ThemeManager.UpdateThemeOnPagesAsync();
|
||||||
|
|
||||||
if (_deviceActionService.SupportsNfc())
|
if (_deviceActionService.SupportsNfc())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
|
@ -8,6 +8,7 @@ using Bit.Core;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using Xamarin.Forms.Xaml;
|
using Xamarin.Forms.Xaml;
|
||||||
|
@ -216,7 +217,8 @@ namespace Bit.App
|
||||||
|
|
||||||
private async void ResumedAsync()
|
private async void ResumedAsync()
|
||||||
{
|
{
|
||||||
UpdateTheme();
|
await UpdateThemeAsync();
|
||||||
|
|
||||||
await _vaultTimeoutService.CheckVaultTimeoutAsync();
|
await _vaultTimeoutService.CheckVaultTimeoutAsync();
|
||||||
_messagingService.Send("startEventTimer");
|
_messagingService.Send("startEventTimer");
|
||||||
await ClearCacheIfNeededAsync();
|
await ClearCacheIfNeededAsync();
|
||||||
|
@ -228,6 +230,15 @@ namespace Bit.App
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task UpdateThemeAsync()
|
||||||
|
{
|
||||||
|
await Device.InvokeOnMainThreadAsync(() =>
|
||||||
|
{
|
||||||
|
ThemeManager.SetTheme(Device.RuntimePlatform == Device.Android, Current.Resources);
|
||||||
|
_messagingService.Send("updatedTheme");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void SetCulture()
|
private void SetCulture()
|
||||||
{
|
{
|
||||||
// Calendars are removed by linker. ref https://bugzilla.xamarin.com/show_bug.cgi?id=59077
|
// Calendars are removed by linker. ref https://bugzilla.xamarin.com/show_bug.cgi?id=59077
|
||||||
|
@ -329,7 +340,7 @@ namespace Bit.App
|
||||||
ThemeManager.SetTheme(Device.RuntimePlatform == Device.Android, Current.Resources);
|
ThemeManager.SetTheme(Device.RuntimePlatform == Device.Android, Current.Resources);
|
||||||
Current.RequestedThemeChanged += (s, a) =>
|
Current.RequestedThemeChanged += (s, a) =>
|
||||||
{
|
{
|
||||||
UpdateTheme();
|
UpdateThemeAsync();
|
||||||
};
|
};
|
||||||
Current.MainPage = new HomePage();
|
Current.MainPage = new HomePage();
|
||||||
var mainPageTask = SetMainPageAsync();
|
var mainPageTask = SetMainPageAsync();
|
||||||
|
@ -353,15 +364,6 @@ namespace Bit.App
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateTheme()
|
|
||||||
{
|
|
||||||
Device.BeginInvokeOnMainThread(() =>
|
|
||||||
{
|
|
||||||
ThemeManager.SetTheme(Device.RuntimePlatform == Device.Android, Current.Resources);
|
|
||||||
_messagingService.Send("updatedTheme");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task LockedAsync(bool autoPromptBiometric)
|
private async Task LockedAsync(bool autoPromptBiometric)
|
||||||
{
|
{
|
||||||
await _stateService.PurgeAsync();
|
await _stateService.PurgeAsync();
|
||||||
|
|
|
@ -30,9 +30,17 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
public DateTime? LastPageAction { get; set; }
|
public DateTime? LastPageAction { get; set; }
|
||||||
|
|
||||||
|
public bool IsThemeDirty { get; set; }
|
||||||
|
|
||||||
protected override void OnAppearing()
|
protected override void OnAppearing()
|
||||||
{
|
{
|
||||||
base.OnAppearing();
|
base.OnAppearing();
|
||||||
|
|
||||||
|
if (IsThemeDirty)
|
||||||
|
{
|
||||||
|
UpdateOnThemeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
SaveActivity();
|
SaveActivity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,5 +131,11 @@ namespace Bit.App.Pages
|
||||||
SetServices();
|
SetServices();
|
||||||
_storageService.SaveAsync(Constants.LastActiveTimeKey, _deviceActionService.GetActiveTime());
|
_storageService.SaveAsync(Constants.LastActiveTimeKey, _deviceActionService.GetActiveTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual Task UpdateOnThemeChanged()
|
||||||
|
{
|
||||||
|
IsThemeDirty = false;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
using Bit.App.Resources;
|
using System;
|
||||||
using System;
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Resources;
|
||||||
|
using Bit.App.Styles;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public partial class GeneratorHistoryPage : BaseContentPage
|
public partial class GeneratorHistoryPage : BaseContentPage, IThemeDirtablePage
|
||||||
{
|
{
|
||||||
private GeneratorHistoryPageViewModel _vm;
|
private GeneratorHistoryPageViewModel _vm;
|
||||||
|
|
||||||
|
@ -28,6 +30,7 @@ namespace Bit.App.Pages
|
||||||
protected override async void OnAppearing()
|
protected override async void OnAppearing()
|
||||||
{
|
{
|
||||||
base.OnAppearing();
|
base.OnAppearing();
|
||||||
|
|
||||||
await LoadOnAppearedAsync(_mainLayout, true, async () => {
|
await LoadOnAppearedAsync(_mainLayout, true, async () => {
|
||||||
await _vm.InitAsync();
|
await _vm.InitAsync();
|
||||||
});
|
});
|
||||||
|
@ -59,5 +62,12 @@ namespace Bit.App.Pages
|
||||||
await _vm.ClearAsync();
|
await _vm.ClearAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override async Task UpdateOnThemeChanged()
|
||||||
|
{
|
||||||
|
await base.UpdateOnThemeChanged();
|
||||||
|
|
||||||
|
await _vm?.UpdateOnThemeChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
using Bit.App.Resources;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Resources;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Models.Domain;
|
using Bit.Core.Models.Domain;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using System.Collections.Generic;
|
#if !FDROID
|
||||||
using System.Threading.Tasks;
|
using Microsoft.AppCenter.Crashes;
|
||||||
|
#endif
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
|
@ -19,8 +22,7 @@ namespace Bit.App.Pages
|
||||||
public GeneratorHistoryPageViewModel()
|
public GeneratorHistoryPageViewModel()
|
||||||
{
|
{
|
||||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
||||||
_passwordGenerationService = ServiceContainer.Resolve<IPasswordGenerationService>(
|
_passwordGenerationService = ServiceContainer.Resolve<IPasswordGenerationService>("passwordGenerationService");
|
||||||
"passwordGenerationService");
|
|
||||||
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
|
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
|
||||||
|
|
||||||
PageTitle = AppResources.PasswordHistory;
|
PageTitle = AppResources.PasswordHistory;
|
||||||
|
@ -57,5 +59,21 @@ namespace Bit.App.Pages
|
||||||
_platformUtilsService.ShowToast("info", null,
|
_platformUtilsService.ShowToast("info", null,
|
||||||
string.Format(AppResources.ValueHasBeenCopied, AppResources.Password));
|
string.Format(AppResources.ValueHasBeenCopied, AppResources.Password));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task UpdateOnThemeChanged()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Device.InvokeOnMainThreadAsync(() => History.ResetWithRange(new List<GeneratedPasswordHistory>()));
|
||||||
|
|
||||||
|
await InitAsync();
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
#if !FDROID
|
||||||
|
Crashes.TrackError(ex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,7 @@
|
||||||
</Frame>
|
</Frame>
|
||||||
</Grid>
|
</Grid>
|
||||||
<controls:MonoLabel
|
<controls:MonoLabel
|
||||||
|
x:Name="lblPassword"
|
||||||
StyleClass="text-lg, text-html"
|
StyleClass="text-lg, text-html"
|
||||||
Text="{Binding ColoredPassword, Mode=OneWay}"
|
Text="{Binding ColoredPassword, Mode=OneWay}"
|
||||||
Margin="0, 20"
|
Margin="0, 20"
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
using Bit.App.Resources;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Resources;
|
||||||
|
using Bit.App.Styles;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using Xamarin.Forms.PlatformConfiguration;
|
|
||||||
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
|
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public partial class GeneratorPage : BaseContentPage
|
public partial class GeneratorPage : BaseContentPage, IThemeDirtablePage
|
||||||
{
|
{
|
||||||
private readonly IBroadcasterService _broadcasterService;
|
private readonly IBroadcasterService _broadcasterService;
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
if (isIos)
|
if (isIos)
|
||||||
{
|
{
|
||||||
_typePicker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);
|
_typePicker.On<Xamarin.Forms.PlatformConfiguration.iOS>().SetUpdateMode(UpdateMode.WhenFinished);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,18 +61,19 @@ namespace Bit.App.Pages
|
||||||
protected async override void OnAppearing()
|
protected async override void OnAppearing()
|
||||||
{
|
{
|
||||||
base.OnAppearing();
|
base.OnAppearing();
|
||||||
|
|
||||||
|
lblPassword.IsVisible = true;
|
||||||
|
|
||||||
if (!_fromTabPage)
|
if (!_fromTabPage)
|
||||||
{
|
{
|
||||||
await InitAsync();
|
await InitAsync();
|
||||||
}
|
}
|
||||||
_broadcasterService.Subscribe(nameof(GeneratorPage), async (message) =>
|
|
||||||
|
_broadcasterService.Subscribe(nameof(GeneratorPage), (message) =>
|
||||||
{
|
{
|
||||||
if (message.Command == "updatedTheme")
|
if (message.Command == "updatedTheme")
|
||||||
{
|
{
|
||||||
Device.BeginInvokeOnMainThread(() =>
|
Device.BeginInvokeOnMainThread(() => _vm.RedrawPassword());
|
||||||
{
|
|
||||||
_vm.RedrawPassword();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -80,6 +81,9 @@ namespace Bit.App.Pages
|
||||||
protected override void OnDisappearing()
|
protected override void OnDisappearing()
|
||||||
{
|
{
|
||||||
base.OnDisappearing();
|
base.OnDisappearing();
|
||||||
|
|
||||||
|
lblPassword.IsVisible = false;
|
||||||
|
|
||||||
_broadcasterService.Unsubscribe(nameof(GeneratorPage));
|
_broadcasterService.Unsubscribe(nameof(GeneratorPage));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,5 +145,12 @@ namespace Bit.App.Pages
|
||||||
await Navigation.PopModalAsync();
|
await Navigation.PopModalAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override async Task UpdateOnThemeChanged()
|
||||||
|
{
|
||||||
|
await base.UpdateOnThemeChanged();
|
||||||
|
|
||||||
|
await Device.InvokeOnMainThreadAsync(() => _vm?.RedrawPassword());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace Bit.App.Styles
|
namespace Bit.App.Styles
|
||||||
{
|
{
|
||||||
public partial class Black : ResourceDictionary
|
public partial class Black : ResourceDictionary, IThemeResourceDictionary
|
||||||
{
|
{
|
||||||
public Black()
|
public Black()
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace Bit.App.Styles
|
namespace Bit.App.Styles
|
||||||
{
|
{
|
||||||
public partial class Dark : ResourceDictionary
|
public partial class Dark : ResourceDictionary, IThemeResourceDictionary
|
||||||
{
|
{
|
||||||
public Dark()
|
public Dark()
|
||||||
{
|
{
|
||||||
|
|
15
src/App/Styles/IThemeDirtablePage.cs
Normal file
15
src/App/Styles/IThemeDirtablePage.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Bit.App.Styles
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This is an interface to mark the pages that need theme update special treatment
|
||||||
|
/// given that they aren't updated automatically by the Forms theme system.
|
||||||
|
/// </summary>
|
||||||
|
public interface IThemeDirtablePage
|
||||||
|
{
|
||||||
|
bool IsThemeDirty { get; set; }
|
||||||
|
|
||||||
|
Task UpdateOnThemeChanged();
|
||||||
|
}
|
||||||
|
}
|
6
src/App/Styles/IThemeResourceDictionary.cs
Normal file
6
src/App/Styles/IThemeResourceDictionary.cs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
namespace Bit.App.Styles
|
||||||
|
{
|
||||||
|
public interface IThemeResourceDictionary
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace Bit.App.Styles
|
namespace Bit.App.Styles
|
||||||
{
|
{
|
||||||
public partial class Light : ResourceDictionary
|
public partial class Light : ResourceDictionary, IThemeResourceDictionary
|
||||||
{
|
{
|
||||||
public Light()
|
public Light()
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace Bit.App.Styles
|
namespace Bit.App.Styles
|
||||||
{
|
{
|
||||||
public partial class Nord : ResourceDictionary
|
public partial class Nord : ResourceDictionary, IThemeResourceDictionary
|
||||||
{
|
{
|
||||||
public Nord()
|
public Nord()
|
||||||
{
|
{
|
||||||
|
|
53
src/App/Utilities/PageExtensions.cs
Normal file
53
src/App/Utilities/PageExtensions.cs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
|
||||||
|
namespace Bit.App.Utilities
|
||||||
|
{
|
||||||
|
public static class PageExtensions
|
||||||
|
{
|
||||||
|
public static async Task TraverseNavigationRecursivelyAsync(this Page page, Func<Page, Task> actionOnPage)
|
||||||
|
{
|
||||||
|
if (page?.Navigation?.ModalStack != null)
|
||||||
|
{
|
||||||
|
foreach (var p in page.Navigation.ModalStack)
|
||||||
|
{
|
||||||
|
if (p is NavigationPage modalNavPage)
|
||||||
|
{
|
||||||
|
await TraverseNavigationStackRecursivelyAsync(modalNavPage.CurrentPage, actionOnPage);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await TraverseNavigationStackRecursivelyAsync(p, actionOnPage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await TraverseNavigationStackRecursivelyAsync(page, actionOnPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task TraverseNavigationStackRecursivelyAsync(this Page page, Func<Page, Task> actionOnPage)
|
||||||
|
{
|
||||||
|
if (page is MultiPage<Page> multiPage && multiPage.Children != null)
|
||||||
|
{
|
||||||
|
foreach (var p in multiPage.Children)
|
||||||
|
{
|
||||||
|
await TraverseNavigationStackRecursivelyAsync(p, actionOnPage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (page is NavigationPage && page.Navigation != null)
|
||||||
|
{
|
||||||
|
if (page.Navigation.NavigationStack != null)
|
||||||
|
{
|
||||||
|
foreach (var p in page.Navigation.NavigationStack)
|
||||||
|
{
|
||||||
|
await TraverseNavigationStackRecursivelyAsync(p, actionOnPage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await actionOnPage(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,8 @@ using Bit.App.Services;
|
||||||
using Bit.App.Styles;
|
using Bit.App.Styles;
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
#if !FDROID
|
#if !FDROID
|
||||||
using Microsoft.AppCenter.Crashes;
|
using Microsoft.AppCenter.Crashes;
|
||||||
#endif
|
#endif
|
||||||
|
@ -15,12 +17,30 @@ namespace Bit.App.Utilities
|
||||||
public static bool UsingLightTheme = true;
|
public static bool UsingLightTheme = true;
|
||||||
public static Func<ResourceDictionary> Resources = () => null;
|
public static Func<ResourceDictionary> Resources = () => null;
|
||||||
|
|
||||||
|
public static bool IsThemeDirty = false;
|
||||||
|
|
||||||
public static void SetThemeStyle(string name, ResourceDictionary resources)
|
public static void SetThemeStyle(string name, ResourceDictionary resources)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Resources = () => resources;
|
Resources = () => resources;
|
||||||
|
|
||||||
|
var newTheme = NeedsThemeUpdate(name, resources);
|
||||||
|
if (newTheme is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentTheme = resources.MergedDictionaries.FirstOrDefault(md => md is IThemeResourceDictionary);
|
||||||
|
if (currentTheme != null)
|
||||||
|
{
|
||||||
|
resources.MergedDictionaries.Remove(currentTheme);
|
||||||
|
resources.MergedDictionaries.Add(newTheme);
|
||||||
|
UsingLightTheme = newTheme is Light;
|
||||||
|
IsThemeDirty = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Reset styles
|
// Reset styles
|
||||||
resources.Clear();
|
resources.Clear();
|
||||||
resources.MergedDictionaries.Clear();
|
resources.MergedDictionaries.Clear();
|
||||||
|
@ -28,40 +48,9 @@ namespace Bit.App.Utilities
|
||||||
// Variables
|
// Variables
|
||||||
resources.MergedDictionaries.Add(new Variables());
|
resources.MergedDictionaries.Add(new Variables());
|
||||||
|
|
||||||
// Themed variables
|
// Theme
|
||||||
if (name == "dark")
|
resources.MergedDictionaries.Add(newTheme);
|
||||||
{
|
UsingLightTheme = newTheme is Light;
|
||||||
resources.MergedDictionaries.Add(new Dark());
|
|
||||||
UsingLightTheme = false;
|
|
||||||
}
|
|
||||||
else if (name == "black")
|
|
||||||
{
|
|
||||||
resources.MergedDictionaries.Add(new Black());
|
|
||||||
UsingLightTheme = false;
|
|
||||||
}
|
|
||||||
else if (name == "nord")
|
|
||||||
{
|
|
||||||
resources.MergedDictionaries.Add(new Nord());
|
|
||||||
UsingLightTheme = false;
|
|
||||||
}
|
|
||||||
else if (name == "light")
|
|
||||||
{
|
|
||||||
resources.MergedDictionaries.Add(new Light());
|
|
||||||
UsingLightTheme = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (OsDarkModeEnabled())
|
|
||||||
{
|
|
||||||
resources.MergedDictionaries.Add(new Dark());
|
|
||||||
UsingLightTheme = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
resources.MergedDictionaries.Add(new Light());
|
|
||||||
UsingLightTheme = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Base styles
|
// Base styles
|
||||||
resources.MergedDictionaries.Add(new Base());
|
resources.MergedDictionaries.Add(new Base());
|
||||||
|
@ -93,6 +82,34 @@ namespace Bit.App.Utilities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ResourceDictionary CheckAndGetThemeForMergedDictionaries(Type themeType, ResourceDictionary resources)
|
||||||
|
{
|
||||||
|
return resources.MergedDictionaries.Any(rd => rd.GetType() == themeType)
|
||||||
|
? null
|
||||||
|
: Activator.CreateInstance(themeType) as ResourceDictionary;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ResourceDictionary NeedsThemeUpdate(string themeName, ResourceDictionary resources)
|
||||||
|
{
|
||||||
|
switch (themeName)
|
||||||
|
{
|
||||||
|
case "dark":
|
||||||
|
return CheckAndGetThemeForMergedDictionaries(typeof(Dark), resources);
|
||||||
|
case "black":
|
||||||
|
return CheckAndGetThemeForMergedDictionaries(typeof(Black), resources);
|
||||||
|
case "nord":
|
||||||
|
return CheckAndGetThemeForMergedDictionaries(typeof(Nord), resources);
|
||||||
|
case "light":
|
||||||
|
return CheckAndGetThemeForMergedDictionaries(typeof(Light), resources);
|
||||||
|
default:
|
||||||
|
if (OsDarkModeEnabled())
|
||||||
|
{
|
||||||
|
return CheckAndGetThemeForMergedDictionaries(typeof(Dark), resources);
|
||||||
|
}
|
||||||
|
return CheckAndGetThemeForMergedDictionaries(typeof(Light), resources);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void SetTheme(bool android, ResourceDictionary resources)
|
public static void SetTheme(bool android, ResourceDictionary resources)
|
||||||
{
|
{
|
||||||
SetThemeStyle(GetTheme(android), resources);
|
SetThemeStyle(GetTheme(android), resources);
|
||||||
|
@ -128,5 +145,34 @@ namespace Bit.App.Utilities
|
||||||
{
|
{
|
||||||
return (Color)Resources()[color];
|
return (Color)Resources()[color];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task UpdateThemeOnPagesAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (IsThemeDirty)
|
||||||
|
{
|
||||||
|
IsThemeDirty = false;
|
||||||
|
|
||||||
|
await Application.Current.MainPage.TraverseNavigationRecursivelyAsync(async p =>
|
||||||
|
{
|
||||||
|
if (p is IThemeDirtablePage themeDirtablePage)
|
||||||
|
{
|
||||||
|
themeDirtablePage.IsThemeDirty = true;
|
||||||
|
if (p.IsVisible)
|
||||||
|
{
|
||||||
|
await themeDirtablePage.UpdateOnThemeChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
#if !FDROID
|
||||||
|
Crashes.TrackError(ex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,6 +216,8 @@ namespace Bit.iOS
|
||||||
view.RemoveFromSuperview();
|
view.RemoveFromSuperview();
|
||||||
UIApplication.SharedApplication.SetStatusBarHidden(false, false);
|
UIApplication.SharedApplication.SetStatusBarHidden(false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ThemeManager.UpdateThemeOnPagesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void WillEnterForeground(UIApplication uiApplication)
|
public override void WillEnterForeground(UIApplication uiApplication)
|
||||||
|
|
Loading…
Reference in a new issue