finally got it working stable
This commit is contained in:
Родитель
5c0a6d1897
Коммит
e2c717402b
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26430.6
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NextcloudApp", "NextcloudApp\NextcloudApp.csproj", "{99EFB7EA-88A3-4FCF-9289-22734215B5CF}"
|
||||
EndProject
|
||||
|
|
|
@ -1,421 +1,424 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel;
|
||||
using Microsoft.Practices.Unity;
|
||||
using Prism.Unity.Windows;
|
||||
using Prism.Windows.AppModel;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
using Windows.Security.Credentials;
|
||||
using Windows.Storage.AccessCache;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Newtonsoft.Json;
|
||||
using NextcloudApp.Models;
|
||||
using NextcloudApp.Services;
|
||||
using NextcloudApp.Utils;
|
||||
using NextcloudClient.Exceptions;
|
||||
using NextcloudClient.Types;
|
||||
using Prism.Windows.Mvvm;
|
||||
using Microsoft.QueryStringDotNET;
|
||||
using Windows.UI.Notifications;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.System;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using Windows.Storage;
|
||||
|
||||
namespace NextcloudApp
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides application-specific behavior to supplement the default Application class.
|
||||
/// </summary>
|
||||
sealed partial class App : PrismUnityApplication
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the singleton application object. This is the first line of authored code
|
||||
/// executed, and as such is the logical equivalent of main() or WinMain().
|
||||
/// </summary>
|
||||
public App()
|
||||
{
|
||||
UnhandledException += OnUnhandledException;
|
||||
TaskScheduler.UnobservedTaskException += TaskSchedulerOnUnobservedTaskException;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public IActivatedEventArgs ActivatedEventArgs { get; private set; }
|
||||
|
||||
private async void TaskSchedulerOnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs args)
|
||||
{
|
||||
var exceptionStackTrace = args.Exception.StackTrace;
|
||||
var
|
||||
exceptionHashCode = string.IsNullOrEmpty(exceptionStackTrace)
|
||||
? args.Exception.GetHashCode().ToString()
|
||||
: exceptionStackTrace.GetHashCode().ToString();
|
||||
await
|
||||
ExceptionReportService.Handle(args.Exception.GetType().ToString(), args.Exception.Message,
|
||||
exceptionStackTrace, args.Exception.InnerException.GetType().ToString(), exceptionHashCode);
|
||||
}
|
||||
|
||||
private async void OnUnhandledException(object sender, UnhandledExceptionEventArgs args)
|
||||
{
|
||||
var exceptionStackTrace = string.Empty;
|
||||
try
|
||||
{
|
||||
exceptionStackTrace = args.Exception.StackTrace + "";
|
||||
}
|
||||
// ReSharper disable once EmptyGeneralCatchClause
|
||||
catch { }
|
||||
var exceptionMessage = args.Message;
|
||||
var exceptionType = string.Empty;
|
||||
var innerExceptionType = string.Empty;
|
||||
var exceptionHashCode = string.Empty;
|
||||
if (args.Exception != null)
|
||||
{
|
||||
// Tasks will throw a canceled exception if they get canceled
|
||||
// We don't care, but avoid closing the app
|
||||
if (args.Exception.GetType() == typeof(TaskCanceledException))
|
||||
{
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
if (args.Exception.GetType() == typeof(OperationCanceledException))
|
||||
{
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
if (args.Exception.GetType() == typeof(FileNotFoundException))
|
||||
{
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
// Temporary Workaround for WP10
|
||||
if (args.Exception.GetType() == typeof(ArgumentException))
|
||||
{
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
if (args.Exception.GetType() == typeof(ResponseError))
|
||||
{
|
||||
args.Handled = true;
|
||||
ResponseErrorHandlerService.HandleException((ResponseError)args.Exception);
|
||||
return;
|
||||
}
|
||||
// 0x8000000B, E_BOUNDS, System.Exception, OutOfBoundsException
|
||||
if ((uint)args.Exception.HResult == 0x80004004)
|
||||
{
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
// 0x80072EE7, ERROR_WINHTTP_NAME_NOT_RESOLVED, The server name or address could not be resolved
|
||||
if ((uint)args.Exception.HResult == 0x80072EE7)
|
||||
{
|
||||
args.Handled = true;
|
||||
var resourceLoader = Container.Resolve<IResourceLoader>();
|
||||
var dialogService = Container.Resolve<DialogService>();
|
||||
var dialog = new ContentDialog
|
||||
{
|
||||
Title = resourceLoader.GetString("AnErrorHasOccurred"),
|
||||
Content = new TextBlock
|
||||
{
|
||||
Text = resourceLoader.GetString("ServerNameOrAddressCouldNotBeResolved"),
|
||||
TextWrapping = TextWrapping.WrapWholeWords,
|
||||
Margin = new Thickness(0, 20, 0, 0)
|
||||
},
|
||||
PrimaryButtonText = resourceLoader.GetString("OK")
|
||||
};
|
||||
await dialogService.ShowAsync(dialog);
|
||||
return;
|
||||
}
|
||||
exceptionType = args.Exception.GetType().ToString();
|
||||
if (args.Exception.InnerException != null)
|
||||
{
|
||||
innerExceptionType = args.Exception.InnerException.GetType().ToString();
|
||||
}
|
||||
exceptionHashCode = string.IsNullOrEmpty(exceptionStackTrace)
|
||||
? args.Exception.GetHashCode().ToString()
|
||||
: exceptionStackTrace.GetHashCode().ToString();
|
||||
}
|
||||
if (args.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
args.Handled = true;
|
||||
await
|
||||
ExceptionReportService.Handle(exceptionType, exceptionMessage, exceptionStackTrace,
|
||||
innerExceptionType, exceptionHashCode);
|
||||
}
|
||||
|
||||
protected override UIElement CreateShell(Frame rootFrame)
|
||||
{
|
||||
var shell = Container.Resolve<AppShell>();
|
||||
shell.SetContentFrame(rootFrame);
|
||||
return shell;
|
||||
}
|
||||
|
||||
protected override void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
|
||||
{
|
||||
base.OnShareTargetActivated(args);
|
||||
|
||||
OnShareTargetActivatedsyncAsync(args);
|
||||
}
|
||||
|
||||
private async Task OnShareTargetActivatedsyncAsync(ShareTargetActivatedEventArgs args)
|
||||
{
|
||||
var fileTokens = new List<string>();
|
||||
var sorageItems = await args.ShareOperation.Data.GetStorageItemsAsync();
|
||||
StorageApplicationPermissions.FutureAccessList.Clear();
|
||||
foreach (var storageItem in sorageItems)
|
||||
{
|
||||
if (storageItem.IsOfType(StorageItemTypes.File))
|
||||
{
|
||||
var token = StorageApplicationPermissions.FutureAccessList.Add(storageItem);
|
||||
fileTokens.Add(token);
|
||||
}
|
||||
}
|
||||
args.ShareOperation.ReportDataRetrieved();
|
||||
|
||||
var options = new LauncherOptions()
|
||||
{
|
||||
TargetApplicationPackageFamilyName = Package.Current.Id.FamilyName
|
||||
};
|
||||
|
||||
ValueSet inputData = new ValueSet
|
||||
{
|
||||
{ "FileTokens", fileTokens.ToArray() }
|
||||
};
|
||||
Uri uri = new Uri("nextcloud:///share");
|
||||
await Launcher.LaunchUriAsync(uri, options, inputData);
|
||||
|
||||
args.ShareOperation.ReportCompleted();
|
||||
}
|
||||
|
||||
//TODO: Find out, why this is not working on WP10
|
||||
//SEE: https://github.com/nextcloud/windows-universal/issues/32
|
||||
//protected override void OnFileSavePickerActivated(FileSavePickerActivatedEventArgs args)
|
||||
//{
|
||||
// base.OnFileSavePickerActivated(args);
|
||||
// OnActivated(args);
|
||||
//}
|
||||
//protected override void OnCachedFileUpdaterActivated(CachedFileUpdaterActivatedEventArgs args)
|
||||
//{
|
||||
// base.OnCachedFileUpdaterActivated(args);
|
||||
// OnActivated(args);
|
||||
//}
|
||||
|
||||
protected override void OnFileActivated(FileActivatedEventArgs args)
|
||||
{
|
||||
base.OnFileActivated(args);
|
||||
OnActivated(args);
|
||||
}
|
||||
|
||||
protected override async Task OnActivateApplicationAsync(IActivatedEventArgs args)
|
||||
{
|
||||
ActivatedEventArgs = args;
|
||||
await base.OnActivateApplicationAsync(args);
|
||||
|
||||
// Remove unnecessary notifications whenever the app is used.
|
||||
ToastNotificationManager.History.RemoveGroup(ToastNotificationService.SYNCACTION);
|
||||
|
||||
// Handle toast activation
|
||||
if (args is ToastNotificationActivatedEventArgs)
|
||||
{
|
||||
var toastActivationArgs = args as ToastNotificationActivatedEventArgs;
|
||||
// Parse the query string
|
||||
QueryString query = QueryString.Parse(toastActivationArgs.Argument);
|
||||
// See what action is being requested
|
||||
switch (query["action"])
|
||||
{
|
||||
// Nothing to do here
|
||||
case ToastNotificationService.SYNCACTION:
|
||||
NavigationService.Navigate(PageToken.DirectoryList.ToString(), null);
|
||||
break;
|
||||
// Open Conflict Page
|
||||
case ToastNotificationService.SYNCONFLICTACTION:
|
||||
ToastNotificationManager.History.RemoveGroup(ToastNotificationService.SYNCONFLICTACTION);
|
||||
NavigationService.Navigate(PageToken.SyncConflict.ToString(), null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (args.Kind == ActivationKind.Protocol)
|
||||
{
|
||||
var protocolArgs = args as ProtocolActivatedEventArgs;
|
||||
|
||||
if (protocolArgs.Uri.AbsolutePath == "/share")
|
||||
{
|
||||
var pageParameters = new ShareTargetPageParameters()
|
||||
{
|
||||
ActivationKind = ActivationKind.ShareTarget,
|
||||
FileTokens = new List<string>()
|
||||
};
|
||||
|
||||
if (protocolArgs.Data.ContainsKey("FileTokens"))
|
||||
{
|
||||
foreach (var token in protocolArgs.Data["FileTokens"] as string[])
|
||||
{
|
||||
pageParameters.FileTokens.Add(token);
|
||||
}
|
||||
}
|
||||
|
||||
CheckSettingsAndContinue(PageToken.ShareTarget, pageParameters);
|
||||
}
|
||||
}
|
||||
else if (args.Kind == ActivationKind.FileSavePicker || args.Kind == ActivationKind.CachedFileUpdater)
|
||||
{
|
||||
CheckSettingsAndContinue(PageToken.FileSavePicker, null);
|
||||
}
|
||||
else if (args.Kind == ActivationKind.File)
|
||||
{
|
||||
if (args is FileActivatedEventArgs activatedEventArgs)
|
||||
{
|
||||
var sorageItems = activatedEventArgs.Files;
|
||||
var pageParameters = new ShareTargetPageParameters()
|
||||
{
|
||||
//ShareOperation = activatedEventArgs.ShareOperation,
|
||||
ActivationKind = ActivationKind.ShareTarget,
|
||||
FileTokens = new List<string>()
|
||||
};
|
||||
StorageApplicationPermissions.FutureAccessList.Clear();
|
||||
foreach (var storageItem in sorageItems)
|
||||
{
|
||||
var token = StorageApplicationPermissions.FutureAccessList.Add(storageItem);
|
||||
pageParameters.FileTokens.Add(token);
|
||||
}
|
||||
CheckSettingsAndContinue(PageToken.ShareTarget, pageParameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override Task OnSuspendingApplicationAsync()
|
||||
{
|
||||
var task = base.OnSuspendingApplicationAsync();
|
||||
// Stop Background Sync Tasks
|
||||
List<FolderSyncInfo> activeSyncs = SyncDbUtils.GetActiveSyncInfos();
|
||||
foreach (var fsi in activeSyncs)
|
||||
{
|
||||
ToastNotificationService.ShowSyncSuspendedNotification(fsi);
|
||||
SyncDbUtils.UnlockFolderSyncInfo(fsi);
|
||||
}
|
||||
return task;
|
||||
}
|
||||
|
||||
protected override Task OnInitializeAsync(IActivatedEventArgs args)
|
||||
{
|
||||
Container.RegisterInstance(new DialogService());
|
||||
Container.RegisterInstance<IResourceLoader>(new ResourceLoaderAdapter(new ResourceLoader()));
|
||||
var task = base.OnInitializeAsync(args);
|
||||
DeviceGestureService.GoBackRequested += DeviceGestureServiceOnGoBackRequested;
|
||||
// Just count total app starts
|
||||
SettingsService.Instance.LocalSettings.AppTotalRuns = SettingsService.Instance.LocalSettings.AppTotalRuns + 1;
|
||||
// Count app starts after last update
|
||||
var currentVersion =
|
||||
$"{Package.Current.Id.Version.Major}.{Package.Current.Id.Version.Minor}.{Package.Current.Id.Version.Build}.{Package.Current.Id.Version.Revision}";
|
||||
if (currentVersion == SettingsService.Instance.LocalSettings.AppRunsAfterLastUpdateVersion)
|
||||
{
|
||||
SettingsService.Instance.LocalSettings.AppRunsAfterLastUpdate = SettingsService.Instance.LocalSettings.AppRunsAfterLastUpdate + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
SettingsService.Instance.LocalSettings.AppRunsAfterLastUpdateVersion = currentVersion;
|
||||
SettingsService.Instance.LocalSettings.AppRunsAfterLastUpdate = 1;
|
||||
SettingsService.Instance.LocalSettings.ShowUpdateMessage = true;
|
||||
}
|
||||
MigrationService.Instance.StartMigration();
|
||||
return task;
|
||||
}
|
||||
|
||||
protected override Task OnLaunchApplicationAsync(LaunchActivatedEventArgs args)
|
||||
{
|
||||
// Ensure the current window is active
|
||||
Window.Current.Activate();
|
||||
// Remove unnecessary notifications whenever the app is used.
|
||||
ToastNotificationManager.History.RemoveGroup(ToastNotificationService.SYNCACTION);
|
||||
PinStartPageParameters pageParameters = null;
|
||||
if (!string.IsNullOrEmpty(args?.Arguments))
|
||||
{
|
||||
var tmpResourceInfo = JsonConvert.DeserializeObject<ResourceInfo>(args.Arguments);
|
||||
if (tmpResourceInfo != null)
|
||||
{
|
||||
pageParameters = new PinStartPageParameters()
|
||||
{
|
||||
ResourceInfo = tmpResourceInfo,
|
||||
PageTarget = tmpResourceInfo.IsDirectory ? PageToken.DirectoryList : PageToken.FileInfo
|
||||
};
|
||||
}
|
||||
}
|
||||
if (SettingsService.Instance.LocalSettings.UseWindowsHello)
|
||||
{
|
||||
CheckSettingsAndContinue(PageToken.Verification, pageParameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckSettingsAndContinue(pageParameters?.PageTarget ?? PageToken.DirectoryList, pageParameters);
|
||||
}
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void CheckSettingsAndContinue(PageToken requestedPage, IPageParameters pageParameters)
|
||||
{
|
||||
if (
|
||||
string.IsNullOrEmpty(SettingsService.Instance.LocalSettings.ServerAddress) ||
|
||||
string.IsNullOrEmpty(SettingsService.Instance.LocalSettings.Username)
|
||||
)
|
||||
{
|
||||
NavigationService.Navigate(PageToken.Login.ToString(), null);
|
||||
}
|
||||
else
|
||||
{
|
||||
var vault = new PasswordVault();
|
||||
IReadOnlyList<PasswordCredential> credentialList = null;
|
||||
try
|
||||
{
|
||||
credentialList = vault.FindAllByResource(SettingsService.Instance.LocalSettings.ServerAddress);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
var credential = credentialList?.FirstOrDefault(item => item.UserName.Equals(SettingsService.Instance.LocalSettings.Username));
|
||||
if (credential != null)
|
||||
{
|
||||
credential.RetrievePassword();
|
||||
if (!string.IsNullOrEmpty(credential.Password))
|
||||
{
|
||||
NavigationService.Navigate(requestedPage.ToString(), pageParameters?.Serialize());
|
||||
}
|
||||
else
|
||||
{
|
||||
NavigationService.Navigate(
|
||||
PageToken.Login.ToString(),
|
||||
null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NavigationService.Navigate(
|
||||
PageToken.Login.ToString(),
|
||||
null);
|
||||
}
|
||||
}
|
||||
// Ensure the current window is active
|
||||
Window.Current.Activate();
|
||||
}
|
||||
|
||||
private void DeviceGestureServiceOnGoBackRequested(object sender, DeviceGestureEventArgs e)
|
||||
{
|
||||
var appShell = (AppShell)Window.Current.Content;
|
||||
var contentFrame = (Frame)appShell.GetContentFrame();
|
||||
var page = (SessionStateAwarePage)contentFrame.Content;
|
||||
var revertable = page?.DataContext as IRevertState;
|
||||
if (revertable == null || !revertable.CanRevertState())
|
||||
{
|
||||
return;
|
||||
}
|
||||
e.Handled = true;
|
||||
e.Cancel = true;
|
||||
revertable.RevertState();
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel;
|
||||
using Microsoft.Practices.Unity;
|
||||
using Prism.Unity.Windows;
|
||||
using Prism.Windows.AppModel;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
using Windows.Security.Credentials;
|
||||
using Windows.Storage.AccessCache;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Newtonsoft.Json;
|
||||
using NextcloudApp.Models;
|
||||
using NextcloudApp.Services;
|
||||
using NextcloudApp.Utils;
|
||||
using NextcloudClient.Exceptions;
|
||||
using NextcloudClient.Types;
|
||||
using Prism.Windows.Mvvm;
|
||||
using Microsoft.QueryStringDotNET;
|
||||
using Windows.UI.Notifications;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.System;
|
||||
using Windows.Storage;
|
||||
|
||||
namespace NextcloudApp
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides application-specific behavior to supplement the default Application class.
|
||||
/// </summary>
|
||||
sealed partial class App : PrismUnityApplication
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the singleton application object. This is the first line of authored code
|
||||
/// executed, and as such is the logical equivalent of main() or WinMain().
|
||||
/// </summary>
|
||||
public App()
|
||||
{
|
||||
UnhandledException += OnUnhandledException;
|
||||
TaskScheduler.UnobservedTaskException += TaskSchedulerOnUnobservedTaskException;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public IActivatedEventArgs ActivatedEventArgs { get; private set; }
|
||||
|
||||
private async void TaskSchedulerOnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs args)
|
||||
{
|
||||
var exceptionStackTrace = args.Exception.StackTrace;
|
||||
var
|
||||
exceptionHashCode = string.IsNullOrEmpty(exceptionStackTrace)
|
||||
? args.Exception.GetHashCode().ToString()
|
||||
: exceptionStackTrace.GetHashCode().ToString();
|
||||
await
|
||||
ExceptionReportService.Handle(args.Exception.GetType().ToString(), args.Exception.Message,
|
||||
exceptionStackTrace, args.Exception.InnerException.GetType().ToString(), exceptionHashCode);
|
||||
}
|
||||
|
||||
private async void OnUnhandledException(object sender, UnhandledExceptionEventArgs args)
|
||||
{
|
||||
var exceptionStackTrace = string.Empty;
|
||||
try
|
||||
{
|
||||
exceptionStackTrace = args.Exception.StackTrace + "";
|
||||
}
|
||||
// ReSharper disable once EmptyGeneralCatchClause
|
||||
catch { }
|
||||
var exceptionMessage = args.Message;
|
||||
var exceptionType = string.Empty;
|
||||
var innerExceptionType = string.Empty;
|
||||
var exceptionHashCode = string.Empty;
|
||||
if (args.Exception != null)
|
||||
{
|
||||
// Tasks will throw a canceled exception if they get canceled
|
||||
// We don't care, but avoid closing the app
|
||||
if (args.Exception.GetType() == typeof(TaskCanceledException))
|
||||
{
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
if (args.Exception.GetType() == typeof(OperationCanceledException))
|
||||
{
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
if (args.Exception.GetType() == typeof(FileNotFoundException))
|
||||
{
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
// Temporary Workaround for WP10
|
||||
if (args.Exception.GetType() == typeof(ArgumentException))
|
||||
{
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
if (args.Exception.GetType() == typeof(ResponseError))
|
||||
{
|
||||
args.Handled = true;
|
||||
ResponseErrorHandlerService.HandleException((ResponseError)args.Exception);
|
||||
return;
|
||||
}
|
||||
// 0x8000000B, E_BOUNDS, System.Exception, OutOfBoundsException
|
||||
if ((uint)args.Exception.HResult == 0x80004004)
|
||||
{
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
// 0x80072EE7, ERROR_WINHTTP_NAME_NOT_RESOLVED, The server name or address could not be resolved
|
||||
if ((uint)args.Exception.HResult == 0x80072EE7)
|
||||
{
|
||||
args.Handled = true;
|
||||
var resourceLoader = Container.Resolve<IResourceLoader>();
|
||||
var dialogService = Container.Resolve<DialogService>();
|
||||
var dialog = new ContentDialog
|
||||
{
|
||||
Title = resourceLoader.GetString("AnErrorHasOccurred"),
|
||||
Content = new TextBlock
|
||||
{
|
||||
Text = resourceLoader.GetString("ServerNameOrAddressCouldNotBeResolved"),
|
||||
TextWrapping = TextWrapping.WrapWholeWords,
|
||||
Margin = new Thickness(0, 20, 0, 0)
|
||||
},
|
||||
PrimaryButtonText = resourceLoader.GetString("OK")
|
||||
};
|
||||
await dialogService.ShowAsync(dialog);
|
||||
return;
|
||||
}
|
||||
exceptionType = args.Exception.GetType().ToString();
|
||||
if (args.Exception.InnerException != null)
|
||||
{
|
||||
innerExceptionType = args.Exception.InnerException.GetType().ToString();
|
||||
}
|
||||
exceptionHashCode = string.IsNullOrEmpty(exceptionStackTrace)
|
||||
? args.Exception.GetHashCode().ToString()
|
||||
: exceptionStackTrace.GetHashCode().ToString();
|
||||
}
|
||||
if (args.Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
args.Handled = true;
|
||||
await
|
||||
ExceptionReportService.Handle(exceptionType, exceptionMessage, exceptionStackTrace,
|
||||
innerExceptionType, exceptionHashCode);
|
||||
}
|
||||
|
||||
protected override UIElement CreateShell(Frame rootFrame)
|
||||
{
|
||||
var shell = Container.Resolve<AppShell>();
|
||||
shell.SetContentFrame(rootFrame);
|
||||
return shell;
|
||||
}
|
||||
|
||||
protected override void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
|
||||
{
|
||||
base.OnShareTargetActivated(args);
|
||||
|
||||
OnShareTargetActivatedsyncAsync(args);
|
||||
}
|
||||
|
||||
private async void OnShareTargetActivatedsyncAsync(ShareTargetActivatedEventArgs args)
|
||||
{
|
||||
var sorageItems = await args.ShareOperation.Data.GetStorageItemsAsync();
|
||||
StorageApplicationPermissions.FutureAccessList.Clear();
|
||||
args.ShareOperation.ReportDataRetrieved();
|
||||
|
||||
var frame = new Frame();
|
||||
frame.Navigate(typeof(ShareTarget), null);
|
||||
Window.Current.Content = frame;
|
||||
Window.Current.Activate();
|
||||
|
||||
var options = new LauncherOptions()
|
||||
{
|
||||
TargetApplicationPackageFamilyName = Package.Current.Id.FamilyName,
|
||||
DesiredRemainingView = Windows.UI.ViewManagement.ViewSizePreference.UseNone
|
||||
};
|
||||
|
||||
var inputData = new ValueSet
|
||||
{
|
||||
{ "FileTokens", (from storageItem in sorageItems where storageItem.IsOfType(StorageItemTypes.File) select StorageApplicationPermissions.FutureAccessList.Add(storageItem)).ToArray() }
|
||||
};
|
||||
var uri = new Uri("nextcloud:///share");
|
||||
|
||||
await Launcher.LaunchUriAsync(uri, options, inputData);
|
||||
|
||||
args.ShareOperation.ReportCompleted();
|
||||
}
|
||||
|
||||
//TODO: Find out, why this is not working on WP10
|
||||
//SEE: https://github.com/nextcloud/windows-universal/issues/32
|
||||
//protected override void OnFileSavePickerActivated(FileSavePickerActivatedEventArgs args)
|
||||
//{
|
||||
// base.OnFileSavePickerActivated(args);
|
||||
// OnActivated(args);
|
||||
//}
|
||||
//protected override void OnCachedFileUpdaterActivated(CachedFileUpdaterActivatedEventArgs args)
|
||||
//{
|
||||
// base.OnCachedFileUpdaterActivated(args);
|
||||
// OnActivated(args);
|
||||
//}
|
||||
|
||||
protected override void OnFileActivated(FileActivatedEventArgs args)
|
||||
{
|
||||
base.OnFileActivated(args);
|
||||
OnActivated(args);
|
||||
}
|
||||
|
||||
protected override async Task OnActivateApplicationAsync(IActivatedEventArgs args)
|
||||
{
|
||||
ActivatedEventArgs = args;
|
||||
await base.OnActivateApplicationAsync(args);
|
||||
|
||||
// Remove unnecessary notifications whenever the app is used.
|
||||
ToastNotificationManager.History.RemoveGroup(ToastNotificationService.SYNCACTION);
|
||||
|
||||
// Handle toast activation
|
||||
var eventArgs = args as ToastNotificationActivatedEventArgs;
|
||||
if (eventArgs != null)
|
||||
{
|
||||
var toastActivationArgs = eventArgs;
|
||||
// Parse the query string
|
||||
var query = QueryString.Parse(toastActivationArgs.Argument);
|
||||
// See what action is being requested
|
||||
switch (query["action"])
|
||||
{
|
||||
// Nothing to do here
|
||||
case ToastNotificationService.SYNCACTION:
|
||||
NavigationService.Navigate(PageToken.DirectoryList.ToString(), null);
|
||||
break;
|
||||
// Open Conflict Page
|
||||
case ToastNotificationService.SYNCONFLICTACTION:
|
||||
ToastNotificationManager.History.RemoveGroup(ToastNotificationService.SYNCONFLICTACTION);
|
||||
NavigationService.Navigate(PageToken.SyncConflict.ToString(), null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else switch (args.Kind)
|
||||
{
|
||||
case ActivationKind.Protocol:
|
||||
var protocolArgs = args as ProtocolActivatedEventArgs;
|
||||
|
||||
if (protocolArgs != null && protocolArgs.Uri.AbsolutePath == "/share")
|
||||
{
|
||||
var pageParameters = new ShareTargetPageParameters()
|
||||
{
|
||||
ActivationKind = ActivationKind.ShareTarget,
|
||||
FileTokens = new List<string>()
|
||||
};
|
||||
|
||||
if (protocolArgs.Data.ContainsKey("FileTokens"))
|
||||
{
|
||||
var tokens = protocolArgs.Data["FileTokens"] as string[];
|
||||
if (tokens != null)
|
||||
{
|
||||
foreach (var token in tokens)
|
||||
{
|
||||
pageParameters.FileTokens.Add(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CheckSettingsAndContinue(PageToken.ShareTarget, pageParameters);
|
||||
}
|
||||
break;
|
||||
case ActivationKind.FileSavePicker:
|
||||
case ActivationKind.CachedFileUpdater:
|
||||
CheckSettingsAndContinue(PageToken.FileSavePicker, null);
|
||||
break;
|
||||
case ActivationKind.File:
|
||||
if (args is FileActivatedEventArgs activatedEventArgs)
|
||||
{
|
||||
var sorageItems = activatedEventArgs.Files;
|
||||
var pageParameters = new ShareTargetPageParameters()
|
||||
{
|
||||
//ShareOperation = activatedEventArgs.ShareOperation,
|
||||
ActivationKind = ActivationKind.ShareTarget,
|
||||
FileTokens = new List<string>()
|
||||
};
|
||||
StorageApplicationPermissions.FutureAccessList.Clear();
|
||||
foreach (var storageItem in sorageItems)
|
||||
{
|
||||
var token = StorageApplicationPermissions.FutureAccessList.Add(storageItem);
|
||||
pageParameters.FileTokens.Add(token);
|
||||
}
|
||||
CheckSettingsAndContinue(PageToken.ShareTarget, pageParameters);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override Task OnSuspendingApplicationAsync()
|
||||
{
|
||||
var task = base.OnSuspendingApplicationAsync();
|
||||
// Stop Background Sync Tasks
|
||||
List<FolderSyncInfo> activeSyncs = SyncDbUtils.GetActiveSyncInfos();
|
||||
foreach (var fsi in activeSyncs)
|
||||
{
|
||||
ToastNotificationService.ShowSyncSuspendedNotification(fsi);
|
||||
SyncDbUtils.UnlockFolderSyncInfo(fsi);
|
||||
}
|
||||
return task;
|
||||
}
|
||||
|
||||
protected override Task OnInitializeAsync(IActivatedEventArgs args)
|
||||
{
|
||||
Container.RegisterInstance(new DialogService());
|
||||
Container.RegisterInstance<IResourceLoader>(new ResourceLoaderAdapter(new ResourceLoader()));
|
||||
var task = base.OnInitializeAsync(args);
|
||||
DeviceGestureService.GoBackRequested += DeviceGestureServiceOnGoBackRequested;
|
||||
// Just count total app starts
|
||||
SettingsService.Instance.LocalSettings.AppTotalRuns = SettingsService.Instance.LocalSettings.AppTotalRuns + 1;
|
||||
// Count app starts after last update
|
||||
var currentVersion =
|
||||
$"{Package.Current.Id.Version.Major}.{Package.Current.Id.Version.Minor}.{Package.Current.Id.Version.Build}.{Package.Current.Id.Version.Revision}";
|
||||
if (currentVersion == SettingsService.Instance.LocalSettings.AppRunsAfterLastUpdateVersion)
|
||||
{
|
||||
SettingsService.Instance.LocalSettings.AppRunsAfterLastUpdate = SettingsService.Instance.LocalSettings.AppRunsAfterLastUpdate + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
SettingsService.Instance.LocalSettings.AppRunsAfterLastUpdateVersion = currentVersion;
|
||||
SettingsService.Instance.LocalSettings.AppRunsAfterLastUpdate = 1;
|
||||
SettingsService.Instance.LocalSettings.ShowUpdateMessage = true;
|
||||
}
|
||||
MigrationService.Instance.StartMigration();
|
||||
return task;
|
||||
}
|
||||
|
||||
protected override Task OnLaunchApplicationAsync(LaunchActivatedEventArgs args)
|
||||
{
|
||||
// Ensure the current window is active
|
||||
Window.Current.Activate();
|
||||
// Remove unnecessary notifications whenever the app is used.
|
||||
ToastNotificationManager.History.RemoveGroup(ToastNotificationService.SYNCACTION);
|
||||
PinStartPageParameters pageParameters = null;
|
||||
if (!string.IsNullOrEmpty(args?.Arguments))
|
||||
{
|
||||
var tmpResourceInfo = JsonConvert.DeserializeObject<ResourceInfo>(args.Arguments);
|
||||
if (tmpResourceInfo != null)
|
||||
{
|
||||
pageParameters = new PinStartPageParameters()
|
||||
{
|
||||
ResourceInfo = tmpResourceInfo,
|
||||
PageTarget = tmpResourceInfo.IsDirectory ? PageToken.DirectoryList : PageToken.FileInfo
|
||||
};
|
||||
}
|
||||
}
|
||||
if (SettingsService.Instance.LocalSettings.UseWindowsHello)
|
||||
{
|
||||
CheckSettingsAndContinue(PageToken.Verification, pageParameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckSettingsAndContinue(pageParameters?.PageTarget ?? PageToken.DirectoryList, pageParameters);
|
||||
}
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void CheckSettingsAndContinue(PageToken requestedPage, IPageParameters pageParameters)
|
||||
{
|
||||
if (
|
||||
string.IsNullOrEmpty(SettingsService.Instance.LocalSettings.ServerAddress) ||
|
||||
string.IsNullOrEmpty(SettingsService.Instance.LocalSettings.Username)
|
||||
)
|
||||
{
|
||||
NavigationService.Navigate(PageToken.Login.ToString(), null);
|
||||
}
|
||||
else
|
||||
{
|
||||
var vault = new PasswordVault();
|
||||
IReadOnlyList<PasswordCredential> credentialList = null;
|
||||
try
|
||||
{
|
||||
credentialList = vault.FindAllByResource(SettingsService.Instance.LocalSettings.ServerAddress);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
var credential = credentialList?.FirstOrDefault(item => item.UserName.Equals(SettingsService.Instance.LocalSettings.Username));
|
||||
if (credential != null)
|
||||
{
|
||||
credential.RetrievePassword();
|
||||
if (!string.IsNullOrEmpty(credential.Password))
|
||||
{
|
||||
NavigationService.Navigate(requestedPage.ToString(), pageParameters?.Serialize());
|
||||
}
|
||||
else
|
||||
{
|
||||
NavigationService.Navigate(
|
||||
PageToken.Login.ToString(),
|
||||
null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NavigationService.Navigate(
|
||||
PageToken.Login.ToString(),
|
||||
null);
|
||||
}
|
||||
}
|
||||
// Ensure the current window is active
|
||||
Window.Current.Activate();
|
||||
}
|
||||
|
||||
private void DeviceGestureServiceOnGoBackRequested(object sender, DeviceGestureEventArgs e)
|
||||
{
|
||||
var appShell = (AppShell)Window.Current.Content;
|
||||
var contentFrame = (Frame)appShell.GetContentFrame();
|
||||
var page = (SessionStateAwarePage)contentFrame.Content;
|
||||
var revertable = page?.DataContext as IRevertState;
|
||||
if (revertable == null || !revertable.CanRevertState())
|
||||
{
|
||||
return;
|
||||
}
|
||||
e.Handled = true;
|
||||
e.Cancel = true;
|
||||
revertable.RevertState();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -168,6 +168,9 @@
|
|||
<Compile Include="Services\ToastNotificationService.cs" />
|
||||
<Compile Include="Services\UpdateNotificationService.cs" />
|
||||
<Compile Include="Services\VerificationService.cs" />
|
||||
<Compile Include="ShareTarget.xaml.cs">
|
||||
<DependentUpon>ShareTarget.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Utils\DebugTraceListener.cs" />
|
||||
<Compile Include="Utils\DefaultSettingValueAttribute.cs" />
|
||||
<Compile Include="Utils\GroupMode.cs" />
|
||||
|
@ -281,6 +284,10 @@
|
|||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="ShareTarget.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Themes\Fonts.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
|
|
@ -27,13 +27,7 @@
|
|||
</uap:InitialRotationPreference>
|
||||
</uap:VisualElements>
|
||||
<Extensions>
|
||||
<uap:Extension Category="windows.protocol">
|
||||
<uap:Protocol Name="nextcloud">
|
||||
<uap:Logo>Assets\StoreLogo.png</uap:Logo>
|
||||
<uap:DisplayName>Nextcloud</uap:DisplayName>
|
||||
</uap:Protocol>
|
||||
</uap:Extension>
|
||||
<uap:Extension Category="windows.shareTarget">
|
||||
<uap:Extension Category="windows.shareTarget" EntryPoint="NextcloudApp.ShareTarget">
|
||||
<uap:ShareTarget>
|
||||
<uap:SupportedFileTypes>
|
||||
<uap:SupportsAnyFileType />
|
||||
|
@ -46,6 +40,12 @@
|
|||
<uap:DataFormat>RTF</uap:DataFormat>
|
||||
</uap:ShareTarget>
|
||||
</uap:Extension>
|
||||
<uap:Extension Category="windows.protocol">
|
||||
<uap:Protocol Name="nextcloud">
|
||||
<uap:Logo>Assets\StoreLogo.png</uap:Logo>
|
||||
<uap:DisplayName>Nextcloud</uap:DisplayName>
|
||||
</uap:Protocol>
|
||||
</uap:Extension>
|
||||
</Extensions>
|
||||
</Application>
|
||||
</Applications>
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<Page
|
||||
x:Class="NextcloudApp.ShareTarget"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:NextcloudApp"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<ProgressRing Foreground="White" Width="100" Height="100" IsActive="True" VerticalAlignment="Bottom" Margin="10"/>
|
||||
<TextBlock Grid.Row="1" x:Uid="PrepareForSharing" Text="Prepare for sharing..." VerticalAlignment="Top" HorizontalAlignment="Center" Margin="10"/>
|
||||
</Grid>
|
||||
</Page>
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Data;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
||||
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
|
||||
|
||||
namespace NextcloudApp
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class ShareTarget : Page
|
||||
{
|
||||
public ShareTarget()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -551,4 +551,7 @@ Please try again later.</value>
|
|||
<data name="DirectoryListStatusBarText" xml:space="preserve">
|
||||
<value>Items: {0} (folders: {1} files: {2})</value>
|
||||
</data>
|
||||
<data name="PrepareForSharing" xml:space="preserve">
|
||||
<value>Prepare for sharing...</value>
|
||||
</data>
|
||||
</root>
|
Загрузка…
Ссылка в новой задаче