Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preview pane error handling improvements #4517

Merged
merged 5 commits into from
Apr 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 40 additions & 24 deletions Files/ViewModels/PreviewPaneViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,41 +210,57 @@ private async Task LoadPreviewControlAsync(CancellationToken token)

private async Task<UIElement> LoadPreviewControlFromExtension(ListedItem item, Extension extension)
{
try
{
UIElement control = null;
var file = await StorageFile.GetFileFromPathAsync(item.ItemPath);
string sharingToken = SharedStorageAccessManager.AddFile(file);
var result = await extension.Invoke(new ValueSet() { { "token", sharingToken } });

if (result.TryGetValue("preview", out object preview))
{
control = XamlReader.Load(preview as string) as UIElement;
}

if (result.TryGetValue("details", out object details))
{
var detailsList = JsonConvert.DeserializeObject<List<FileProperty>>(details as string);
await BasePreviewModel.LoadDetailsOnly(item, detailsList);
}
UIElement control = null;
var file = await StorageFile.GetFileFromPathAsync(item.ItemPath);
string sharingToken = SharedStorageAccessManager.AddFile(file);
var result = await extension.Invoke(new ValueSet() { { "token", sharingToken } });

return control;
if (result.TryGetValue("preview", out object preview))
{
control = XamlReader.Load(preview as string) as UIElement;
}
catch (Exception e)

if (result.TryGetValue("details", out object details))
{
Debug.WriteLine(e.ToString());
var detailsList = JsonConvert.DeserializeObject<List<FileProperty>>(details as string);
await BasePreviewModel.LoadDetailsOnly(item, detailsList);
}
return null;

return control;
}

private async void SelectedItemChanged()
{
loadCancellationTokenSource?.Cancel();
if (SelectedItem != null && SelectedItems.Count == 1)
{
DetailsListVisibility = Visibility.Visible;
loadCancellationTokenSource = new CancellationTokenSource();
await LoadPreviewControlAsync(loadCancellationTokenSource.Token);
try
{
DetailsListVisibility = Visibility.Visible;
loadCancellationTokenSource = new CancellationTokenSource();
await LoadPreviewControlAsync(loadCancellationTokenSource.Token);
}
catch (Exception e)
{
Debug.WriteLine(e);
loadCancellationTokenSource?.Cancel();
// If initial loading fails, attempt to load a basic preivew (thumbnail and details only)
// If that fails, revert to no preview/details available
try
{
var basicModel = new BasicPreviewViewModel(SelectedItem);
await basicModel.LoadAsync();
PreviewPaneContent = new BasicPreview(basicModel);
}
catch (Exception ex)
{
Debug.WriteLine(ex);
PreviewPaneContent = null;
DetailsListVisibility = Visibility.Collapsed;
DetailsErrorText = "PreviewPaneDetailsNotAvailableText".GetLocalized();
PreviewErrorText = "DetailsPanePreviewNotAvaliableText".GetLocalized();
}
}
}
else if (SelectedItem != null)
{
Expand Down
96 changes: 55 additions & 41 deletions Files/ViewModels/Previews/BasePreviewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using Microsoft.Toolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
Expand All @@ -21,42 +20,32 @@ public BasePreviewModel(ListedItem item) : base()
Item = item;
}

public delegate void LoadedEventHandler(object sender, EventArgs e);

public event LoadedEventHandler LoadedEvent;
public ListedItem Item { get; internal set; }

public List<FileProperty> DetailsFromPreview { get; set; }
public ListedItem Item { get; internal set; }
public CancellationTokenSource LoadCancelledTokenSource { get; } = new CancellationTokenSource();

public static async Task LoadDetailsOnly(ListedItem item, List<FileProperty> details = null)
{
var temp = new DetailsOnlyPreviewModel(item) { DetailsFromPreview = details };
await temp.LoadAsync();
}
/// <summary>
/// This is cancelled when the user has selected another file or closed the pane.
/// </summary>
public CancellationTokenSource LoadCancelledTokenSource { get; } = new CancellationTokenSource();

public virtual async Task LoadAsync()
/// <summary>
/// Override this if the preview control needs to handle the unloaded event.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public virtual void PreviewControlBase_Unloaded(object sender, RoutedEventArgs e)
{
// Files can be corrupt, in use, and stuff
try
{
var detailsFull = new List<FileProperty>();
Item.ItemFile ??= await StorageFile.GetFileFromPathAsync(Item.ItemPath);
DetailsFromPreview = await LoadPreviewAndDetails();
RaiseLoadedEvent();
var props = await GetSystemFileProperties();

DetailsFromPreview?.ForEach(i => detailsFull.Add(i));
props?.ForEach(i => detailsFull.Add(i));

Item.FileDetails = new System.Collections.ObjectModel.ObservableCollection<FileProperty>(detailsFull);
}
catch (Exception e)
{
Debug.WriteLine(e);
}
LoadCancelledTokenSource.Cancel();
}

/// <summary>
/// Override this and place the code to load the file preview here.
/// You can return details that may have been obtained while loading the preview (eg. word count).
/// This details will be displayed *before* the system file properties.
/// If there are none, return an empty list.
/// </summary>
/// <returns>A list of details</returns>
public async virtual Task<List<FileProperty>> LoadPreviewAndDetails()
{
var (IconData, OverlayData, IsCustom) = await FileThumbnailHelper.LoadIconOverlayAsync(Item.ItemPath, 400);
Expand All @@ -75,17 +64,6 @@ public async virtual Task<List<FileProperty>> LoadPreviewAndDetails()
return new List<FileProperty>();
}

public virtual void PreviewControlBase_Unloaded(object sender, RoutedEventArgs e)
{
LoadCancelledTokenSource.Cancel();
}

protected virtual void RaiseLoadedEvent()
{
// Raise the event in a thread-safe manner using the ?. operator.
LoadedEvent?.Invoke(this, new EventArgs());
}

private async Task<List<FileProperty>> GetSystemFileProperties()
{
if (Item.IsShortcutItem)
Expand All @@ -100,6 +78,42 @@ private async Task<List<FileProperty>> GetSystemFileProperties()
return list.Where(i => i.Value != null).ToList();
}

/// <summary>
/// Call this function when you are ready to load the preview and details.
/// Override if you need custom loading code.
/// </summary>
/// <returns>The task to run</returns>
public virtual async Task LoadAsync()
{
var detailsFull = new List<FileProperty>();
Item.ItemFile ??= await StorageFile.GetFileFromPathAsync(Item.ItemPath);
DetailsFromPreview = await LoadPreviewAndDetails();
RaiseLoadedEvent();
var props = await GetSystemFileProperties();

// Add the details from the preview function, then the system file properties
DetailsFromPreview?.ForEach(i => detailsFull.Add(i));
props?.ForEach(i => detailsFull.Add(i));

Item.FileDetails = new System.Collections.ObjectModel.ObservableCollection<FileProperty>(detailsFull);
}

public event LoadedEventHandler LoadedEvent;

public delegate void LoadedEventHandler(object sender, EventArgs e);

protected virtual void RaiseLoadedEvent()
{
// Raise the event in a thread-safe manner using the ?. operator.
LoadedEvent?.Invoke(this, new EventArgs());
}

public static async Task LoadDetailsOnly(ListedItem item, List<FileProperty> details = null)
{
var temp = new DetailsOnlyPreviewModel(item) { DetailsFromPreview = details };
await temp.LoadAsync();
}

internal class DetailsOnlyPreviewModel : BasePreviewModel
{
public DetailsOnlyPreviewModel(ListedItem item) : base(item)
Expand Down
8 changes: 1 addition & 7 deletions Files/ViewModels/Previews/FolderPreviewViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,7 @@ public FolderPreviewViewModel(ListedItem item)

public async Task LoadAsync()
{
try
{
await LoadPreviewAndDetailsAsync();
}
catch (Exception)
{
}
await LoadPreviewAndDetailsAsync();
}

private async Task LoadPreviewAndDetailsAsync()
Expand Down
9 changes: 1 addition & 8 deletions Files/ViewModels/Previews/HtmlPreviewViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,7 @@ public string TextValue

public async override Task<List<FileProperty>> LoadPreviewAndDetails()
{
try
{
TextValue = await FileIO.ReadTextAsync(Item.ItemFile);
}
catch (Exception e)
{
Debug.WriteLine(e);
}
TextValue = await FileIO.ReadTextAsync(Item.ItemFile);
return new List<FileProperty>();
}
}
Expand Down
29 changes: 11 additions & 18 deletions Files/ViewModels/Previews/ImagePreviewViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,27 +31,20 @@ public ImageSource ImageSource

public override async Task<List<FileProperty>> LoadPreviewAndDetails()
{
try
{
FileRandomAccessStream stream = (FileRandomAccessStream)await Item.ItemFile.OpenAsync(FileAccessMode.Read);
FileRandomAccessStream stream = (FileRandomAccessStream)await Item.ItemFile.OpenAsync(FileAccessMode.Read);

// svg files require a different type of source
if (!Item.ItemPath.EndsWith(".svg"))
{
var bitmap = new BitmapImage();
ImageSource = bitmap;
await bitmap.SetSourceAsync(stream);
}
else
{
var bitmap = new SvgImageSource();
ImageSource = bitmap;
await bitmap.SetSourceAsync(stream);
}
// svg files require a different type of source
if (!Item.ItemPath.EndsWith(".svg"))
{
var bitmap = new BitmapImage();
ImageSource = bitmap;
await bitmap.SetSourceAsync(stream);
}
catch (Exception e)
else
{
Debug.WriteLine(e);
var bitmap = new SvgImageSource();
ImageSource = bitmap;
await bitmap.SetSourceAsync(stream);
}

return new List<FileProperty>();
Expand Down
13 changes: 3 additions & 10 deletions Files/ViewModels/Previews/MarkdownPreviewViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,9 @@ public string TextValue

public override async Task<List<FileProperty>> LoadPreviewAndDetails()
{
try
{
var text = await FileIO.ReadTextAsync(Item.ItemFile);
var displayText = text.Length < Constants.PreviewPane.TextCharacterLimit ? text : text.Remove(Constants.PreviewPane.TextCharacterLimit);
TextValue = displayText;
}
catch (Exception e)
{
Debug.WriteLine(e);
}
var text = await FileIO.ReadTextAsync(Item.ItemFile);
var displayText = text.Length < Constants.PreviewPane.TextCharacterLimit ? text : text.Remove(Constants.PreviewPane.TextCharacterLimit);
TextValue = displayText;

return new List<FileProperty>();
}
Expand Down
33 changes: 24 additions & 9 deletions Files/ViewModels/Previews/PDFPreviewViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.Data.Pdf;
using Windows.Storage.Streams;
Expand Down Expand Up @@ -35,20 +36,34 @@ public Visibility LoadingBarVisibility
public async override Task<List<FileProperty>> LoadPreviewAndDetails()
{
var pdf = await PdfDocument.LoadFromFileAsync(Item.ItemFile);
var details = new List<FileProperty>();

LoadPagesAsync(pdf);
// Add the number of pages to the details
details.Add(new FileProperty()
TryLoadPagesAsync(pdf);
var details = new List<FileProperty>
{
NameResource = "PropertyPageCount",
Value = pdf.PageCount,
});

// Add the number of pages to the details
new FileProperty()
{
NameResource = "PropertyPageCount",
Value = pdf.PageCount,
}
};

return details;
}

private async void LoadPagesAsync(PdfDocument pdf)
public async void TryLoadPagesAsync(PdfDocument pdf)
{
try
{
await LoadPagesAsync(pdf);
}
catch (Exception e)
{
Debug.WriteLine(e);
}
}

private async Task LoadPagesAsync(PdfDocument pdf)
{
// This fixes an issue where loading an absurdly large PDF would take to much RAM
// and eventually cause a crash
Expand Down
10 changes: 1 addition & 9 deletions Files/ViewModels/Previews/RichTextPreviewViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,7 @@ public RichTextPreviewViewModel(ListedItem item) : base(item)

public async override Task<List<FileProperty>> LoadPreviewAndDetails()
{
try
{
Stream = await Item.ItemFile.OpenReadAsync();
}
catch (Exception e)
{
Debug.WriteLine(e);
}

Stream = await Item.ItemFile.OpenReadAsync();
return new List<FileProperty>();
}
}
Expand Down
Loading