mirror of
https://github.com/bitwarden/android.git
synced 2024-12-24 18:08:26 +03:00
more device actions
This commit is contained in:
parent
9e51c46522
commit
0d417b3eee
6 changed files with 279 additions and 5 deletions
|
@ -1,10 +1,13 @@
|
||||||
using Bit.App.Abstractions;
|
using System.Threading.Tasks;
|
||||||
|
using Android.App;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
using Plugin.CurrentActivity;
|
using Plugin.CurrentActivity;
|
||||||
|
|
||||||
namespace Bit.Droid.Services
|
namespace Bit.Droid.Services
|
||||||
{
|
{
|
||||||
public class DeviceActionService : IDeviceActionService
|
public class DeviceActionService : IDeviceActionService
|
||||||
{
|
{
|
||||||
|
private ProgressDialog _progressDialog;
|
||||||
private Android.Widget.Toast _toast;
|
private Android.Widget.Toast _toast;
|
||||||
|
|
||||||
public void Toast(string text, bool longDuration = false)
|
public void Toast(string text, bool longDuration = false)
|
||||||
|
@ -31,5 +34,29 @@ namespace Bit.Droid.Services
|
||||||
}
|
}
|
||||||
return launchIntent != null;
|
return launchIntent != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task ShowLoadingAsync(string text)
|
||||||
|
{
|
||||||
|
if(_progressDialog != null)
|
||||||
|
{
|
||||||
|
await HideLoadingAsync();
|
||||||
|
}
|
||||||
|
var activity = (MainActivity)CrossCurrentActivity.Current.Activity;
|
||||||
|
_progressDialog = new ProgressDialog(activity);
|
||||||
|
_progressDialog.SetMessage(text);
|
||||||
|
_progressDialog.SetCancelable(false);
|
||||||
|
_progressDialog.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task HideLoadingAsync()
|
||||||
|
{
|
||||||
|
if(_progressDialog != null)
|
||||||
|
{
|
||||||
|
_progressDialog.Dismiss();
|
||||||
|
_progressDialog.Dispose();
|
||||||
|
_progressDialog = null;
|
||||||
|
}
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,8 +1,12 @@
|
||||||
namespace Bit.App.Abstractions
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Bit.App.Abstractions
|
||||||
{
|
{
|
||||||
public interface IDeviceActionService
|
public interface IDeviceActionService
|
||||||
{
|
{
|
||||||
void Toast(string text, bool longDuration = false);
|
void Toast(string text, bool longDuration = false);
|
||||||
bool LaunchApp(string appName);
|
bool LaunchApp(string appName);
|
||||||
|
Task ShowLoadingAsync(string text);
|
||||||
|
Task HideLoadingAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
143
src/iOS.Core/Views/Toast.cs
Normal file
143
src/iOS.Core/Views/Toast.cs
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
using Foundation;
|
||||||
|
using System;
|
||||||
|
using UIKit;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Core.Views
|
||||||
|
{
|
||||||
|
public class Toast : UIView
|
||||||
|
{
|
||||||
|
private NSTimer _dismissTimer;
|
||||||
|
private NSLayoutConstraint _heightConstraint;
|
||||||
|
private NSLayoutConstraint _leftMarginConstraint;
|
||||||
|
private NSLayoutConstraint _rightMarginConstraint;
|
||||||
|
private NSLayoutConstraint _bottomMarginConstraint;
|
||||||
|
|
||||||
|
public Toast(string text)
|
||||||
|
: base(CoreGraphics.CGRect.FromLTRB(0, 0, 320, 38))
|
||||||
|
{
|
||||||
|
TranslatesAutoresizingMaskIntoConstraints = false;
|
||||||
|
BackgroundColor = UIColor.DarkGray.ColorWithAlpha(0.9f);
|
||||||
|
Layer.CornerRadius = 15;
|
||||||
|
Layer.MasksToBounds = true;
|
||||||
|
|
||||||
|
MessageLabel = new UILabel
|
||||||
|
{
|
||||||
|
TranslatesAutoresizingMaskIntoConstraints = false,
|
||||||
|
TextColor = UIColor.White,
|
||||||
|
Font = UIFont.SystemFontOfSize(14),
|
||||||
|
BackgroundColor = UIColor.Clear,
|
||||||
|
LineBreakMode = UILineBreakMode.WordWrap,
|
||||||
|
TextAlignment = UITextAlignment.Center,
|
||||||
|
Lines = 0,
|
||||||
|
Text = text
|
||||||
|
};
|
||||||
|
|
||||||
|
AddSubview(MessageLabel);
|
||||||
|
|
||||||
|
var hMessageConstraints = NSLayoutConstraint.FromVisualFormat("H:|-5-[messageLabel]-5-|", 0, new NSDictionary(),
|
||||||
|
NSDictionary.FromObjectsAndKeys(new NSObject[] { MessageLabel },
|
||||||
|
new NSObject[] { new NSString("messageLabel") })
|
||||||
|
);
|
||||||
|
|
||||||
|
var vMessageConstraints = NSLayoutConstraint.FromVisualFormat("V:|-0-[messageLabel]-0-|", 0, new NSDictionary(),
|
||||||
|
NSDictionary.FromObjectsAndKeys(new NSObject[] { MessageLabel },
|
||||||
|
new NSObject[] { new NSString("messageLabel") })
|
||||||
|
);
|
||||||
|
|
||||||
|
AddConstraints(hMessageConstraints);
|
||||||
|
AddConstraints(vMessageConstraints);
|
||||||
|
|
||||||
|
AddGestureRecognizer(new UITapGestureRecognizer(() => Dismiss(false)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Dismissed { get; set; }
|
||||||
|
public Action DismissCallback { get; set; }
|
||||||
|
public TimeSpan Duration { get; set; } = TimeSpan.FromSeconds(3);
|
||||||
|
public UILabel MessageLabel { get; set; }
|
||||||
|
public nfloat LeftMargin { get; set; } = 5;
|
||||||
|
public nfloat RightMargin { get; set; } = 5;
|
||||||
|
public nfloat BottomMargin { get; set; } = 5;
|
||||||
|
public nfloat Height { get; set; } = 38;
|
||||||
|
|
||||||
|
public void Show()
|
||||||
|
{
|
||||||
|
if(Superview != null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dismissTimer = NSTimer.CreateScheduledTimer(Duration, x => Dismiss());
|
||||||
|
LayoutIfNeeded();
|
||||||
|
|
||||||
|
var localSuperView = UIApplication.SharedApplication.KeyWindow;
|
||||||
|
if(localSuperView != null)
|
||||||
|
{
|
||||||
|
localSuperView.AddSubview(this);
|
||||||
|
|
||||||
|
_heightConstraint = NSLayoutConstraint.Create(this, NSLayoutAttribute.Height,
|
||||||
|
NSLayoutRelation.GreaterThanOrEqual, null, NSLayoutAttribute.NoAttribute, 1, Height);
|
||||||
|
|
||||||
|
_leftMarginConstraint = NSLayoutConstraint.Create(this, NSLayoutAttribute.Left, NSLayoutRelation.Equal,
|
||||||
|
localSuperView, NSLayoutAttribute.Left, 1, LeftMargin);
|
||||||
|
|
||||||
|
_rightMarginConstraint = NSLayoutConstraint.Create(this, NSLayoutAttribute.Right, NSLayoutRelation.Equal,
|
||||||
|
localSuperView, NSLayoutAttribute.Right, 1, -RightMargin);
|
||||||
|
|
||||||
|
_bottomMarginConstraint = NSLayoutConstraint.Create(this, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal,
|
||||||
|
localSuperView, NSLayoutAttribute.Bottom, 1, -BottomMargin);
|
||||||
|
|
||||||
|
// Avoid the "UIView-Encapsulated-Layout-Height" constraint conflicts
|
||||||
|
// http://stackoverflow.com/questions/25059443/what-is-nslayoutconstraint-uiview-encapsulated-layout-height-and-how-should-i
|
||||||
|
_leftMarginConstraint.Priority = 999;
|
||||||
|
_rightMarginConstraint.Priority = 999;
|
||||||
|
|
||||||
|
AddConstraint(_heightConstraint);
|
||||||
|
localSuperView.AddConstraint(_leftMarginConstraint);
|
||||||
|
localSuperView.AddConstraint(_rightMarginConstraint);
|
||||||
|
localSuperView.AddConstraint(_bottomMarginConstraint);
|
||||||
|
|
||||||
|
ShowWithAnimation();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("Toast needs a keyWindows to display.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dismiss(bool animated = true)
|
||||||
|
{
|
||||||
|
if(Dismissed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dismissed = true;
|
||||||
|
_dismissTimer?.Invalidate();
|
||||||
|
_dismissTimer = null;
|
||||||
|
|
||||||
|
if(!animated)
|
||||||
|
{
|
||||||
|
RemoveFromSuperview();
|
||||||
|
DismissCallback?.Invoke();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetNeedsLayout();
|
||||||
|
Animate(0.3f, 0, UIViewAnimationOptions.CurveEaseIn, () => { Alpha = 0; }, () =>
|
||||||
|
{
|
||||||
|
RemoveFromSuperview();
|
||||||
|
DismissCallback?.Invoke();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowWithAnimation()
|
||||||
|
{
|
||||||
|
Alpha = 0;
|
||||||
|
SetNeedsLayout();
|
||||||
|
_bottomMarginConstraint.Constant = -BottomMargin;
|
||||||
|
_leftMarginConstraint.Constant = LeftMargin;
|
||||||
|
_rightMarginConstraint.Constant = -RightMargin;
|
||||||
|
AnimateNotify(0.3f, 0, 0.7f, 5f, UIViewAnimationOptions.CurveEaseInOut, () => { Alpha = 1; }, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -49,6 +49,7 @@
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Services\CryptoPrimitiveService.cs" />
|
<Compile Include="Services\CryptoPrimitiveService.cs" />
|
||||||
<Compile Include="Services\KeyChainStorageService.cs" />
|
<Compile Include="Services\KeyChainStorageService.cs" />
|
||||||
|
<Compile Include="Views\Toast.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Core\Core.csproj">
|
<ProjectReference Include="..\Core\Core.csproj">
|
||||||
|
|
100
src/iOS/Services/DeviceActionService.cs
Normal file
100
src/iOS/Services/DeviceActionService.cs
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.iOS.Core.Views;
|
||||||
|
using CoreGraphics;
|
||||||
|
using Foundation;
|
||||||
|
using UIKit;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Services
|
||||||
|
{
|
||||||
|
public class DeviceActionService : IDeviceActionService
|
||||||
|
{
|
||||||
|
private Toast _toast;
|
||||||
|
private UIAlertController _progressAlert;
|
||||||
|
|
||||||
|
public bool LaunchApp(string appName)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Toast(string text, bool longDuration = false)
|
||||||
|
{
|
||||||
|
if(!_toast?.Dismissed ?? false)
|
||||||
|
{
|
||||||
|
_toast.Dismiss(false);
|
||||||
|
}
|
||||||
|
_toast = new Toast(text)
|
||||||
|
{
|
||||||
|
Duration = TimeSpan.FromSeconds(longDuration ? 5 : 3)
|
||||||
|
};
|
||||||
|
if(TabBarVisible())
|
||||||
|
{
|
||||||
|
_toast.BottomMargin = 55;
|
||||||
|
}
|
||||||
|
_toast.Show();
|
||||||
|
_toast.DismissCallback = () =>
|
||||||
|
{
|
||||||
|
_toast?.Dispose();
|
||||||
|
_toast = null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task ShowLoadingAsync(string text)
|
||||||
|
{
|
||||||
|
if(_progressAlert != null)
|
||||||
|
{
|
||||||
|
HideLoadingAsync().GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = new TaskCompletionSource<int>();
|
||||||
|
|
||||||
|
var loadingIndicator = new UIActivityIndicatorView(new CGRect(10, 5, 50, 50));
|
||||||
|
loadingIndicator.HidesWhenStopped = true;
|
||||||
|
loadingIndicator.ActivityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray;
|
||||||
|
loadingIndicator.StartAnimating();
|
||||||
|
|
||||||
|
_progressAlert = UIAlertController.Create(null, text, UIAlertControllerStyle.Alert);
|
||||||
|
_progressAlert.View.TintColor = UIColor.Black;
|
||||||
|
_progressAlert.View.Add(loadingIndicator);
|
||||||
|
|
||||||
|
var vc = GetPresentedViewController();
|
||||||
|
vc?.PresentViewController(_progressAlert, false, () => result.TrySetResult(0));
|
||||||
|
return result.Task;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task HideLoadingAsync()
|
||||||
|
{
|
||||||
|
var result = new TaskCompletionSource<int>();
|
||||||
|
if(_progressAlert == null)
|
||||||
|
{
|
||||||
|
result.TrySetResult(0);
|
||||||
|
}
|
||||||
|
_progressAlert.DismissViewController(false, () => result.TrySetResult(0));
|
||||||
|
_progressAlert.Dispose();
|
||||||
|
_progressAlert = null;
|
||||||
|
return result.Task;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UIViewController GetPresentedViewController()
|
||||||
|
{
|
||||||
|
var window = UIApplication.SharedApplication.KeyWindow;
|
||||||
|
var vc = window.RootViewController;
|
||||||
|
while(vc.PresentedViewController != null)
|
||||||
|
{
|
||||||
|
vc = vc.PresentedViewController;
|
||||||
|
}
|
||||||
|
return vc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TabBarVisible()
|
||||||
|
{
|
||||||
|
var vc = GetPresentedViewController();
|
||||||
|
return vc != null && (vc is UITabBarController ||
|
||||||
|
(vc.ChildViewControllers?.Any(c => c is UITabBarController) ?? false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -92,6 +92,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Main.cs" />
|
<Compile Include="Main.cs" />
|
||||||
<Compile Include="AppDelegate.cs" />
|
<Compile Include="AppDelegate.cs" />
|
||||||
|
<Compile Include="Services\DeviceActionService.cs" />
|
||||||
<None Include="Entitlements.plist" />
|
<None Include="Entitlements.plist" />
|
||||||
<None Include="Info.plist" />
|
<None Include="Info.plist" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
@ -171,7 +172,5 @@
|
||||||
<IsWatchApp>false</IsWatchApp>
|
<IsWatchApp>false</IsWatchApp>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup />
|
||||||
<Folder Include="Services\" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
</Project>
|
Loading…
Reference in a new issue