diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 9ed865b66..b233d9af9 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -330,7 +330,7 @@ jobs:
ios:
name: Apple iOS
- runs-on: macos-10.15
+ runs-on: macos-11
steps:
- name: Print environment
run: |
diff --git a/src/Android/Accessibility/AccessibilityActivity.cs b/src/Android/Accessibility/AccessibilityActivity.cs
index f0e8d0e15..2be39b24f 100644
--- a/src/Android/Accessibility/AccessibilityActivity.cs
+++ b/src/Android/Accessibility/AccessibilityActivity.cs
@@ -9,7 +9,7 @@ using Bit.Core.Utilities;
namespace Bit.Droid.Accessibility
{
- [Activity(Theme = "@style/LightTheme.Splash", WindowSoftInputMode = SoftInput.StateHidden)]
+ [Activity(Theme = "@style/BaseTheme", WindowSoftInputMode = SoftInput.StateHidden)]
public class AccessibilityActivity : Activity
{
private DateTime? _lastLaunch = null;
diff --git a/src/Android/Android.csproj b/src/Android/Android.csproj
index de1b03b29..3ba99a4d4 100644
--- a/src/Android/Android.csproj
+++ b/src/Android/Android.csproj
@@ -76,11 +76,11 @@
1.8.10
-
-
-
-
-
+
+
+
+
+
1.7.0
@@ -88,7 +88,7 @@
122.0.0
-
+
117.0.1
@@ -122,6 +122,8 @@
+
+
@@ -144,6 +146,7 @@
+
@@ -171,8 +174,6 @@
-
-
@@ -185,6 +186,7 @@
+
diff --git a/src/Android/Effects/FabShadowEffect.cs b/src/Android/Effects/FabShadowEffect.cs
index 11bda2e4f..9901a51ba 100644
--- a/src/Android/Effects/FabShadowEffect.cs
+++ b/src/Android/Effects/FabShadowEffect.cs
@@ -1,6 +1,6 @@
using Android.Graphics.Drawables;
-using Bit.App.Utilities;
using Bit.Droid.Effects;
+using Bit.Droid.Utilities;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
@@ -14,7 +14,7 @@ namespace Bit.Droid.Effects
if (Control is Android.Widget.Button button)
{
var gd = new GradientDrawable();
- gd.SetColor(ThemeManager.GetResourceColor("FabColor").ToAndroid());
+ gd.SetColor(ThemeHelpers.FabColor);
gd.SetCornerRadius(100);
button.SetBackground(gd);
diff --git a/src/Android/MainActivity.cs b/src/Android/MainActivity.cs
index 3208295f4..7d2023606 100644
--- a/src/Android/MainActivity.cs
+++ b/src/Android/MainActivity.cs
@@ -15,9 +15,9 @@ using Bit.Droid.Receivers;
using Bit.App.Models;
using Bit.Core.Enums;
using Android.Nfc;
-using Bit.App.Utilities;
using System.Threading.Tasks;
using AndroidX.Core.Content;
+using Bit.App.Utilities;
using ZXing.Net.Mobile.Android;
namespace Bit.Droid
@@ -30,7 +30,7 @@ namespace Bit.Droid
LaunchMode = LaunchMode.SingleTask,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation |
ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden |
- ConfigChanges.Navigation)]
+ ConfigChanges.Navigation | ConfigChanges.UiMode)]
[IntentFilter(
new[] { Intent.ActionSend },
Categories = new[] { Intent.CategoryDefault },
@@ -81,7 +81,6 @@ namespace Bit.Droid
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
- UpdateTheme(ThemeManager.GetTheme(true));
base.OnCreate(savedInstanceState);
if (!CoreHelpers.InDebugMode())
{
@@ -118,7 +117,7 @@ namespace Bit.Droid
}
else if (message.Command == "updatedTheme")
{
- RestartApp();
+ Xamarin.Forms.Device.BeginInvokeOnMainThread(() => AppearanceAdjustments());
}
else if (message.Command == "exit")
{
@@ -141,6 +140,7 @@ namespace Bit.Droid
{
base.OnResume();
Xamarin.Essentials.Platform.OnResume();
+ AppearanceAdjustments();
if (_deviceActionService.SupportsNfc())
{
try
@@ -382,45 +382,10 @@ namespace Bit.Droid
}
}
- private void UpdateTheme(string theme)
+ private void AppearanceAdjustments()
{
- if (theme == "light")
- {
- SetTheme(Resource.Style.LightTheme);
- }
- else if (theme == "dark")
- {
- SetTheme(Resource.Style.DarkTheme);
- }
- else if (theme == "black")
- {
- SetTheme(Resource.Style.BlackTheme);
- }
- else if (theme == "nord")
- {
- SetTheme(Resource.Style.NordTheme);
- }
- else
- {
- if (_deviceActionService.UsingDarkTheme())
- {
- SetTheme(Resource.Style.DarkTheme);
- }
- else
- {
- SetTheme(Resource.Style.LightTheme);
- }
- }
- }
-
- private void RestartApp()
- {
- var intent = new Intent(this, typeof(MainActivity));
- var pendingIntent = PendingIntent.GetActivity(this, 5923650, intent, PendingIntentFlags.CancelCurrent);
- var alarmManager = GetSystemService(AlarmService) as AlarmManager;
- var triggerMs = Java.Lang.JavaSystem.CurrentTimeMillis() + 500;
- alarmManager.Set(AlarmType.Rtc, triggerMs, pendingIntent);
- Java.Lang.JavaSystem.Exit(0);
+ Window?.SetStatusBarColor(ThemeHelpers.NavBarBackgroundColor);
+ ThemeHelpers.SetAppearance(ThemeManager.GetTheme(true), ThemeManager.OsDarkModeEnabled());
}
private void ExitApp()
diff --git a/src/Android/Renderers/CustomEditorRenderer.cs b/src/Android/Renderers/CustomEditorRenderer.cs
index edadb4c54..035c2f3eb 100644
--- a/src/Android/Renderers/CustomEditorRenderer.cs
+++ b/src/Android/Renderers/CustomEditorRenderer.cs
@@ -1,6 +1,9 @@
-using Android.Content;
+using System.ComponentModel;
+using Android.Content;
+using Android.Content.Res;
using Android.Views.InputMethods;
using Bit.Droid.Renderers;
+using Bit.Droid.Utilities;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
@@ -25,6 +28,7 @@ namespace Bit.Droid.Renderers
protected override void OnElementChanged(ElementChangedEventArgs e)
{
base.OnElementChanged(e);
+ UpdateBorderColor();
if (Control != null && e.NewElement != null)
{
Control.SetPadding(Control.PaddingLeft, Control.PaddingTop - 10, Control.PaddingRight,
@@ -33,5 +37,33 @@ namespace Bit.Droid.Renderers
(ImeAction)ImeFlags.NoExtractUi;
}
}
+
+ protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ base.OnElementPropertyChanged(sender, e);
+
+ if (e.PropertyName == Entry.TextColorProperty.PropertyName)
+ {
+ UpdateBorderColor();
+ }
+ }
+
+ private void UpdateBorderColor()
+ {
+ if (Control != null)
+ {
+ var states = new[]
+ {
+ new[] { Android.Resource.Attribute.StateFocused }, // focused
+ new[] { -Android.Resource.Attribute.StateFocused }, // unfocused
+ };
+ var colors = new int[]
+ {
+ ThemeHelpers.PrimaryColor,
+ ThemeHelpers.MutedColor
+ };
+ Control.BackgroundTintList = new ColorStateList(states, colors);
+ }
+ }
}
}
diff --git a/src/Android/Renderers/CustomEntryRenderer.cs b/src/Android/Renderers/CustomEntryRenderer.cs
index 219b5aa17..fd17aa108 100644
--- a/src/Android/Renderers/CustomEntryRenderer.cs
+++ b/src/Android/Renderers/CustomEntryRenderer.cs
@@ -1,10 +1,12 @@
using System.ComponentModel;
using Android.Content;
+using Android.Content.Res;
using Android.Graphics;
using Android.Text;
using Android.Views.InputMethods;
using Android.Widget;
using Bit.Droid.Renderers;
+using Bit.Droid.Utilities;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
@@ -20,6 +22,7 @@ namespace Bit.Droid.Renderers
protected override void OnElementChanged(ElementChangedEventArgs e)
{
base.OnElementChanged(e);
+ UpdateBorderColor();
if (Control != null && e.NewElement != null)
{
Control.SetPadding(Control.PaddingLeft, Control.PaddingTop - 10, Control.PaddingRight,
@@ -68,6 +71,28 @@ namespace Bit.Droid.Renderers
}
}
}
+ else if (e.PropertyName == Entry.TextColorProperty.PropertyName)
+ {
+ UpdateBorderColor();
+ }
+ }
+
+ private void UpdateBorderColor()
+ {
+ if (Control != null)
+ {
+ var states = new[]
+ {
+ new[] { Android.Resource.Attribute.StateFocused }, // focused
+ new[] { -Android.Resource.Attribute.StateFocused }, // unfocused
+ };
+ var colors = new int[]
+ {
+ ThemeHelpers.PrimaryColor,
+ ThemeHelpers.MutedColor
+ };
+ Control.BackgroundTintList = new ColorStateList(states, colors);
+ }
}
}
}
diff --git a/src/Android/Renderers/CustomPickerRenderer.cs b/src/Android/Renderers/CustomPickerRenderer.cs
index 2327072d4..ba0d60fe2 100644
--- a/src/Android/Renderers/CustomPickerRenderer.cs
+++ b/src/Android/Renderers/CustomPickerRenderer.cs
@@ -1,5 +1,8 @@
-using Android.Content;
+using System.ComponentModel;
+using Android.Content;
+using Android.Content.Res;
using Bit.Droid.Renderers;
+using Bit.Droid.Utilities;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
@@ -15,11 +18,40 @@ namespace Bit.Droid.Renderers
protected override void OnElementChanged(ElementChangedEventArgs e)
{
base.OnElementChanged(e);
+ UpdateBorderColor();
if (Control != null && e.NewElement != null)
{
Control.SetPadding(Control.PaddingLeft, Control.PaddingTop - 10, Control.PaddingRight,
Control.PaddingBottom + 20);
}
}
+
+ protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ base.OnElementPropertyChanged(sender, e);
+
+ if (e.PropertyName == Picker.TextColorProperty.PropertyName)
+ {
+ UpdateBorderColor();
+ }
+ }
+
+ private void UpdateBorderColor()
+ {
+ if (Control != null)
+ {
+ var states = new[]
+ {
+ new[] { Android.Resource.Attribute.StateFocused }, // focused
+ new[] { -Android.Resource.Attribute.StateFocused }, // unfocused
+ };
+ var colors = new int[]
+ {
+ ThemeHelpers.PrimaryColor,
+ ThemeHelpers.MutedColor
+ };
+ Control.BackgroundTintList = new ColorStateList(states, colors);
+ }
+ }
}
}
diff --git a/src/Android/Renderers/CustomSwitchRenderer.cs b/src/Android/Renderers/CustomSwitchRenderer.cs
new file mode 100644
index 000000000..121f152ca
--- /dev/null
+++ b/src/Android/Renderers/CustomSwitchRenderer.cs
@@ -0,0 +1,59 @@
+using System.ComponentModel;
+using Android.Content;
+using Android.Content.Res;
+using Android.Graphics.Drawables;
+using AndroidX.Core.Content.Resources;
+using Bit.Droid.Renderers;
+using Bit.Droid.Utilities;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Android;
+
+[assembly: ExportRenderer(typeof(Switch), typeof(CustomSwitchRenderer))]
+namespace Bit.Droid.Renderers
+{
+ public class CustomSwitchRenderer : SwitchRenderer
+ {
+ public CustomSwitchRenderer(Context context)
+ : base(context)
+ {}
+
+ protected override void OnElementChanged(ElementChangedEventArgs e)
+ {
+ base.OnElementChanged(e);
+ UpdateColors();
+ }
+
+ protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ base.OnElementPropertyChanged(sender, e);
+
+ if (e.PropertyName == Switch.OnColorProperty.PropertyName)
+ {
+ UpdateColors();
+ }
+ }
+
+ private void UpdateColors()
+ {
+ if (Control != null)
+ {
+ var t = ResourcesCompat.GetDrawable(Resources, Resource.Drawable.switch_thumb, null);
+ if (t is GradientDrawable thumb)
+ {
+ Control.ThumbDrawable = thumb;
+ }
+ var thumbStates = new[]
+ {
+ new[] { Android.Resource.Attribute.StateChecked }, // checked
+ new[] { -Android.Resource.Attribute.StateChecked }, // unchecked
+ };
+ var thumbColors = new int[]
+ {
+ ThemeHelpers.SwitchOnColor,
+ ThemeHelpers.SwitchThumbColor
+ };
+ Control.ThumbTintList = new ColorStateList(thumbStates, thumbColors);
+ }
+ }
+ }
+}
diff --git a/src/Android/Renderers/ExtendedGridRenderer.cs b/src/Android/Renderers/ExtendedGridRenderer.cs
index 050e0f011..a46cbca52 100644
--- a/src/Android/Renderers/ExtendedGridRenderer.cs
+++ b/src/Android/Renderers/ExtendedGridRenderer.cs
@@ -1,6 +1,5 @@
using Android.Content;
using Bit.App.Controls;
-using Bit.App.Utilities;
using Bit.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
@@ -10,8 +9,6 @@ namespace Bit.Droid.Renderers
{
public class ExtendedGridRenderer : ViewRenderer
{
- private static int? _bgResId;
-
public ExtendedGridRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs elementChangedEvent)
@@ -19,25 +16,8 @@ namespace Bit.Droid.Renderers
base.OnElementChanged(elementChangedEvent);
if (elementChangedEvent.NewElement != null)
{
- SetBackgroundResource(GetBgResId());
+ SetBackgroundResource(Resource.Drawable.list_item_bg);
}
}
-
- private int GetBgResId()
- {
- if (_bgResId == null)
- {
- if (ThemeManager.GetTheme(true) == "nord")
- {
- _bgResId = Resource.Drawable.list_item_bg_nord;
- }
- else
- {
- _bgResId ??= ThemeManager.UsingLightTheme ? Resource.Drawable.list_item_bg :
- Resource.Drawable.list_item_bg_dark;
- }
- }
- return _bgResId.Value;
- }
}
}
diff --git a/src/Android/Renderers/ExtendedSliderRenderer.cs b/src/Android/Renderers/ExtendedSliderRenderer.cs
index aee0ffc63..0ff6fa9f3 100644
--- a/src/Android/Renderers/ExtendedSliderRenderer.cs
+++ b/src/Android/Renderers/ExtendedSliderRenderer.cs
@@ -1,4 +1,5 @@
-using Android.Content;
+using System.ComponentModel;
+using Android.Content;
using Android.Graphics.Drawables;
using AndroidX.Core.Content.Resources;
using Bit.App.Controls;
@@ -18,6 +19,21 @@ namespace Bit.Droid.Renderers
protected override void OnElementChanged(ElementChangedEventArgs e)
{
base.OnElementChanged(e);
+ UpdateColor();
+ }
+
+ protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ base.OnElementPropertyChanged(sender, e);
+
+ if (e.PropertyName == ExtendedSlider.ThumbBorderColorProperty.PropertyName)
+ {
+ UpdateColor();
+ }
+ }
+
+ private void UpdateColor()
+ {
if (Control != null && Element is ExtendedSlider view)
{
var t = ResourcesCompat.GetDrawable(Resources, Resource.Drawable.slider_thumb, null);
diff --git a/src/Android/Renderers/ExtendedStackLayoutRenderer.cs b/src/Android/Renderers/ExtendedStackLayoutRenderer.cs
index 7242ef825..d28668a4a 100644
--- a/src/Android/Renderers/ExtendedStackLayoutRenderer.cs
+++ b/src/Android/Renderers/ExtendedStackLayoutRenderer.cs
@@ -1,6 +1,5 @@
using Android.Content;
using Bit.App.Controls;
-using Bit.App.Utilities;
using Bit.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
@@ -10,8 +9,6 @@ namespace Bit.Droid.Renderers
{
public class ExtendedStackLayoutRenderer : ViewRenderer
{
- private static int? _bgResId;
-
public ExtendedStackLayoutRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs elementChangedEvent)
@@ -19,25 +16,8 @@ namespace Bit.Droid.Renderers
base.OnElementChanged(elementChangedEvent);
if (elementChangedEvent.NewElement != null)
{
- SetBackgroundResource(GetBgResId());
+ SetBackgroundResource(Resource.Drawable.list_item_bg);
}
}
-
- private int GetBgResId()
- {
- if (_bgResId == null)
- {
- if (ThemeManager.GetTheme(true) == "nord")
- {
- _bgResId = Resource.Drawable.list_item_bg_nord;
- }
- else
- {
- _bgResId ??= ThemeManager.UsingLightTheme ? Resource.Drawable.list_item_bg :
- Resource.Drawable.list_item_bg_dark;
- }
- }
- return _bgResId.Value;
- }
}
}
diff --git a/src/Android/Renderers/ExtendedStepperRenderer.cs b/src/Android/Renderers/ExtendedStepperRenderer.cs
new file mode 100644
index 000000000..656eb46b9
--- /dev/null
+++ b/src/Android/Renderers/ExtendedStepperRenderer.cs
@@ -0,0 +1,72 @@
+using System.ComponentModel;
+using Android.Content;
+using Android.Graphics;
+using Android.OS;
+using Bit.App.Controls;
+using Bit.Droid.Renderers;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Android;
+
+[assembly: ExportRenderer(typeof(ExtendedStepper), typeof(ExtendedStepperRenderer))]
+namespace Bit.Droid.Renderers
+{
+ public class ExtendedStepperRenderer : StepperRenderer
+ {
+ public ExtendedStepperRenderer(Context context)
+ : base(context)
+ {}
+
+ protected override void OnElementChanged(ElementChangedEventArgs e)
+ {
+ base.OnElementChanged(e);
+ UpdateBgColor();
+ UpdateFgColor();
+ }
+
+ protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ base.OnElementPropertyChanged(sender, e);
+
+ if (e.PropertyName == ExtendedStepper.StepperBackgroundColorProperty.PropertyName)
+ {
+ UpdateBgColor();
+ }
+ else if (e.PropertyName == ExtendedStepper.StepperForegroundColorProperty.PropertyName)
+ {
+ UpdateFgColor();
+ }
+ }
+
+ private void UpdateBgColor()
+ {
+ if (Control != null && Element is ExtendedStepper view)
+ {
+ if (Build.VERSION.SdkInt >= BuildVersionCodes.Q)
+ {
+ Control.GetChildAt(0)?.Background?.SetColorFilter(
+ new BlendModeColorFilter(view.StepperBackgroundColor.ToAndroid(), BlendMode.Multiply));
+ Control.GetChildAt(1)?.Background?.SetColorFilter(
+ new BlendModeColorFilter(view.StepperBackgroundColor.ToAndroid(), BlendMode.Multiply));
+ }
+ else
+ {
+ Control.GetChildAt(0)?.Background?.SetColorFilter(
+ view.StepperBackgroundColor.ToAndroid(), PorterDuff.Mode.Multiply);
+ Control.GetChildAt(1)?.Background?.SetColorFilter(
+ view.StepperBackgroundColor.ToAndroid(), PorterDuff.Mode.Multiply);
+ }
+ }
+ }
+
+ private void UpdateFgColor()
+ {
+ if (Control != null && Element is ExtendedStepper view)
+ {
+ var btn0 = Control.GetChildAt(0) as Android.Widget.Button;
+ btn0?.SetTextColor(view.StepperForegroundColor.ToAndroid());
+ var btn1 = Control.GetChildAt(1) as Android.Widget.Button;
+ btn1?.SetTextColor(view.StepperForegroundColor.ToAndroid());
+ }
+ }
+ }
+}
diff --git a/src/Android/Resources/drawable-v23/splash_screen.xml b/src/Android/Resources/drawable-v23/splash_screen.xml
index 2b50133a9..fe987e71d 100644
--- a/src/Android/Resources/drawable-v23/splash_screen.xml
+++ b/src/Android/Resources/drawable-v23/splash_screen.xml
@@ -6,7 +6,7 @@ TODO: When API 23 becomes our new minimum, replace 'splash_screen.xml' in 'drawa
-->
-
-
+
-
+ android:color="#8E8E93">
-
-
-
-
\ No newline at end of file
diff --git a/src/Android/Resources/drawable/list_item_bg_nord.xml b/src/Android/Resources/drawable/list_item_bg_nord.xml
deleted file mode 100644
index d9e9f0c75..000000000
--- a/src/Android/Resources/drawable/list_item_bg_nord.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/src/Android/Resources/drawable/splash_screen.xml b/src/Android/Resources/drawable/splash_screen.xml
index aaf7619dc..56530dc15 100644
--- a/src/Android/Resources/drawable/splash_screen.xml
+++ b/src/Android/Resources/drawable/splash_screen.xml
@@ -1,7 +1,7 @@
-
-
+
-
diff --git a/src/Android/Resources/drawable/switch_thumb.xml b/src/Android/Resources/drawable/switch_thumb.xml
new file mode 100644
index 000000000..ea043d6bd
--- /dev/null
+++ b/src/Android/Resources/drawable/switch_thumb.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/Android/Resources/values-night/styles.xml b/src/Android/Resources/values-night/styles.xml
index 58dda976a..7e5a4074e 100644
--- a/src/Android/Resources/values-night/styles.xml
+++ b/src/Android/Resources/values-night/styles.xml
@@ -1,8 +1,26 @@
-
+
+
+
+
diff --git a/src/Android/Resources/values/colors.xml b/src/Android/Resources/values/colors.xml
index 5bbfa662c..a75733e20 100644
--- a/src/Android/Resources/values/colors.xml
+++ b/src/Android/Resources/values/colors.xml
@@ -1,38 +1,19 @@
-
+
#175DDC
#1A3B66
#175DDC
#1452BC
#dddddd
- #bbbbbb
-
+
#52bdfb
#191919
- #191919
+ #666666
#191919
-
- #282828
-
-
- #3b4252
- #e5e9f0
- #81a1c1
- #2e3440
- #e5e9f0
- #20242D
- #3b4252
- #2e3440
- #4c566a
- #e5e9f0
- #4c566a
- #20242D
-
- #FFFFFF
#FFFFFF
#000000
#333333
diff --git a/src/Android/Resources/values/styles.xml b/src/Android/Resources/values/styles.xml
index 07e4e2866..6b0b37f0b 100644
--- a/src/Android/Resources/values/styles.xml
+++ b/src/Android/Resources/values/styles.xml
@@ -1,21 +1,12 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/src/Android/Services/DeviceActionService.cs b/src/Android/Services/DeviceActionService.cs
index 45fd32f27..35202e7e4 100644
--- a/src/Android/Services/DeviceActionService.cs
+++ b/src/Android/Services/DeviceActionService.cs
@@ -8,7 +8,6 @@ using Android.App;
using Android.App.Assist;
using Android.Content;
using Android.Content.PM;
-using Android.Content.Res;
using Android.Nfc;
using Android.OS;
using Android.Provider;
@@ -641,18 +640,11 @@ namespace Bit.Droid.Services
public bool AutofillAccessibilityServiceRunning()
{
- try
- {
- var activity = (MainActivity)CrossCurrentActivity.Current.Activity;
- var manager = activity.GetSystemService(Context.ActivityService) as ActivityManager;
- var services = manager.GetRunningServices(int.MaxValue);
- return services.Any(s => s.Process.ToLowerInvariant().Contains("bitwarden") &&
- s.Service.ClassName.ToLowerInvariant().Contains("accessibilityservice"));
- }
- catch
- {
- return false;
- }
+ var activity = (MainActivity)CrossCurrentActivity.Current.Activity;
+ var enabledServices = Settings.Secure.GetString(activity.ContentResolver,
+ Settings.Secure.EnabledAccessibilityServices);
+ return Application.Context.PackageName != null &&
+ (enabledServices?.Contains(Application.Context.PackageName) ?? false);
}
public bool AutofillAccessibilityOverlayPermitted()
@@ -741,21 +733,6 @@ namespace Bit.Droid.Services
}
}
- public bool UsingDarkTheme()
- {
- try
- {
- if (Build.VERSION.SdkInt >= BuildVersionCodes.Q)
- {
- var app = CrossCurrentActivity.Current.AppContext;
- var uiModeFlags = app.Resources.Configuration.UiMode & UiMode.NightMask;
- return uiModeFlags == UiMode.NightYes;
- }
- }
- catch { }
- return false;
- }
-
public long GetActiveTime()
{
// Returns milliseconds since the system was booted, and includes deep sleep. This clock is guaranteed to
diff --git a/src/Android/Utilities/ThemeHelpers.cs b/src/Android/Utilities/ThemeHelpers.cs
new file mode 100644
index 000000000..3dfac9efa
--- /dev/null
+++ b/src/Android/Utilities/ThemeHelpers.cs
@@ -0,0 +1,67 @@
+using Android.Graphics;
+using Bit.App.Utilities;
+using Xamarin.Forms.Platform.Android;
+
+namespace Bit.Droid.Utilities
+{
+ public class ThemeHelpers
+ {
+ public static bool LightTheme = true;
+
+ public static Color PrimaryColor
+ {
+ get => ThemeManager.GetResourceColor("PrimaryColor").ToAndroid();
+ }
+ public static Color MutedColor
+ {
+ get => ThemeManager.GetResourceColor("MutedColor").ToAndroid();
+ }
+ public static Color NavBarBackgroundColor
+ {
+ get => ThemeManager.GetResourceColor("NavigationBarBackgroundColor").ToAndroid();
+ }
+ public static Color FabColor
+ {
+ get => ThemeManager.GetResourceColor("FabColor").ToAndroid();
+ }
+ public static Color SwitchOnColor
+ {
+ get => ThemeManager.GetResourceColor("SwitchOnColor").ToAndroid();
+ }
+ public static Color SwitchThumbColor
+ {
+ get => ThemeManager.GetResourceColor("SwitchThumbColor").ToAndroid();
+ }
+
+ public static void SetAppearance(string theme, bool osDarkModeEnabled)
+ {
+ SetThemeVariables(theme, osDarkModeEnabled);
+ }
+
+ public static int GetDialogTheme()
+ {
+ if (LightTheme)
+ {
+ return Android.Resource.Style.ThemeMaterialLightDialog;
+ }
+ return Android.Resource.Style.ThemeMaterialDialog;
+ }
+
+ private static void SetThemeVariables(string theme, bool osDarkModeEnabled)
+ {
+ if (string.IsNullOrWhiteSpace(theme) && osDarkModeEnabled)
+ {
+ theme = "dark";
+ }
+
+ if (theme == "dark" || theme == "black" || theme == "nord")
+ {
+ LightTheme = false;
+ }
+ else
+ {
+ LightTheme = true;
+ }
+ }
+ }
+}
diff --git a/src/App/Abstractions/IDeviceActionService.cs b/src/App/Abstractions/IDeviceActionService.cs
index 3c78759ba..e9d2b7dfb 100644
--- a/src/App/Abstractions/IDeviceActionService.cs
+++ b/src/App/Abstractions/IDeviceActionService.cs
@@ -42,7 +42,6 @@ namespace Bit.App.Abstractions
void OpenAccessibilitySettings();
void OpenAccessibilityOverlayPermissionSettings();
void OpenAutofillSettings();
- bool UsingDarkTheme();
long GetActiveTime();
void CloseMainApp();
bool SupportsFido2();
diff --git a/src/App/App.xaml.cs b/src/App/App.xaml.cs
index aff7401d7..f3b80e68f 100644
--- a/src/App/App.xaml.cs
+++ b/src/App/App.xaml.cs
@@ -200,6 +200,7 @@ namespace Bit.App
private async void ResumedAsync()
{
+ UpdateTheme();
await _vaultTimeoutService.CheckVaultTimeoutAsync();
_messagingService.Send("startEventTimer");
await ClearCacheIfNeededAsync();
@@ -337,6 +338,10 @@ namespace Bit.App
InitializeComponent();
SetCulture();
ThemeManager.SetTheme(Device.RuntimePlatform == Device.Android, Current.Resources);
+ Current.RequestedThemeChanged += (s, a) =>
+ {
+ UpdateTheme();
+ };
Current.MainPage = new HomePage();
var mainPageTask = SetMainPageAsync();
ServiceContainer.Resolve("platformUtilsService").Init();
@@ -359,6 +364,15 @@ 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)
{
await _stateService.PurgeAsync();
diff --git a/src/App/Controls/ExtendedSlider.cs b/src/App/Controls/ExtendedSlider.cs
index 00aa8fab8..7d673fab9 100644
--- a/src/App/Controls/ExtendedSlider.cs
+++ b/src/App/Controls/ExtendedSlider.cs
@@ -5,7 +5,7 @@ namespace Bit.App.Controls
public class ExtendedSlider : Slider
{
public static readonly BindableProperty ThumbBorderColorProperty = BindableProperty.Create(
- nameof(ThumbBorderColor), typeof(Color), typeof(ExtendedSlider), Color.Gray);
+ nameof(ThumbBorderColor), typeof(Color), typeof(ExtendedSlider), Color.Default);
public Color ThumbBorderColor
{
diff --git a/src/App/Controls/ExtendedStepper.cs b/src/App/Controls/ExtendedStepper.cs
new file mode 100644
index 000000000..68191ae20
--- /dev/null
+++ b/src/App/Controls/ExtendedStepper.cs
@@ -0,0 +1,25 @@
+using Xamarin.Forms;
+
+namespace Bit.App.Controls
+{
+ public class ExtendedStepper : Stepper
+ {
+ public static readonly BindableProperty StepperBackgroundColorProperty = BindableProperty.Create(
+ nameof(StepperBackgroundColor), typeof(Color), typeof(ExtendedStepper), Color.Default);
+
+ public static readonly BindableProperty StepperForegroundColorProperty = BindableProperty.Create(
+ nameof(StepperForegroundColor), typeof(Color), typeof(ExtendedStepper), Color.Default);
+
+ public Color StepperBackgroundColor
+ {
+ get => (Color)GetValue(StepperBackgroundColorProperty);
+ set => SetValue(StepperBackgroundColorProperty, value);
+ }
+
+ public Color StepperForegroundColor
+ {
+ get => (Color)GetValue(StepperForegroundColorProperty);
+ set => SetValue(StepperForegroundColorProperty, value);
+ }
+ }
+}
diff --git a/src/App/Pages/Accounts/HomePage.xaml b/src/App/Pages/Accounts/HomePage.xaml
index 62896ba2f..1040914ad 100644
--- a/src/App/Pages/Accounts/HomePage.xaml
+++ b/src/App/Pages/Accounts/HomePage.xaml
@@ -40,11 +40,12 @@
HorizontalTextAlignment="Center">
+ StyleClass="btn-primary"
+ Clicked="LogIn_Clicked" />
+ Clicked="Register_Clicked" />
+ Clicked="LogInSso_Clicked" />
diff --git a/src/App/Pages/Accounts/HomePage.xaml.cs b/src/App/Pages/Accounts/HomePage.xaml.cs
index 204f389a1..a51185d13 100644
--- a/src/App/Pages/Accounts/HomePage.xaml.cs
+++ b/src/App/Pages/Accounts/HomePage.xaml.cs
@@ -13,11 +13,13 @@ namespace Bit.App.Pages
private readonly HomeViewModel _vm;
private readonly AppOptions _appOptions;
private IMessagingService _messagingService;
+ private IBroadcasterService _broadcasterService;
public HomePage(AppOptions appOptions = null)
{
_messagingService = ServiceContainer.Resolve("messagingService");
_messagingService.Send("showStatusBar", false);
+ _broadcasterService = ServiceContainer.Resolve("broadcasterService");
_appOptions = appOptions;
InitializeComponent();
_vm = BindingContext as HomeViewModel;
@@ -26,7 +28,7 @@ namespace Bit.App.Pages
_vm.StartRegisterAction = () => Device.BeginInvokeOnMainThread(async () => await StartRegisterAsync());
_vm.StartSsoLoginAction = () => Device.BeginInvokeOnMainThread(async () => await StartSsoLoginAsync());
_vm.StartEnvironmentAction = () => Device.BeginInvokeOnMainThread(async () => await StartEnvironmentAsync());
- _logo.Source = !ThemeManager.UsingLightTheme ? "logo_white.png" : "logo.png";
+ UpdateLogo();
}
public async Task DismissRegisterPageAndLogInAsync(string email)
@@ -39,6 +41,27 @@ namespace Bit.App.Pages
{
base.OnAppearing();
_messagingService.Send("showStatusBar", false);
+ _broadcasterService.Subscribe(nameof(HomePage), async (message) =>
+ {
+ if (message.Command == "updatedTheme")
+ {
+ Device.BeginInvokeOnMainThread(() =>
+ {
+ UpdateLogo();
+ });
+ }
+ });
+ }
+
+ protected override void OnDisappearing()
+ {
+ base.OnDisappearing();
+ _broadcasterService.Unsubscribe(nameof(HomePage));
+ }
+
+ private void UpdateLogo()
+ {
+ _logo.Source = !ThemeManager.UsingLightTheme ? "logo_white.png" : "logo.png";
}
private void Close_Clicked(object sender, EventArgs e)
diff --git a/src/App/Pages/Accounts/LockPage.xaml b/src/App/Pages/Accounts/LockPage.xaml
index 5bb281f1f..22e5220f8 100644
--- a/src/App/Pages/Accounts/LockPage.xaml
+++ b/src/App/Pages/Accounts/LockPage.xaml
@@ -120,7 +120,9 @@
IsVisible="{Binding BiometricIntegrityValid, Converter={StaticResource inverseBool}}" />
-
+
diff --git a/src/App/Pages/Accounts/LoginPage.xaml b/src/App/Pages/Accounts/LoginPage.xaml
index 1363785ce..227c252cf 100644
--- a/src/App/Pages/Accounts/LoginPage.xaml
+++ b/src/App/Pages/Accounts/LoginPage.xaml
@@ -82,7 +82,9 @@
-
+
diff --git a/src/App/Pages/Accounts/LoginSsoPage.xaml b/src/App/Pages/Accounts/LoginSsoPage.xaml
index 1c54eb1ec..3c6fd941d 100644
--- a/src/App/Pages/Accounts/LoginSsoPage.xaml
+++ b/src/App/Pages/Accounts/LoginSsoPage.xaml
@@ -37,7 +37,8 @@
+ StyleClass="btn-primary"
+ Clicked="LogIn_Clicked">
diff --git a/src/App/Pages/BaseContentPage.cs b/src/App/Pages/BaseContentPage.cs
index 8919f8e1d..ce844e183 100644
--- a/src/App/Pages/BaseContentPage.cs
+++ b/src/App/Pages/BaseContentPage.cs
@@ -4,6 +4,7 @@ using Bit.Core.Utilities;
using System;
using System.Threading.Tasks;
using Bit.App.Abstractions;
+using Bit.App.Utilities;
using Xamarin.Forms;
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
@@ -52,7 +53,8 @@ namespace Bit.App.Pages
{
IsRunning = true,
VerticalOptions = LayoutOptions.CenterAndExpand,
- HorizontalOptions = LayoutOptions.Center
+ HorizontalOptions = LayoutOptions.Center,
+ Color = ThemeManager.GetResourceColor("PrimaryColor"),
};
if (targetView != null)
{
diff --git a/src/App/Pages/Generator/GeneratorPage.xaml b/src/App/Pages/Generator/GeneratorPage.xaml
index 6824140b3..cdc241044 100644
--- a/src/App/Pages/Generator/GeneratorPage.xaml
+++ b/src/App/Pages/Generator/GeneratorPage.xaml
@@ -71,6 +71,7 @@
HorizontalOptions="CenterAndExpand"
LineBreakMode="CharacterWrap" />
-
-
- _selectAction;
@@ -18,6 +22,7 @@ namespace Bit.App.Pages
{
_tabsPage = tabsPage;
InitializeComponent();
+ _broadcasterService = ServiceContainer.Resolve("broadcasterService");
_vm = BindingContext as GeneratorPageViewModel;
_vm.Page = this;
_fromTabPage = fromTabPage;
@@ -60,6 +65,22 @@ namespace Bit.App.Pages
{
await InitAsync();
}
+ _broadcasterService.Subscribe(nameof(GeneratorPage), async (message) =>
+ {
+ if (message.Command == "updatedTheme")
+ {
+ Device.BeginInvokeOnMainThread(() =>
+ {
+ _vm.RedrawPassword();
+ });
+ }
+ });
+ }
+
+ protected override void OnDisappearing()
+ {
+ base.OnDisappearing();
+ _broadcasterService.Unsubscribe(nameof(GeneratorPage));
}
protected override bool OnBackButtonPressed()
diff --git a/src/App/Pages/Generator/GeneratorPageViewModel.cs b/src/App/Pages/Generator/GeneratorPageViewModel.cs
index 770f905ed..fb9350bc5 100644
--- a/src/App/Pages/Generator/GeneratorPageViewModel.cs
+++ b/src/App/Pages/Generator/GeneratorPageViewModel.cs
@@ -262,6 +262,14 @@ namespace Bit.App.Pages
await _passwordGenerationService.AddHistoryAsync(Password);
}
+ public void RedrawPassword()
+ {
+ if (!string.IsNullOrEmpty(_password))
+ {
+ TriggerPropertyChanged(nameof(ColoredPassword));
+ }
+ }
+
public async Task SaveOptionsAsync(bool regenerate = true)
{
if (!_doneIniting)
diff --git a/src/App/Pages/Send/SendAddEditPage.xaml b/src/App/Pages/Send/SendAddEditPage.xaml
index 55bbb3a1c..dd9882ba3 100644
--- a/src/App/Pages/Send/SendAddEditPage.xaml
+++ b/src/App/Pages/Send/SendAddEditPage.xaml
@@ -54,26 +54,6 @@
x:Name="_deleteItem"
x:Key="deleteItem" />
-
-
-
-
@@ -131,51 +111,25 @@
@@ -289,20 +243,20 @@
Text="{u:I18n Options}"
x:Name="_btnOptions"
StyleClass="box-row-button"
- TextColor="{StaticResource PrimaryColor}"
+ TextColor="{DynamicResource PrimaryColor}"
Margin="0" />
@@ -421,7 +375,7 @@
MaxLength="9"
TextChanged="OnMaxAccessCountTextChanged"
HorizontalOptions="FillAndExpand" />
- SendOptionsCommand { get; set; }
public bool LoadedOnce { get; set; }
- public async Task InitAsync()
- {
- SendEnabled = ! await AppHelpers.IsSendDisabledByPolicyAsync();
- }
-
public async Task LoadAsync()
{
if (_doingLoad)
@@ -142,6 +137,7 @@ namespace Bit.App.Pages
ShowNoData = false;
Loading = true;
ShowList = false;
+ SendEnabled = ! await AppHelpers.IsSendDisabledByPolicyAsync();
var groupedSends = new List();
var page = Page as SendGroupingsPage;
diff --git a/src/App/Pages/Settings/AutofillServicesPage.xaml b/src/App/Pages/Settings/AutofillServicesPage.xaml
index 03dc7bb83..15f5c9b2a 100644
--- a/src/App/Pages/Settings/AutofillServicesPage.xaml
+++ b/src/App/Pages/Settings/AutofillServicesPage.xaml
@@ -29,7 +29,7 @@
HorizontalOptions="End" />