mirror of
https://github.com/bitwarden/mobile
synced 2025-12-27 05:33:23 +00:00
207 lines
7.9 KiB
C#
207 lines
7.9 KiB
C#
using System;
|
|
using Bit.App.Abstractions;
|
|
using UIKit;
|
|
using Foundation;
|
|
using System.IO;
|
|
using MobileCoreServices;
|
|
using Bit.App.Resources;
|
|
using Xamarin.Forms;
|
|
using Photos;
|
|
using System.Net;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Bit.iOS.Services
|
|
{
|
|
public class DeviceActionService : IDeviceActionService
|
|
{
|
|
private readonly IAppSettingsService _appSettingsService;
|
|
|
|
public DeviceActionService(IAppSettingsService appSettingsService)
|
|
{
|
|
_appSettingsService = appSettingsService;
|
|
}
|
|
|
|
public void CopyToClipboard(string text)
|
|
{
|
|
UIPasteboard clipboard = UIPasteboard.General;
|
|
clipboard.String = text;
|
|
}
|
|
|
|
public bool OpenFile(byte[] fileData, string id, string fileName)
|
|
{
|
|
var filePath = Path.Combine(GetTempPath(), fileName);
|
|
File.WriteAllBytes(filePath, fileData);
|
|
var url = NSUrl.FromFilename(filePath);
|
|
var viewer = UIDocumentInteractionController.FromUrl(url);
|
|
var controller = GetVisibleViewController();
|
|
return viewer.PresentOpenInMenu(controller.View.Frame, controller.View, true);
|
|
}
|
|
|
|
public bool CanOpenFile(string fileName)
|
|
{
|
|
// Not sure of a way to check this ahead of time on iOS
|
|
return true;
|
|
}
|
|
|
|
public void ClearCache()
|
|
{
|
|
var url = new NSUrl(GetTempPath());
|
|
NSError error;
|
|
var tmpFiles = NSFileManager.DefaultManager.GetDirectoryContent(url, null,
|
|
NSDirectoryEnumerationOptions.SkipsHiddenFiles, out error);
|
|
if(error == null && tmpFiles.Length > 0)
|
|
{
|
|
foreach(var item in tmpFiles)
|
|
{
|
|
NSError itemError;
|
|
NSFileManager.DefaultManager.Remove(item, out itemError);
|
|
}
|
|
}
|
|
|
|
_appSettingsService.LastCacheClear = DateTime.UtcNow;
|
|
}
|
|
|
|
private UIViewController GetVisibleViewController(UIViewController controller = null)
|
|
{
|
|
controller = controller ?? UIApplication.SharedApplication.KeyWindow.RootViewController;
|
|
if(controller.PresentedViewController == null)
|
|
{
|
|
return controller;
|
|
}
|
|
|
|
if(controller.PresentedViewController is UINavigationController)
|
|
{
|
|
return ((UINavigationController)controller.PresentedViewController).VisibleViewController;
|
|
}
|
|
|
|
if(controller.PresentedViewController is UITabBarController)
|
|
{
|
|
return ((UITabBarController)controller.PresentedViewController).SelectedViewController;
|
|
}
|
|
|
|
return GetVisibleViewController(controller.PresentedViewController);
|
|
}
|
|
|
|
// ref: //https://developer.xamarin.com/guides/ios/application_fundamentals/working_with_the_file_system/
|
|
public string GetTempPath()
|
|
{
|
|
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
|
var tmp = Path.Combine(documents, "..", "tmp");
|
|
return tmp;
|
|
}
|
|
|
|
public Task SelectFileAsync()
|
|
{
|
|
var controller = GetVisibleViewController();
|
|
var picker = new UIDocumentMenuViewController(new string[] { UTType.Data }, UIDocumentPickerMode.Import);
|
|
|
|
picker.AddOption(AppResources.Camera, UIImage.FromBundle("camera"), UIDocumentMenuOrder.First, () =>
|
|
{
|
|
var imagePicker = new UIImagePickerController { SourceType = UIImagePickerControllerSourceType.Camera };
|
|
imagePicker.FinishedPickingMedia += ImagePicker_FinishedPickingMedia;
|
|
imagePicker.Canceled += ImagePicker_Canceled;
|
|
controller.PresentModalViewController(imagePicker, true);
|
|
});
|
|
|
|
picker.AddOption(AppResources.Photos, UIImage.FromBundle("photo"), UIDocumentMenuOrder.First, () =>
|
|
{
|
|
var imagePicker = new UIImagePickerController { SourceType = UIImagePickerControllerSourceType.PhotoLibrary };
|
|
imagePicker.FinishedPickingMedia += ImagePicker_FinishedPickingMedia;
|
|
imagePicker.Canceled += ImagePicker_Canceled;
|
|
controller.PresentModalViewController(imagePicker, true);
|
|
});
|
|
|
|
picker.DidPickDocumentPicker += (sender, e) =>
|
|
{
|
|
controller.PresentViewController(e.DocumentPicker, true, null);
|
|
e.DocumentPicker.DidPickDocument += DocumentPicker_DidPickDocument;
|
|
};
|
|
|
|
controller.PresentViewController(picker, true, null);
|
|
return Task.FromResult(0);
|
|
}
|
|
|
|
private void ImagePicker_FinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs e)
|
|
{
|
|
if(sender is UIImagePickerController picker)
|
|
{
|
|
string fileName = null;
|
|
NSObject urlObj;
|
|
if(e.Info.TryGetValue(UIImagePickerController.ReferenceUrl, out urlObj))
|
|
{
|
|
var result = PHAsset.FetchAssets(new NSUrl[] { (urlObj as NSUrl) }, null);
|
|
fileName = result?.firstObject?.ValueForKey(new NSString("filename"))?.ToString();
|
|
}
|
|
|
|
fileName = fileName ?? $"photo_{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}.jpg";
|
|
|
|
var lowerFilename = fileName?.ToLowerInvariant();
|
|
byte[] data;
|
|
if(lowerFilename != null && (lowerFilename.EndsWith(".jpg") || lowerFilename.EndsWith(".jpeg")))
|
|
{
|
|
using(var imageData = e.OriginalImage.AsJPEG())
|
|
{
|
|
data = new byte[imageData.Length];
|
|
System.Runtime.InteropServices.Marshal.Copy(imageData.Bytes, data, 0,
|
|
Convert.ToInt32(imageData.Length));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
using(var imageData = e.OriginalImage.AsPNG())
|
|
{
|
|
data = new byte[imageData.Length];
|
|
System.Runtime.InteropServices.Marshal.Copy(imageData.Bytes, data, 0,
|
|
Convert.ToInt32(imageData.Length));
|
|
}
|
|
}
|
|
|
|
SelectFileResult(data, fileName);
|
|
picker.DismissViewController(true, null);
|
|
}
|
|
}
|
|
|
|
private void ImagePicker_Canceled(object sender, EventArgs e)
|
|
{
|
|
if(sender is UIImagePickerController picker)
|
|
{
|
|
picker.DismissViewController(true, null);
|
|
}
|
|
}
|
|
|
|
private void DocumentPicker_DidPickDocument(object sender, UIDocumentPickedEventArgs e)
|
|
{
|
|
e.Url.StartAccessingSecurityScopedResource();
|
|
|
|
var doc = new UIDocument(e.Url);
|
|
var fileName = doc.LocalizedName;
|
|
if(string.IsNullOrWhiteSpace(fileName))
|
|
{
|
|
var path = doc.FileUrl?.ToString();
|
|
if(path != null)
|
|
{
|
|
path = WebUtility.UrlDecode(path);
|
|
var split = path.LastIndexOf('/');
|
|
fileName = path.Substring(split + 1);
|
|
}
|
|
}
|
|
|
|
var fileCoordinator = new NSFileCoordinator();
|
|
NSError error;
|
|
fileCoordinator.CoordinateRead(e.Url, NSFileCoordinatorReadingOptions.WithoutChanges, out error, (url) =>
|
|
{
|
|
var data = NSData.FromUrl(url).ToArray();
|
|
SelectFileResult(data, fileName ?? "unknown_file_name");
|
|
});
|
|
|
|
e.Url.StopAccessingSecurityScopedResource();
|
|
}
|
|
|
|
private void SelectFileResult(byte[] data, string fileName)
|
|
{
|
|
MessagingCenter.Send(Xamarin.Forms.Application.Current, "SelectFileResult",
|
|
new Tuple<byte[], string>(data, fileName));
|
|
}
|
|
}
|
|
}
|