diff --git a/src/Android/Android.csproj b/src/Android/Android.csproj index 030c56350..b8bf69266 100644 --- a/src/Android/Android.csproj +++ b/src/Android/Android.csproj @@ -875,6 +875,21 @@ + + + + + + + + + + + + + + + diff --git a/src/Android/Resources/Resource.Designer.cs b/src/Android/Resources/Resource.Designer.cs index 553e91046..7c2708678 100644 --- a/src/Android/Resources/Resource.Designer.cs +++ b/src/Android/Resources/Resource.Designer.cs @@ -2436,361 +2436,364 @@ namespace Bit.Android public const int design_snackbar_background = 2130837629; // aapt resource value: 0x7f02007e - public const int envelope = 2130837630; + public const int download = 2130837630; // aapt resource value: 0x7f02007f - public const int eye = 2130837631; + public const int envelope = 2130837631; // aapt resource value: 0x7f020080 - public const int eye_slash = 2130837632; + public const int eye = 2130837632; // aapt resource value: 0x7f020081 - public const int fa_lock = 2130837633; + public const int eye_slash = 2130837633; // aapt resource value: 0x7f020082 - public const int fa_lock_selected = 2130837634; + public const int fa_lock = 2130837634; // aapt resource value: 0x7f020083 - public const int fingerprint = 2130837635; + public const int fa_lock_selected = 2130837635; // aapt resource value: 0x7f020084 - public const int fingerprint_white = 2130837636; + public const int fingerprint = 2130837636; // aapt resource value: 0x7f020085 - public const int folder = 2130837637; + public const int fingerprint_white = 2130837637; // aapt resource value: 0x7f020086 - public const int globe = 2130837638; + public const int folder = 2130837638; // aapt resource value: 0x7f020087 - public const int hockeyapp_btn_background = 2130837639; + public const int globe = 2130837639; // aapt resource value: 0x7f020088 - public const int ic_audiotrack = 2130837640; + public const int hockeyapp_btn_background = 2130837640; // aapt resource value: 0x7f020089 - public const int ic_audiotrack_light = 2130837641; + public const int ic_audiotrack = 2130837641; // aapt resource value: 0x7f02008a - public const int ic_bluetooth_grey = 2130837642; + public const int ic_audiotrack_light = 2130837642; // aapt resource value: 0x7f02008b - public const int ic_bluetooth_white = 2130837643; + public const int ic_bluetooth_grey = 2130837643; // aapt resource value: 0x7f02008c - public const int ic_cast_dark = 2130837644; + public const int ic_bluetooth_white = 2130837644; // aapt resource value: 0x7f02008d - public const int ic_cast_disabled_light = 2130837645; + public const int ic_cast_dark = 2130837645; // aapt resource value: 0x7f02008e - public const int ic_cast_grey = 2130837646; + public const int ic_cast_disabled_light = 2130837646; // aapt resource value: 0x7f02008f - public const int ic_cast_light = 2130837647; + public const int ic_cast_grey = 2130837647; // aapt resource value: 0x7f020090 - public const int ic_cast_off_light = 2130837648; + public const int ic_cast_light = 2130837648; // aapt resource value: 0x7f020091 - public const int ic_cast_on_0_light = 2130837649; + public const int ic_cast_off_light = 2130837649; // aapt resource value: 0x7f020092 - public const int ic_cast_on_1_light = 2130837650; + public const int ic_cast_on_0_light = 2130837650; // aapt resource value: 0x7f020093 - public const int ic_cast_on_2_light = 2130837651; + public const int ic_cast_on_1_light = 2130837651; // aapt resource value: 0x7f020094 - public const int ic_cast_on_light = 2130837652; + public const int ic_cast_on_2_light = 2130837652; // aapt resource value: 0x7f020095 - public const int ic_cast_white = 2130837653; + public const int ic_cast_on_light = 2130837653; // aapt resource value: 0x7f020096 - public const int ic_close_dark = 2130837654; + public const int ic_cast_white = 2130837654; // aapt resource value: 0x7f020097 - public const int ic_close_light = 2130837655; + public const int ic_close_dark = 2130837655; // aapt resource value: 0x7f020098 - public const int ic_collapse = 2130837656; + public const int ic_close_light = 2130837656; // aapt resource value: 0x7f020099 - public const int ic_collapse_00000 = 2130837657; + public const int ic_collapse = 2130837657; // aapt resource value: 0x7f02009a - public const int ic_collapse_00001 = 2130837658; + public const int ic_collapse_00000 = 2130837658; // aapt resource value: 0x7f02009b - public const int ic_collapse_00002 = 2130837659; + public const int ic_collapse_00001 = 2130837659; // aapt resource value: 0x7f02009c - public const int ic_collapse_00003 = 2130837660; + public const int ic_collapse_00002 = 2130837660; // aapt resource value: 0x7f02009d - public const int ic_collapse_00004 = 2130837661; + public const int ic_collapse_00003 = 2130837661; // aapt resource value: 0x7f02009e - public const int ic_collapse_00005 = 2130837662; + public const int ic_collapse_00004 = 2130837662; // aapt resource value: 0x7f02009f - public const int ic_collapse_00006 = 2130837663; + public const int ic_collapse_00005 = 2130837663; // aapt resource value: 0x7f0200a0 - public const int ic_collapse_00007 = 2130837664; + public const int ic_collapse_00006 = 2130837664; // aapt resource value: 0x7f0200a1 - public const int ic_collapse_00008 = 2130837665; + public const int ic_collapse_00007 = 2130837665; // aapt resource value: 0x7f0200a2 - public const int ic_collapse_00009 = 2130837666; + public const int ic_collapse_00008 = 2130837666; // aapt resource value: 0x7f0200a3 - public const int ic_collapse_00010 = 2130837667; + public const int ic_collapse_00009 = 2130837667; // aapt resource value: 0x7f0200a4 - public const int ic_collapse_00011 = 2130837668; + public const int ic_collapse_00010 = 2130837668; // aapt resource value: 0x7f0200a5 - public const int ic_collapse_00012 = 2130837669; + public const int ic_collapse_00011 = 2130837669; // aapt resource value: 0x7f0200a6 - public const int ic_collapse_00013 = 2130837670; + public const int ic_collapse_00012 = 2130837670; // aapt resource value: 0x7f0200a7 - public const int ic_collapse_00014 = 2130837671; + public const int ic_collapse_00013 = 2130837671; // aapt resource value: 0x7f0200a8 - public const int ic_collapse_00015 = 2130837672; + public const int ic_collapse_00014 = 2130837672; // aapt resource value: 0x7f0200a9 - public const int ic_errorstatus = 2130837673; + public const int ic_collapse_00015 = 2130837673; // aapt resource value: 0x7f0200aa - public const int ic_expand = 2130837674; + public const int ic_errorstatus = 2130837674; // aapt resource value: 0x7f0200ab - public const int ic_expand_00000 = 2130837675; + public const int ic_expand = 2130837675; // aapt resource value: 0x7f0200ac - public const int ic_expand_00001 = 2130837676; + public const int ic_expand_00000 = 2130837676; // aapt resource value: 0x7f0200ad - public const int ic_expand_00002 = 2130837677; + public const int ic_expand_00001 = 2130837677; // aapt resource value: 0x7f0200ae - public const int ic_expand_00003 = 2130837678; + public const int ic_expand_00002 = 2130837678; // aapt resource value: 0x7f0200af - public const int ic_expand_00004 = 2130837679; + public const int ic_expand_00003 = 2130837679; // aapt resource value: 0x7f0200b0 - public const int ic_expand_00005 = 2130837680; + public const int ic_expand_00004 = 2130837680; // aapt resource value: 0x7f0200b1 - public const int ic_expand_00006 = 2130837681; + public const int ic_expand_00005 = 2130837681; // aapt resource value: 0x7f0200b2 - public const int ic_expand_00007 = 2130837682; + public const int ic_expand_00006 = 2130837682; // aapt resource value: 0x7f0200b3 - public const int ic_expand_00008 = 2130837683; + public const int ic_expand_00007 = 2130837683; // aapt resource value: 0x7f0200b4 - public const int ic_expand_00009 = 2130837684; + public const int ic_expand_00008 = 2130837684; // aapt resource value: 0x7f0200b5 - public const int ic_expand_00010 = 2130837685; + public const int ic_expand_00009 = 2130837685; // aapt resource value: 0x7f0200b6 - public const int ic_expand_00011 = 2130837686; + public const int ic_expand_00010 = 2130837686; // aapt resource value: 0x7f0200b7 - public const int ic_expand_00012 = 2130837687; + public const int ic_expand_00011 = 2130837687; // aapt resource value: 0x7f0200b8 - public const int ic_expand_00013 = 2130837688; + public const int ic_expand_00012 = 2130837688; // aapt resource value: 0x7f0200b9 - public const int ic_expand_00014 = 2130837689; + public const int ic_expand_00013 = 2130837689; // aapt resource value: 0x7f0200ba - public const int ic_expand_00015 = 2130837690; + public const int ic_expand_00014 = 2130837690; // aapt resource value: 0x7f0200bb - public const int ic_media_pause = 2130837691; + public const int ic_expand_00015 = 2130837691; // aapt resource value: 0x7f0200bc - public const int ic_media_play = 2130837692; + public const int ic_media_pause = 2130837692; // aapt resource value: 0x7f0200bd - public const int ic_media_route_disabled_mono_dark = 2130837693; + public const int ic_media_play = 2130837693; // aapt resource value: 0x7f0200be - public const int ic_media_route_off_mono_dark = 2130837694; + public const int ic_media_route_disabled_mono_dark = 2130837694; // aapt resource value: 0x7f0200bf - public const int ic_media_route_on_0_mono_dark = 2130837695; + public const int ic_media_route_off_mono_dark = 2130837695; // aapt resource value: 0x7f0200c0 - public const int ic_media_route_on_1_mono_dark = 2130837696; + public const int ic_media_route_on_0_mono_dark = 2130837696; // aapt resource value: 0x7f0200c1 - public const int ic_media_route_on_2_mono_dark = 2130837697; + public const int ic_media_route_on_1_mono_dark = 2130837697; // aapt resource value: 0x7f0200c2 - public const int ic_media_route_on_mono_dark = 2130837698; + public const int ic_media_route_on_2_mono_dark = 2130837698; // aapt resource value: 0x7f0200c3 - public const int ic_pause_dark = 2130837699; + public const int ic_media_route_on_mono_dark = 2130837699; // aapt resource value: 0x7f0200c4 - public const int ic_pause_light = 2130837700; + public const int ic_pause_dark = 2130837700; // aapt resource value: 0x7f0200c5 - public const int ic_play_dark = 2130837701; + public const int ic_pause_light = 2130837701; // aapt resource value: 0x7f0200c6 - public const int ic_play_light = 2130837702; + public const int ic_play_dark = 2130837702; // aapt resource value: 0x7f0200c7 - public const int ic_speaker_dark = 2130837703; + public const int ic_play_light = 2130837703; // aapt resource value: 0x7f0200c8 - public const int ic_speaker_group_dark = 2130837704; + public const int ic_speaker_dark = 2130837704; // aapt resource value: 0x7f0200c9 - public const int ic_speaker_group_light = 2130837705; + public const int ic_speaker_group_dark = 2130837705; // aapt resource value: 0x7f0200ca - public const int ic_speaker_light = 2130837706; + public const int ic_speaker_group_light = 2130837706; // aapt resource value: 0x7f0200cb - public const int ic_successstatus = 2130837707; + public const int ic_speaker_light = 2130837707; // aapt resource value: 0x7f0200cc - public const int ic_tv_dark = 2130837708; + public const int ic_successstatus = 2130837708; // aapt resource value: 0x7f0200cd - public const int ic_tv_light = 2130837709; + public const int ic_tv_dark = 2130837709; // aapt resource value: 0x7f0200ce - public const int icon = 2130837710; + public const int ic_tv_light = 2130837710; // aapt resource value: 0x7f0200cf - public const int ion_chevron_right = 2130837711; + public const int icon = 2130837711; // aapt resource value: 0x7f0200d0 - public const int lightbulb = 2130837712; + public const int ion_chevron_right = 2130837712; // aapt resource value: 0x7f0200d1 - public const int list_selector = 2130837713; + public const int lightbulb = 2130837713; // aapt resource value: 0x7f0200d2 - public const int @lock = 2130837714; + public const int list_selector = 2130837714; // aapt resource value: 0x7f0200d3 - public const int logo = 2130837715; + public const int @lock = 2130837715; // aapt resource value: 0x7f0200d4 - public const int more = 2130837716; + public const int logo = 2130837716; // aapt resource value: 0x7f0200d5 - public const int mr_dialog_material_background_dark = 2130837717; + public const int more = 2130837717; // aapt resource value: 0x7f0200d6 - public const int mr_dialog_material_background_light = 2130837718; + public const int mr_dialog_material_background_dark = 2130837718; // aapt resource value: 0x7f0200d7 - public const int mr_ic_audiotrack_light = 2130837719; + public const int mr_dialog_material_background_light = 2130837719; // aapt resource value: 0x7f0200d8 - public const int mr_ic_cast_dark = 2130837720; + public const int mr_ic_audiotrack_light = 2130837720; // aapt resource value: 0x7f0200d9 - public const int mr_ic_cast_light = 2130837721; + public const int mr_ic_cast_dark = 2130837721; // aapt resource value: 0x7f0200da - public const int mr_ic_close_dark = 2130837722; + public const int mr_ic_cast_light = 2130837722; // aapt resource value: 0x7f0200db - public const int mr_ic_close_light = 2130837723; + public const int mr_ic_close_dark = 2130837723; // aapt resource value: 0x7f0200dc - public const int mr_ic_media_route_connecting_mono_dark = 2130837724; + public const int mr_ic_close_light = 2130837724; // aapt resource value: 0x7f0200dd - public const int mr_ic_media_route_connecting_mono_light = 2130837725; + public const int mr_ic_media_route_connecting_mono_dark = 2130837725; // aapt resource value: 0x7f0200de - public const int mr_ic_media_route_mono_dark = 2130837726; + public const int mr_ic_media_route_connecting_mono_light = 2130837726; // aapt resource value: 0x7f0200df - public const int mr_ic_media_route_mono_light = 2130837727; + public const int mr_ic_media_route_mono_dark = 2130837727; // aapt resource value: 0x7f0200e0 - public const int mr_ic_pause_dark = 2130837728; + public const int mr_ic_media_route_mono_light = 2130837728; // aapt resource value: 0x7f0200e1 - public const int mr_ic_pause_light = 2130837729; + public const int mr_ic_pause_dark = 2130837729; // aapt resource value: 0x7f0200e2 - public const int mr_ic_play_dark = 2130837730; + public const int mr_ic_pause_light = 2130837730; // aapt resource value: 0x7f0200e3 - public const int mr_ic_play_light = 2130837731; + public const int mr_ic_play_dark = 2130837731; // aapt resource value: 0x7f0200e4 - public const int notification_sm = 2130837732; - - // aapt resource value: 0x7f0200f4 - public const int notification_template_icon_bg = 2130837748; + public const int mr_ic_play_light = 2130837732; // aapt resource value: 0x7f0200e5 - public const int plus = 2130837733; + public const int notification_sm = 2130837733; + + // aapt resource value: 0x7f0200f5 + public const int notification_template_icon_bg = 2130837749; // aapt resource value: 0x7f0200e6 - public const int refresh = 2130837734; + public const int plus = 2130837734; // aapt resource value: 0x7f0200e7 - public const int roundedbg = 2130837735; + public const int refresh = 2130837735; // aapt resource value: 0x7f0200e8 - public const int roundedbgdark = 2130837736; + public const int roundedbg = 2130837736; // aapt resource value: 0x7f0200e9 - public const int search = 2130837737; + public const int roundedbgdark = 2130837737; // aapt resource value: 0x7f0200ea - public const int share = 2130837738; + public const int search = 2130837738; // aapt resource value: 0x7f0200eb - public const int share_tools = 2130837739; + public const int share = 2130837739; // aapt resource value: 0x7f0200ec - public const int splash_screen = 2130837740; + public const int share_tools = 2130837740; // aapt resource value: 0x7f0200ed - public const int star = 2130837741; + public const int splash_screen = 2130837741; // aapt resource value: 0x7f0200ee - public const int star_selected = 2130837742; + public const int star = 2130837742; // aapt resource value: 0x7f0200ef - public const int tools = 2130837743; + public const int star_selected = 2130837743; // aapt resource value: 0x7f0200f0 - public const int tools_selected = 2130837744; + public const int tools = 2130837744; // aapt resource value: 0x7f0200f1 - public const int upload = 2130837745; + public const int tools_selected = 2130837745; // aapt resource value: 0x7f0200f2 - public const int user = 2130837746; + public const int upload = 2130837746; // aapt resource value: 0x7f0200f3 - public const int yubikey = 2130837747; + public const int user = 2130837747; + + // aapt resource value: 0x7f0200f4 + public const int yubikey = 2130837748; static Drawable() { diff --git a/src/Android/Resources/drawable-hdpi/download.png b/src/Android/Resources/drawable-hdpi/download.png new file mode 100644 index 000000000..a0b964e28 Binary files /dev/null and b/src/Android/Resources/drawable-hdpi/download.png differ diff --git a/src/Android/Resources/drawable-xhdpi/download.png b/src/Android/Resources/drawable-xhdpi/download.png new file mode 100644 index 000000000..843eb7384 Binary files /dev/null and b/src/Android/Resources/drawable-xhdpi/download.png differ diff --git a/src/Android/Resources/drawable-xxhdpi/download.png b/src/Android/Resources/drawable-xxhdpi/download.png new file mode 100644 index 000000000..82951e574 Binary files /dev/null and b/src/Android/Resources/drawable-xxhdpi/download.png differ diff --git a/src/Android/Resources/drawable-xxxhdpi/download.png b/src/Android/Resources/drawable-xxxhdpi/download.png new file mode 100644 index 000000000..631ff3cc0 Binary files /dev/null and b/src/Android/Resources/drawable-xxxhdpi/download.png differ diff --git a/src/Android/Resources/drawable/download.png b/src/Android/Resources/drawable/download.png new file mode 100644 index 000000000..477a72d3f Binary files /dev/null and b/src/Android/Resources/drawable/download.png differ diff --git a/src/Android/Services/DeviceActionService.cs b/src/Android/Services/DeviceActionService.cs index 32351fa39..87ba79afc 100644 --- a/src/Android/Services/DeviceActionService.cs +++ b/src/Android/Services/DeviceActionService.cs @@ -2,11 +2,9 @@ using Android.Content; using Bit.App.Abstractions; using Xamarin.Forms; -using Java.IO; using Android.Webkit; using Plugin.CurrentActivity; using System.IO; -using System.Diagnostics; using Android.Support.V4.Content; namespace Bit.Android.Services @@ -21,6 +19,11 @@ namespace Bit.Android.Services public bool OpenFile(byte[] fileData, string id, string fileName) { + if(!CanOpenFile(fileName)) + { + return false; + } + var extension = MimeTypeMap.GetFileExtensionFromUrl(fileName); if(extension == null) { @@ -35,29 +38,47 @@ namespace Bit.Android.Services var cachePath = CrossCurrentActivity.Current.Activity.CacheDir; var filePath = Path.Combine(cachePath.Path, fileName); - System.IO.File.WriteAllBytes(filePath, fileData); + File.WriteAllBytes(filePath, fileData); var file = new Java.IO.File(cachePath, fileName); + if(!file.IsFile) + { + return false; + } + try { - var packageManager = CrossCurrentActivity.Current.Activity.PackageManager; - var testIntent = new Intent(Intent.ActionView); - testIntent.SetType(mimeType); - var list = packageManager.QueryIntentActivities(testIntent, - global::Android.Content.PM.PackageInfoFlags.MatchDefaultOnly); - if(list.Count > 0 && file.IsFile) - { - var intent = new Intent(Intent.ActionView); - var uri = FileProvider.GetUriForFile(CrossCurrentActivity.Current.Activity.ApplicationContext, - "com.x8bit.bitwarden.fileprovider", file); - intent.SetDataAndType(uri, mimeType); - intent.SetFlags(ActivityFlags.GrantReadUriPermission); - CrossCurrentActivity.Current.Activity.StartActivity(intent); - return true; - } + var intent = new Intent(Intent.ActionView); + var uri = FileProvider.GetUriForFile(CrossCurrentActivity.Current.Activity.ApplicationContext, + "com.x8bit.bitwarden.fileprovider", file); + intent.SetDataAndType(uri, mimeType); + intent.SetFlags(ActivityFlags.GrantReadUriPermission); + CrossCurrentActivity.Current.Activity.StartActivity(intent); + return true; } catch { } return false; } + + public bool CanOpenFile(string fileName) + { + var extension = MimeTypeMap.GetFileExtensionFromUrl(fileName); + if(extension == null) + { + return false; + } + + var mimeType = MimeTypeMap.Singleton.GetMimeTypeFromExtension(extension.ToLower()); + if(mimeType == null) + { + return false; + } + + var pm = CrossCurrentActivity.Current.Activity.PackageManager; + var intent = new Intent(Intent.ActionView); + intent.SetType(mimeType); + var activities = pm.QueryIntentActivities(intent, global::Android.Content.PM.PackageInfoFlags.MatchDefaultOnly); + return (activities?.Count ?? 0) > 0; + } } } diff --git a/src/App/Abstractions/Services/IDeviceActionService.cs b/src/App/Abstractions/Services/IDeviceActionService.cs index 6e4ce8f6a..7d7e06ec5 100644 --- a/src/App/Abstractions/Services/IDeviceActionService.cs +++ b/src/App/Abstractions/Services/IDeviceActionService.cs @@ -4,5 +4,6 @@ { void CopyToClipboard(string text); bool OpenFile(byte[] fileData, string id, string fileName); + bool CanOpenFile(string fileName); } } diff --git a/src/App/Models/Attachment.cs b/src/App/Models/Attachment.cs index dc41a6218..7f328db90 100644 --- a/src/App/Models/Attachment.cs +++ b/src/App/Models/Attachment.cs @@ -13,7 +13,7 @@ namespace Bit.App.Models Id = data.Id; Url = data.Url; FileName = data.FileName != null ? new CipherString(data.FileName) : null; - Size = data.Size; + SetSize(data.Size); SizeName = data.SizeName; } @@ -22,19 +22,30 @@ namespace Bit.App.Models Id = response.Id; Url = response.Url; FileName = response.FileName != null ? new CipherString(response.FileName) : null; - Size = response.Size; + SetSize(response.Size); SizeName = response.SizeName; } public string Id { get; set; } public string Url { get; set; } public CipherString FileName { get; set; } - public string Size { get; set; } + public long Size { get; set; } public string SizeName { get; set; } public AttachmentData ToAttachmentData(string loginId) { return new AttachmentData(this, loginId); } + + private void SetSize(string sizeString) + { + long size; + if(!long.TryParse(sizeString, out size)) + { + size = 0; + } + + Size = size; + } } } diff --git a/src/App/Models/Data/AttachmentData.cs b/src/App/Models/Data/AttachmentData.cs index a64c8f1a2..d59156743 100644 --- a/src/App/Models/Data/AttachmentData.cs +++ b/src/App/Models/Data/AttachmentData.cs @@ -16,7 +16,7 @@ namespace Bit.App.Models.Data LoginId = loginId; Url = attachment.Url; FileName = attachment.FileName?.EncryptedString; - Size = attachment.Size; + Size = attachment.Size.ToString(); SizeName = attachment.SizeName; } diff --git a/src/App/Models/Page/VaultViewLoginPageModel.cs b/src/App/Models/Page/VaultViewLoginPageModel.cs index 6b35b07ab..de1b4cba8 100644 --- a/src/App/Models/Page/VaultViewLoginPageModel.cs +++ b/src/App/Models/Page/VaultViewLoginPageModel.cs @@ -223,7 +223,8 @@ namespace Bit.App.Models.Page { Id = attachment.Id, Name = attachment.FileName?.Decrypt(login.OrganizationId), - Size = attachment.SizeName, + SizeName = attachment.SizeName, + Size = attachment.Size, Url = attachment.Url }); } @@ -239,7 +240,8 @@ namespace Bit.App.Models.Page { public string Id { get; set; } public string Name { get; set; } - public string Size { get; set; } + public string SizeName { get; set; } + public long Size { get; set; } public string Url { get; set; } } } diff --git a/src/App/Pages/Vault/VaultViewLoginPage.cs b/src/App/Pages/Vault/VaultViewLoginPage.cs index ef0d68f0e..33b6fe5c3 100644 --- a/src/App/Pages/Vault/VaultViewLoginPage.cs +++ b/src/App/Pages/Vault/VaultViewLoginPage.cs @@ -196,7 +196,7 @@ namespace Bit.App.Pages { AttachmentsSection.Add(new AttachmentViewCell(attachment, async () => { - await SaveAttachmentAsync(attachment); + await OpenAttachmentAsync(attachment); })); } Table.Root.Add(AttachmentsSection); @@ -211,8 +211,22 @@ namespace Bit.App.Pages EditItem.Dispose(); } - private async Task SaveAttachmentAsync(VaultViewLoginPageModel.Attachment attachment) + private async Task OpenAttachmentAsync(VaultViewLoginPageModel.Attachment attachment) { + // 20 MB warning + if(attachment.Size >= 20971520 && !(await _userDialogs.ConfirmAsync( + string.Format(AppResources.AttachmentLargeWarning, attachment.SizeName), null, + AppResources.Yes, AppResources.No))) + { + return; + } + + if(!_deviceActionService.CanOpenFile(attachment.Name)) + { + await _userDialogs.AlertAsync(AppResources.UnableToOpenFile, null, AppResources.Ok); + return; + } + _userDialogs.ShowLoading(AppResources.Downloading, MaskType.Black); var data = await _loginService.DownloadAndDecryptAttachmentAsync(null, attachment.Url); _userDialogs.HideLoading(); @@ -222,8 +236,7 @@ namespace Bit.App.Pages return; } - var opened = _deviceActionService.OpenFile(data, attachment.Id, attachment.Name); - if(!opened) + if(!_deviceActionService.OpenFile(data, attachment.Id, attachment.Name)) { await _userDialogs.AlertAsync(AppResources.UnableToOpenFile, null, AppResources.Ok); return; @@ -269,8 +282,8 @@ namespace Bit.App.Pages { _tapped = tappedAction; Label.Text = attachment.Name; - Detail.Text = attachment.Size; - Icon.Source = "user"; // TODO: download icon + Detail.Text = attachment.SizeName; + Icon.Source = "download"; BackgroundColor = Color.White; Tapped += AttachmentViewCell_Tapped; } diff --git a/src/App/Resources/AppResources.Designer.cs b/src/App/Resources/AppResources.Designer.cs index 8b42a6858..b058a0d8f 100644 --- a/src/App/Resources/AppResources.Designer.cs +++ b/src/App/Resources/AppResources.Designer.cs @@ -151,6 +151,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to This attachment is {0} in size. Are you sure you want to download it onto your device?. + /// + public static string AttachmentLargeWarning { + get { + return ResourceManager.GetString("AttachmentLargeWarning", resourceCulture); + } + } + /// /// Looks up a localized string similar to Attachments. /// @@ -2006,7 +2015,7 @@ namespace Bit.App.Resources { } /// - /// Looks up a localized string similar to Unable to open this type of file on your device.. + /// Looks up a localized string similar to Your device cannot open this type of tile.. /// public static string UnableToOpenFile { get { diff --git a/src/App/Resources/AppResources.resx b/src/App/Resources/AppResources.resx index abcb882cd..8d9fb6b19 100644 --- a/src/App/Resources/AppResources.resx +++ b/src/App/Resources/AppResources.resx @@ -912,10 +912,14 @@ Unable to download file. - Unable to open this type of file on your device. + Your device cannot open this type of tile. Downloading... Message shown when downloading a file + + This attachment is {0} in size. Are you sure you want to download it onto your device? + The placeholder will show the file size of the attachment. Ex "25 MB" + \ No newline at end of file diff --git a/src/App/Utilities/ApiHttpClient.cs b/src/App/Utilities/ApiHttpClient.cs index 163643995..cc958a07e 100644 --- a/src/App/Utilities/ApiHttpClient.cs +++ b/src/App/Utilities/ApiHttpClient.cs @@ -20,9 +20,9 @@ namespace Bit.App private void Init() { //BaseAddress = new Uri("http://169.254.80.80:4000"); // Desktop from VS Android Emulator - //BaseAddress = new Uri("http://192.168.1.6:4000"); // Desktop + BaseAddress = new Uri("http://192.168.1.4:4000"); // Desktop //BaseAddress = new Uri("https://preview-api.bitwarden.com"); // Preview - BaseAddress = new Uri("https://api.bitwarden.com"); // Production + // BaseAddress = new Uri("https://api.bitwarden.com"); // Production DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); } } diff --git a/src/App/Utilities/IdentityHttpClient.cs b/src/App/Utilities/IdentityHttpClient.cs index 58d509c48..259c6d16c 100644 --- a/src/App/Utilities/IdentityHttpClient.cs +++ b/src/App/Utilities/IdentityHttpClient.cs @@ -20,9 +20,9 @@ namespace Bit.App private void Init() { //BaseAddress = new Uri("http://169.254.80.80:33656"); // Desktop from VS Android Emulator - //BaseAddress = new Uri("http://192.168.1.6:33656"); // Desktop + BaseAddress = new Uri("http://192.168.1.4:33656"); // Desktop //BaseAddress = new Uri("https://identity-api.bitwarden.com"); // Preview - BaseAddress = new Uri("https://identity.bitwarden.com"); // Production + //BaseAddress = new Uri("https://identity.bitwarden.com"); // Production DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); } } diff --git a/src/iOS/Resources/download.png b/src/iOS/Resources/download.png new file mode 100644 index 000000000..477a72d3f Binary files /dev/null and b/src/iOS/Resources/download.png differ diff --git a/src/iOS/Resources/download@2x.png b/src/iOS/Resources/download@2x.png new file mode 100644 index 000000000..843eb7384 Binary files /dev/null and b/src/iOS/Resources/download@2x.png differ diff --git a/src/iOS/Resources/download@3x.png b/src/iOS/Resources/download@3x.png new file mode 100644 index 000000000..82951e574 Binary files /dev/null and b/src/iOS/Resources/download@3x.png differ diff --git a/src/iOS/Services/DeviceActionService.cs b/src/iOS/Services/DeviceActionService.cs index 618edc608..f9cb9086e 100644 --- a/src/iOS/Services/DeviceActionService.cs +++ b/src/iOS/Services/DeviceActionService.cs @@ -14,7 +14,12 @@ namespace Bit.iOS.Services public bool OpenFile(byte[] fileData, string id, string fileName) { - throw new NotImplementedException(); + return true; + } + + public bool CanOpenFile(string fileName) + { + return true; } } } diff --git a/src/iOS/iOS.csproj b/src/iOS/iOS.csproj index dd0e6dae7..7c353b9be 100644 --- a/src/iOS/iOS.csproj +++ b/src/iOS/iOS.csproj @@ -725,6 +725,15 @@ + + + + + + + + +