From 76fc1205a5c7d66c0fcb016facc3d261203ef4d7 Mon Sep 17 00:00:00 2001 From: Egor-Pavshuk Date: Tue, 25 Apr 2023 14:10:18 +0300 Subject: [PATCH 01/11] Add OneDrive auth dialog --- FileManager.Helpers/Constants.cs | 1 + FileManager.Helpers/ControlExtensions.cs | 80 ++ .../FileManager.Helpers.csproj | 1 + FileManager.Models/Dialogs/DialogResult.cs | 11 + FileManager.Models/Enums/OperationResult.cs | 22 + FileManager.Models/FileManager.Models.csproj | 4 + FileManager.Models/Interfaces/IDialog.cs | 17 + .../Interfaces/IWebViewDialog.cs | 4 + FileManager.ViewModels/BaseDialogControl.cs | 228 +++++ .../FileManager.ViewModels.csproj | 5 + FileManager.ViewModels/MainViewModel.cs | 4 + FileManager.ViewModels/OneDriveViewModel.cs | 874 ++++++++++++++++++ FileManager/App.xaml | 11 +- FileManager/App.xaml.cs | 15 +- FileManager/Controlls/WebViewDialog.cs | 54 ++ FileManager/Controlls/WebViewDialog.xaml | 39 + FileManager/FileManager.csproj | 12 + FileManager/Strings/en-US/Resources.resw | 3 + FileManager/Strings/ru-RU/Resources.resw | 3 + FileManager/Views/MainPage.xaml | 1 + FileManager/Views/OneDrivePage.xaml | 62 ++ FileManager/Views/OneDrivePage.xaml.cs | 17 + 22 files changed, 1465 insertions(+), 3 deletions(-) create mode 100644 FileManager.Helpers/ControlExtensions.cs create mode 100644 FileManager.Models/Dialogs/DialogResult.cs create mode 100644 FileManager.Models/Enums/OperationResult.cs create mode 100644 FileManager.Models/Interfaces/IDialog.cs create mode 100644 FileManager.Models/Interfaces/IWebViewDialog.cs create mode 100644 FileManager.ViewModels/BaseDialogControl.cs create mode 100644 FileManager.ViewModels/OneDriveViewModel.cs create mode 100644 FileManager/Controlls/WebViewDialog.cs create mode 100644 FileManager/Controlls/WebViewDialog.xaml create mode 100644 FileManager/Views/OneDrivePage.xaml create mode 100644 FileManager/Views/OneDrivePage.xaml.cs diff --git a/FileManager.Helpers/Constants.cs b/FileManager.Helpers/Constants.cs index f645e4e..2c3fdec 100644 --- a/FileManager.Helpers/Constants.cs +++ b/FileManager.Helpers/Constants.cs @@ -78,5 +78,6 @@ public static class Constants public const string InformationPage = "InformationPage"; public const string GoogleDrivePage = "GoogleDrivePage"; public const string FtpPage = "FtpPage"; + public const string OneDrivePage = "OneDrivePage"; } } diff --git a/FileManager.Helpers/ControlExtensions.cs b/FileManager.Helpers/ControlExtensions.cs new file mode 100644 index 0000000..040d007 --- /dev/null +++ b/FileManager.Helpers/ControlExtensions.cs @@ -0,0 +1,80 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media.Animation; + +namespace FileManager.Helpers +{ + public static class ControlExtensions + { + public static async Task GoToVisualStateAsync(this Control control, FrameworkElement visualStatesHost, string stateGroupName, string stateName) + { + if (control != null) + { + var taskCompletionSource = new TaskCompletionSource(); + + var storyboard = GetStoryboardForVisualState(visualStatesHost, stateGroupName, stateName); + if (storyboard != null) + { + EventHandler handler = null; + handler = (s, e) => + { + storyboard.Completed -= handler; + taskCompletionSource.SetResult(storyboard); + }; + + storyboard.Completed += handler; + } + + VisualStateManager.GoToState(control, stateName, true); + + if (storyboard != null) + { + await taskCompletionSource.Task; + } + } + } + + private static Storyboard GetStoryboardForVisualState(FrameworkElement visualStatesHost, string stateGroupName, string stateName) + { + Storyboard storyboard = null; + + if (visualStatesHost != null) + { + VisualStateGroup stateGroup = null; + var stateGroups = VisualStateManager.GetVisualStateGroups(visualStatesHost); + if (!string.IsNullOrEmpty(stateGroupName)) + { + stateGroup = stateGroups.FirstOrDefault(visualStateGroup => visualStateGroup.Name == stateGroupName); + } + + VisualState state = null; + if (stateGroup != null) + { + state = stateGroup.States.FirstOrDefault(visualState => visualState.Name == stateName); + } + + if (state == null) + { + foreach (var group in stateGroups) + { + state = group.States.FirstOrDefault(visualState => visualState.Name == stateName); + if (state != null) + { + break; + } + } + } + + if (state != null) + { + storyboard = state.Storyboard; + } + } + + return storyboard; + } + } +} \ No newline at end of file diff --git a/FileManager.Helpers/FileManager.Helpers.csproj b/FileManager.Helpers/FileManager.Helpers.csproj index 5222182..8c4554c 100644 --- a/FileManager.Helpers/FileManager.Helpers.csproj +++ b/FileManager.Helpers/FileManager.Helpers.csproj @@ -122,6 +122,7 @@ + diff --git a/FileManager.Models/Dialogs/DialogResult.cs b/FileManager.Models/Dialogs/DialogResult.cs new file mode 100644 index 0000000..a7490a3 --- /dev/null +++ b/FileManager.Models/Dialogs/DialogResult.cs @@ -0,0 +1,11 @@ +using FileManager.Models.Enums; + +namespace FileManager.Models.Dialogs +{ + public class DialogResult + { + public object Value { get; set; } + + public OperationResult OperationResult { get; set; } + } +} \ No newline at end of file diff --git a/FileManager.Models/Enums/OperationResult.cs b/FileManager.Models/Enums/OperationResult.cs new file mode 100644 index 0000000..043a8c3 --- /dev/null +++ b/FileManager.Models/Enums/OperationResult.cs @@ -0,0 +1,22 @@ +namespace FileManager.Models.Enums +{ + public enum OperationResult + { + Canceled, + + Ok, + + /* storage item */ + + Add, + + Remove, + + /*rate dialog*/ + + Rate, + + Feedback + + } +} \ No newline at end of file diff --git a/FileManager.Models/FileManager.Models.csproj b/FileManager.Models/FileManager.Models.csproj index 89060eb..720f1e9 100644 --- a/FileManager.Models/FileManager.Models.csproj +++ b/FileManager.Models/FileManager.Models.csproj @@ -120,9 +120,13 @@ PackageReference + + + + diff --git a/FileManager.Models/Interfaces/IDialog.cs b/FileManager.Models/Interfaces/IDialog.cs new file mode 100644 index 0000000..68c6dbc --- /dev/null +++ b/FileManager.Models/Interfaces/IDialog.cs @@ -0,0 +1,17 @@ +using FileManager.Models.Dialogs; +using System.Threading.Tasks; + +namespace FileManager.Models.Interfaces +{ + public interface IDialog : IDialog + { + Task ShowAsync(T parameter); + } + + public interface IDialog + { + void Dismiss(); + + void OnEnterKeyUp(); + } +} \ No newline at end of file diff --git a/FileManager.Models/Interfaces/IWebViewDialog.cs b/FileManager.Models/Interfaces/IWebViewDialog.cs new file mode 100644 index 0000000..4181746 --- /dev/null +++ b/FileManager.Models/Interfaces/IWebViewDialog.cs @@ -0,0 +1,4 @@ +namespace FileManager.Models.Interfaces +{ + public interface IAuthWebViewDialog : IDialog { } +} diff --git a/FileManager.ViewModels/BaseDialogControl.cs b/FileManager.ViewModels/BaseDialogControl.cs new file mode 100644 index 0000000..b7f7d2e --- /dev/null +++ b/FileManager.ViewModels/BaseDialogControl.cs @@ -0,0 +1,228 @@ +using CommonToolkit.Core.Extensions; +using FileManager.Helpers; +using FileManager.Models.Dialogs; +using FileManager.Models.Enums; +using FileManager.Models.Interfaces; +using System; +using System.Linq; +using System.Threading.Tasks; +using Windows.System; +using Windows.UI; +using Windows.UI.Core; +using Windows.UI.ViewManagement; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Media; + +namespace FileManager.ViewModels +{ + public class BaseDialogControl : Control, IDialog + { + protected const string PopupStatesGroupName = "PopupStates"; + protected const string OpenPopupStateName = "OpenPopupState"; + protected const string ClosedPopupStateName = "ClosedPopupState"; + + protected const string LayoutPanelName = "LayoutRoot"; + protected const string ContentBorderName = "ContentBorder"; + protected const string ContentGridName = "ContentGrid"; + + protected const string CloseButtonName = "CloseButton"; + + private bool isShowing; + + private Panel parentPanel; + private Popup dialogPopup; + + private Button closeButton; + + private Color originalColor; + + private ApplicationView AppView = ApplicationView.GetForCurrentView(); + + public BaseDialogControl() + { + this.Visibility = Visibility.Collapsed; + + this.Loaded += this.OnLoaded; + this.Unloaded += this.OnUnloaded; + } + + protected Panel LayoutPanel { get; private set; } + + protected TaskCompletionSource ApplyTemplateTaskSource { get; } = new TaskCompletionSource(); + + protected TaskCompletionSource DismissTaskSource { get; private set; } + + protected virtual void OnUnloaded(object sender, RoutedEventArgs e) + { + if (this.closeButton != null) + { + this.closeButton.Click -= this.OnCloseButtonClick; + } + } + + protected virtual async void OnLoaded(object sender, RoutedEventArgs e) + { + await this.ApplyTemplateTaskSource.Task; + + if (this.closeButton != null) + { + this.closeButton.Click += this.OnCloseButtonClick; + } + } + + protected override void OnApplyTemplate() + { + this.LayoutPanel = this.GetTemplateChild(LayoutPanelName) as Panel; + this.closeButton = this.GetTemplateChild(CloseButtonName) as Button; + + base.OnApplyTemplate(); + + this.ApplyTemplateTaskSource.TrySetResult(true); + } + + public virtual async Task ShowAsync(T param) + { + if (this.isShowing) + { + throw new InvalidOperationException("The dialog is already shown."); + } + + //originalColor = AppView.TitleBar.ButtonForegroundColor.Value; + //AppView.TitleBar.ButtonForegroundColor = Color.FromArgb(0, 255, 255, 255); + + this.Visibility = Visibility.Visible; + this.isShowing = true; + + Window.Current.CoreWindow.KeyDown += this.OnCoreWindowKeyDown; + + this.DismissTaskSource = new TaskCompletionSource(); + + this.dialogPopup = new Popup { Child = this }; + + this.parentPanel = Window.Current.Content.GetFirstDescendantOfType(); + if (this.parentPanel != null) + { + this.parentPanel.Children.Add(this.dialogPopup); + this.parentPanel.SizeChanged += this.OnParentSizeChanged; + } + + this.dialogPopup.IsOpen = true; + + this.LayoutUpdated += this.OnLayoutUpdated; + + var result = await this.DismissTaskSource.Task; + + await this.CloseAsync(); + + Window.Current.CoreWindow.KeyDown -= this.OnCoreWindowKeyDown; + + return result; + } + + public void Dismiss() + { + this.DismissDialog(); + } + + private async void OnLayoutUpdated(object sender, object e) + { + this.LayoutUpdated -= this.OnLayoutUpdated; + this.ResizeLayoutRoot(); + + this.SetAdditionalLayout(); + + await this.GoToVisualStateAsync(this.LayoutPanel, PopupStatesGroupName, OpenPopupStateName); + + // set focus to opened dialog + this.Focus(FocusState.Programmatic); + } + + protected virtual void SetAdditionalLayout() { } + + protected void ResizeLayoutRoot() + { + if (this.parentPanel != null && this.LayoutPanel != null) + { + this.LayoutPanel.Width = this.parentPanel.ActualWidth; + this.LayoutPanel.Height = this.parentPanel.ActualHeight; + } + } + + protected void InvertResizeLayoutRoot() + { + if (this.parentPanel != null && this.LayoutPanel != null) + { + this.LayoutPanel.Width = this.parentPanel.ActualHeight; + this.LayoutPanel.Height = this.parentPanel.ActualWidth; + } + } + + private void OnParentSizeChanged(object sender, SizeChangedEventArgs sizeChangedEventArgs) + { + if (sizeChangedEventArgs.NewSize != sizeChangedEventArgs.PreviousSize) + { + this.ResizeLayoutRoot(); + } + } + + protected virtual void OnCloseButtonClick(object sender, RoutedEventArgs e) + { + this.DismissDialog(); + } + + private void OnCoreWindowKeyDown(CoreWindow sender, KeyEventArgs e) + { + if (!e.Handled) + { + var lastDailog = VisualTreeHelper.GetOpenPopups(Window.Current).FirstOrDefault(popup => popup.Child is IDialog)?.Child as IDialog; + if (e.VirtualKey == VirtualKey.Escape) + { + lastDailog?.Dismiss(); + } + else if (e.VirtualKey == VirtualKey.Enter) + { + lastDailog?.OnEnterKeyUp(); + } + + e.Handled = true; + } + } + + public virtual void OnEnterKeyUp() { } + + protected virtual void DismissDialog() + { + this.DismissTaskSource.TrySetResult(new DialogResult { OperationResult = OperationResult.Canceled }); + + AppView.TitleBar.ButtonForegroundColor = originalColor; + } + + protected virtual async Task CloseAsync() + { + if (!this.isShowing) + { + throw new InvalidOperationException("The dialog isn't shown, so it can't be closed."); + } + + await this.GoToVisualStateAsync(this.LayoutPanel, PopupStatesGroupName, ClosedPopupStateName); + + this.dialogPopup.IsOpen = false; + this.dialogPopup.Child = null; + + if (this.parentPanel != null) + { + this.parentPanel.Children.Remove(this.dialogPopup); + this.parentPanel.SizeChanged -= this.OnParentSizeChanged; + this.parentPanel = null; + } + + this.dialogPopup = null; + this.Visibility = Visibility.Collapsed; + this.isShowing = false; + + AppView.TitleBar.ButtonForegroundColor = originalColor; + } + } +} \ No newline at end of file diff --git a/FileManager.ViewModels/FileManager.ViewModels.csproj b/FileManager.ViewModels/FileManager.ViewModels.csproj index c5cb91c..47033bd 100644 --- a/FileManager.ViewModels/FileManager.ViewModels.csproj +++ b/FileManager.ViewModels/FileManager.ViewModels.csproj @@ -120,12 +120,14 @@ PackageReference + + @@ -154,6 +156,9 @@ 6.2.14 + + 1.0.0.22 + diff --git a/FileManager.ViewModels/MainViewModel.cs b/FileManager.ViewModels/MainViewModel.cs index 2deb7ab..a24c9a2 100644 --- a/FileManager.ViewModels/MainViewModel.cs +++ b/FileManager.ViewModels/MainViewModel.cs @@ -134,6 +134,10 @@ private void SelectionChanged() CurrentContent = (Page)VMDependencies.Container.Resolve(VMDependencies.Views[Constants.FtpPage]); CurrentTitle = resourceLoader.GetString(Constants.FtpServer); break; + case "6": + CurrentContent = (Page)VMDependencies.Container.Resolve(VMDependencies.Views[Constants.OneDrivePage]); + CurrentTitle = resourceLoader.GetString(Constants.OneDrivePage); + break; default: CurrentContent = (Page)VMDependencies.Container.Resolve(VMDependencies.Views[Constants.MainTitlePage]); CurrentTitle = resourceLoader.GetString(Constants.MainNavigation); diff --git a/FileManager.ViewModels/OneDriveViewModel.cs b/FileManager.ViewModels/OneDriveViewModel.cs new file mode 100644 index 0000000..ac5a4fb --- /dev/null +++ b/FileManager.ViewModels/OneDriveViewModel.cs @@ -0,0 +1,874 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Input; +using Windows.ApplicationModel.Core; +using Windows.ApplicationModel.Resources; +using Windows.Storage; +using Windows.Storage.Pickers; +using Windows.UI; +using Windows.UI.Core; +using Windows.UI.Popups; +using Windows.UI.ViewManagement; +using Windows.UI.Xaml.Controls; +using FileManager.Helpers.Commands; +using FileManager.Helpers.Validation; +using FileManager.Models; +using FileManager.Services; +using FileManager.ViewModels.OnlineFileControls; +using FileManager.Helpers.Factory; +using FileManager.Helpers; +using Autofac; +using FileManager.Dependencies; +using ThirdPartyServices.UWP.AuthorizationServices; +using ThirdPartyServices.Shared.Interfaces; +using ThirdPartyServices.Shared.Models.Enums; +using ThirdPartyServices.Shared.Models; +using ThirdPartyServices.UWP.CloudServices; +using FileManager.Models.Interfaces; +using FileManager.Models.Dialogs; +using System.IO; +using ThirdPartyServices.Shared.Models.Parameters; + +namespace FileManager.ViewModels +{ + public class OneDriveViewModel : BindableBase + { + private const string ClientId = "4d6596ac-0602-49e6-be9e-ed97fdea89f5"; + private const string Secret = "Ofq8Q~ARZDOVNJ12brW9nUkIFEFeJ6eHxnA1-caD"; + private const string GoogleUri = "https://accounts.google.com/o/oauth2/auth?client_id=" + ClientId + "&redirect_uri=" + "https://localhost/" + "&response_type=code&scope=" + Constants.DriveScope; + private const string GoogleDownloadUri = "https://www.googleapis.com/drive/v3/files/"; + private readonly TokenResult tokenResult; + private readonly ResourceLoader stringsResourceLoader; + private readonly Stack openedFoldersId = new Stack(); + private readonly List downloadingFilesId; + private readonly Services.GoogleDriveService googleDriveService; + private string loadingText; + private string errorText; + private string currentFolderId; + private string MicrosoftToken = string.Empty; + private string MicrosoftRefreshToken = string.Empty; + private Uri webViewCurrentSource; + private bool isWebViewVisible; + private bool isCommandPanelVisible; + private bool isLoadingVisible; + private bool isFilesVisible; + private bool isBackButtonAvailable; + private bool isErrorVisible; + private Collection storageFiles; + private OnlineFileControlViewModel selectedGridItem; + private ResourceLoader themeResourceLoader; + private IMicrosoftAuthorizationService microsoftAuthService; + private IOneDriveCloudService oneDriveCloudService; + private ICommand navigationStartingCommand; + private ICommand doubleClickedCommand; + private ICommand getParentCommand; + private ICommand downloadFileCommand; + private ICommand uploadFileCommand; + private ICommand deleteFileCommand; + private ICommand createNewFolderCommand; + private ICommand renameFileCommand; + private ICommand itemClickedCommand; + private readonly MicrosoftAuthParams MicrosoftParams = new MicrosoftAuthParams() + { + ClientId = "4d6596ac-0602-49e6-be9e-ed97fdea89f5", + ClientSecret = "k9k8Q~BzgRKh59sc.C8lZtCyGexcf~NNGdxBudtN", //"Ofq8Q~ARZDOVNJ12brW9nUkIFEFeJ6eHxnA1-caD", + RedirectUri = "http://localhost:3000", + ScopeType = MicrosoftScope.OneDrive + }; + + public Uri WebViewCurrentSource + { + get => webViewCurrentSource; + set + { + if (webViewCurrentSource != value) + { + webViewCurrentSource = value; + OnPropertyChanged(); + } + } + } + public bool IsWebViewVisible + { + get => isWebViewVisible; + set + { + if (isWebViewVisible != value) + { + isWebViewVisible = value; + OnPropertyChanged(); + } + } + } + public bool IsCommandPanelVisible + { + get => isCommandPanelVisible; + set + { + if (isCommandPanelVisible != value) + { + isCommandPanelVisible = value; + OnPropertyChanged(); + } + } + } + public bool IsLoadingVisible + { + get => isLoadingVisible; + set + { + if (isLoadingVisible != value) + { + isLoadingVisible = value; + OnPropertyChanged(); + } + } + } + public bool IsFilesVisible + { + get => isFilesVisible; + set + { + if (isFilesVisible != value) + { + isFilesVisible = value; + OnPropertyChanged(); + } + } + } + public bool IsBackButtonAvailable + { + get => isBackButtonAvailable; + set + { + if (isBackButtonAvailable != value) + { + isBackButtonAvailable = value; + OnPropertyChanged(); + } + } + } + public bool IsErrorVisible + { + get => isErrorVisible; + set + { + if (isErrorVisible != value) + { + isErrorVisible = value; + OnPropertyChanged(); + } + } + } + public string LoadingText + { + get => loadingText; + set + { + if (loadingText != value) + { + loadingText = value; + OnPropertyChanged(); + } + } + } + public string ErrorText + { + get => errorText; + set + { + if (errorText != value) + { + errorText = value; + OnPropertyChanged(); + } + } + } + public OnlineFileControlViewModel SelectedGridItem + { + get => selectedGridItem; + set + { + if (selectedGridItem != value) + { + selectedGridItem = value; + OnPropertyChanged(); + } + } + } + public Collection StorageFiles + { + get => storageFiles; + set + { + if (storageFiles != value) + { + storageFiles = value; + OnPropertyChanged(); + } + } + } + public ICommand NavigationStartingCommand + { + get => navigationStartingCommand; + set + { + if (navigationStartingCommand != value) + { + navigationStartingCommand = value; + OnPropertyChanged(); + } + } + } + public ICommand DoubleClickedCommand + { + get => doubleClickedCommand; + set + { + if (doubleClickedCommand != value) + { + doubleClickedCommand = value; + OnPropertyChanged(); + } + } + } + public ICommand GetParentCommand + { + get => getParentCommand; + set + { + if (getParentCommand != value) + { + getParentCommand = value; + OnPropertyChanged(); + } + } + } + public ICommand DownloadFileCommand + { + get => downloadFileCommand; + set + { + if (downloadFileCommand != value) + { + downloadFileCommand = value; + OnPropertyChanged(); + } + } + } + public ICommand UploadFileCommand + { + get => uploadFileCommand; + set + { + if (uploadFileCommand != value) + { + uploadFileCommand = value; + OnPropertyChanged(); + } + } + } + public ICommand DeleteFileCommand + { + get => deleteFileCommand; + set + { + if (deleteFileCommand != value) + { + deleteFileCommand = value; + OnPropertyChanged(); + } + } + } + public ICommand CreateNewFolderCommand + { + get => createNewFolderCommand; + set + { + if (createNewFolderCommand != value) + { + createNewFolderCommand = value; + OnPropertyChanged(); + } + } + } + public ICommand RenameFileCommand + { + get => renameFileCommand; + set + { + if (renameFileCommand != value) + { + renameFileCommand = value; + OnPropertyChanged(); + } + } + } + public ICommand ItemClickedCommand + { + get => itemClickedCommand; + set + { + if (itemClickedCommand != value) + { + itemClickedCommand = value; + OnPropertyChanged(); + } + } + } + + public OneDriveViewModel() + { + tokenResult = new TokenResult(); + ChangeColorMode(settings, this); + downloadingFilesId = new List(); + googleDriveService = new Services.GoogleDriveService(); + if (Windows.System.Profile.AnalyticsInfo.VersionInfo.DeviceFamily == "Windows.Xbox") + { + ItemClickedCommand = new RelayCommand(OpenFolder); + DoubleClickedCommand = new RelayCommand((o) => { }); + } + else + { + DoubleClickedCommand = new RelayCommand(OpenFolder); + ItemClickedCommand = new RelayCommand((o) => { }); + } + NavigationStartingCommand = new RelayCommand(NavigationStarting); + DoubleClickedCommand = new RelayCommand(OpenFolder); + GetParentCommand = new RelayCommand(GetParent); + DownloadFileCommand = new RelayCommand(DownloadFileAsync); + UploadFileCommand = new RelayCommand(UploadFileAsync); + DeleteFileCommand = new RelayCommand(DeleteFileAsync); + CreateNewFolderCommand = new RelayCommand(CreateNewFolderAsync); + RenameFileCommand = new RelayCommand(RenameFileAsync); + stringsResourceLoader = ResourceLoader.GetForCurrentView(Constants.StringResources); + oneDriveCloudService = VMDependencies.Container.Resolve(); + microsoftAuthService = VMDependencies.Container.Resolve(); //Factory.CommonFactory.GetInstance(); + IsWebViewVisible = true; + _ = CheckInternetConnectionAsync(); + //WebViewCurrentSource = new Uri(GoogleUri); + LoadingText = stringsResourceLoader.GetString(Constants.Loading); + ErrorText = stringsResourceLoader.GetString(Constants.ConnectionErrorContent); + + OneDriveAuthAsync(); + } + + protected override void ChangeColorMode(UISettings uiSettings, object sender) + { + var currentBackgroundColor = uiSettings?.GetColorValue(UIColorType.Background); + string resourcePath; + if (backgroundColor != currentBackgroundColor || storageFiles == null) + { + if (currentBackgroundColor == Colors.Black) + { + resourcePath = string.Join('\\', Constants.Resources, Constants.ImagesDark); + backgroundColor = Colors.Black; + } + else + { + resourcePath = string.Join('\\', Constants.Resources, Constants.ImagesLight); + backgroundColor = Colors.White; + } + themeResourceLoader = ResourceLoader.GetForViewIndependentUse(resourcePath); + if (storageFiles != null) + { + CoreApplication.MainView.CoreWindow.Dispatcher + .RunAsync(CoreDispatcherPriority.Normal, + () => + { + foreach (var storageFile in storageFiles) + { + storageFile.ChangeColorMode(themeResourceLoader); + } + }).AsTask().ConfigureAwait(true); + } + } + } + + private async Task CheckInternetConnectionAsync() + { + string result = await googleDriveService.CheckInternetConnectionAsync(GoogleUri).ConfigureAwait(true); + if (result == Constants.Failed) + { + IsErrorVisible = true; + IsCommandPanelVisible = false; + IsWebViewVisible = false; + } + } + + private async void OneDriveAuthAsync() + { + var dialog = VMDependencies.Container.Resolve();// Factory.CommonFactory.GetInstance(); + var dialogResult = dialog.ShowAsync(null); //ShowDialogAsync(dialog, null); + var token = await microsoftAuthService.AuthorizeAsync(MicrosoftParams); + MicrosoftToken = token.Token; + MicrosoftRefreshToken = token.RefreshToken; + + if (token != null && !string.IsNullOrEmpty(token.Token)) + { + var md = new MessageDialog(MicrosoftToken); + await md.ShowAsync(); + } + dialog.Dismiss(); + } + + private async void NavigationStarting(object args) + { + var webView = (WebViewNavigationStartingEventArgs)args; + string exchangeCode; + string errorContent; + string errorTitle; + if (webView != null) + { + if (webView.Uri.ToString().StartsWith("https://localhost/", StringComparison.Ordinal)) + { + string navigationUri = webView.Uri.ToString(); + if (navigationUri.Contains("code=", StringComparison.Ordinal)) + { + exchangeCode = navigationUri.Split('=')[1].Split('&')[0]; + webView.Cancel = true; + IsWebViewVisible = false; + IsCommandPanelVisible = true; + await ExchangeCodeOnTokenAsync(exchangeCode).ConfigureAwait(true); + _ = GetItemsAsync().ConfigureAwait(true); + } + else + { + errorContent = stringsResourceLoader.GetString(Constants.ResponseError); + errorTitle = stringsResourceLoader.GetString(Constants.Failed); + _ = ShowMessageDialogAsync(errorContent, errorTitle); + } + } + else if (webView.Uri.ToString().StartsWith("https://support.google.com", StringComparison.Ordinal)) + { + webView.Cancel = true; + IsWebViewVisible = false; + IsErrorVisible = true; + } + } + } + + private async Task ExchangeCodeOnTokenAsync(string exchangeCode) + { + string errorContent; + string errorTitle; + string result = await googleDriveService.ExchangeCodeOnTokenAsync(exchangeCode, ClientId, Secret, tokenResult).ConfigureAwait(true); + if (result == Constants.Failed) + { + errorContent = stringsResourceLoader.GetString(Constants.ConnectionErrorContent); + errorTitle = stringsResourceLoader.GetString(Constants.ConnectionError); + _ = ShowMessageDialogAsync(errorContent, errorTitle); + } + } + + private async Task GetItemsAsync(string folderId = "") + { + IsFilesVisible = false; + IsLoadingVisible = true; + _ = CheckInternetConnectionAsync(); + List responseFiles = await GetFilesFromGoogleDriveAsync(folderId).ConfigureAwait(true); + List driveFiles = new List(); + foreach (var driveFile in responseFiles) + { + var viewModel = OnlineFileControlCreator.CreateFileControl(themeResourceLoader, driveFile.Id, driveFile.Name, driveFile.MimeType); + if (viewModel.Type == Constants.Folder) + { + var lastIndexOfFolder = driveFiles.FindLastIndex(f => f.Type == Constants.Folder); + driveFiles.Insert(lastIndexOfFolder + 1, viewModel); + } + else + { + driveFiles.Add(viewModel); + } + } + StorageFiles = new Collection(driveFiles); + CheckFilesForDownloading(); + IsLoadingVisible = false; + IsFilesVisible = true; + } + + private async Task> GetFilesFromGoogleDriveAsync(string folderId) + { + List driveFiles; + string q; + string errorContent; + string errorTitle; + if (DateTime.Now.Subtract(tokenResult.LastRefreshTime).Seconds >= int.Parse(tokenResult.Expires_in)) + { + await RefreshTokenAsync().ConfigureAwait(true); + } + if (string.IsNullOrEmpty(folderId)) + { + currentFolderId = await GetRootFolderIdAsync().ConfigureAwait(true); + folderId = currentFolderId; + } + q = $"\"{folderId}\"+in+parents and trashed=false&fields=files(*)"; + driveFiles = await googleDriveService.GetFilesAsync(q, tokenResult.Token_type, tokenResult.Access_token).ConfigureAwait(true); + if (driveFiles == null) + { + errorContent = stringsResourceLoader.GetString(Constants.ConnectionErrorContent); + errorTitle = stringsResourceLoader.GetString(Constants.ConnectionError); + _ = ShowMessageDialogAsync(errorContent, errorTitle); + driveFiles = new List(); + } + return driveFiles; + } + + private async Task GetRootFolderIdAsync() + { + string result = await googleDriveService.GetRootFolderIdAsync(tokenResult.Token_type, tokenResult.Access_token).ConfigureAwait(true); + if (result == Constants.Failed) + { + string errorContent = stringsResourceLoader.GetString(Constants.ConnectionErrorContent); + string errorTitle = stringsResourceLoader.GetString(Constants.ConnectionError); + _ = ShowMessageDialogAsync(errorContent, errorTitle); + } + return result; + } + + private void CheckFilesForDownloading() + { + foreach (var file in storageFiles) + { + if (downloadingFilesId.Exists(id => id == file.Id)) + { + file.IsDownloading = true; + file.DownloadStatus = stringsResourceLoader.GetString(Constants.DownloadingText); + } + } + } + + private async Task RefreshTokenAsync() + { + string result; + string errorContent; + string errorTitle; + result = await googleDriveService.RefreshTokenAsync(ClientId, Secret, tokenResult).ConfigureAwait(true); + if (result == Constants.Failed) + { + errorContent = stringsResourceLoader.GetString(Constants.ConnectionErrorContent); + errorTitle = stringsResourceLoader.GetString(Constants.ConnectionError); + _ = ShowMessageDialogAsync(errorContent, errorTitle); + } + } + + private void OpenFolder(object sender) + { + if (sender != null) + { + var gridItems = (GridView)sender; + if (gridItems.SelectedItem is OnlineFileControlViewModel selectedItem && !string.IsNullOrEmpty(selectedItem.DisplayName) && selectedItem.Type == Constants.Folder) + { + if (openedFoldersId.Count == 0) + { + IsBackButtonAvailable = true; + } + openedFoldersId.Push(currentFolderId); + currentFolderId = selectedItem.Id; + GetItemsAsync(currentFolderId).ConfigureAwait(true); + } + } + + } + + private void GetParent(object sender) + { + if (openedFoldersId.Count != 0) + { + currentFolderId = openedFoldersId.Pop(); + GetItemsAsync(currentFolderId).ConfigureAwait(true); + if (openedFoldersId.Count == 0) + { + IsBackButtonAvailable = false; + } + } + } + + private async void DownloadFileAsync(object sender) + { + string result; + string errorContent; + string errorTitle; + string fileId = selectedGridItem.Id; + if (selectedGridItem != null && !string.IsNullOrEmpty(selectedGridItem.DisplayName) && selectedGridItem.Type != Constants.Folder) + { + StorageFolder downloadFolder = await GetDestinationFolderAsync().ConfigureAwait(true); + if (DateTime.Now.Subtract(tokenResult.LastRefreshTime).Seconds >= int.Parse(tokenResult.Expires_in)) + { + await RefreshTokenAsync().ConfigureAwait(true); + } + SelectedGridItem.IsDownloading = true; + SelectedGridItem.DownloadStatus = stringsResourceLoader.GetString(Constants.DownloadingText); + downloadingFilesId.Add(SelectedGridItem.Id); + Uri source = new Uri(string.Join("", GoogleDownloadUri, + selectedGridItem.Id, "?alt=media")); + + result = await googleDriveService.DownloadFileAsync(source, downloadFolder, selectedGridItem.DisplayName, + tokenResult.Token_type, tokenResult.Access_token).ConfigureAwait(true); + + //var file = await oneDriveCloudService.DownloadItemAsync(new DownloadParams + //{ + // Token = MicrosoftToken, + // FileName = path.Text + //}); + + //try + //{ + // var tmp = await DownloadsFolder.CreateFileAsync(file.Name, CreationCollisionOption.GenerateUniqueName); + // using (file.StreamContent) + // { + // await FileIO.WriteBytesAsync(tmp, (file.StreamContent as MemoryStream).ToArray()); + // } + //} + //catch (Exception) { } + + downloadingFilesId.Remove(fileId); + var downloadingFile = storageFiles.FirstOrDefault(f => f.Id == fileId); + if (downloadingFile != null) + { + if (result == Constants.Success) + { + downloadingFile.DownloadStatus = stringsResourceLoader.GetString(Constants.DownloadCompleted); + } + else + { + downloadingFile.DownloadStatus = stringsResourceLoader.GetString(Constants.Failed); + errorContent = stringsResourceLoader.GetString(Constants.ConnectionErrorContent); + errorTitle = stringsResourceLoader.GetString(Constants.ConnectionError); + _ = ShowMessageDialogAsync(errorContent, errorTitle); + } + _ = CloseDownloadingAsync(downloadingFile); + } + } + } + private async Task GetDestinationFolderAsync() + { + var picker = new FolderPicker + { + ViewMode = PickerViewMode.Thumbnail, + SuggestedStartLocation = PickerLocationId.Downloads + }; + picker.FileTypeFilter.Add("*"); + return await picker.PickSingleFolderAsync(); + } + + private async Task CloseDownloadingAsync(OnlineFileControlViewModel file) + { + await Task.Delay(3000).ConfigureAwait(true); + file.IsDownloading = false; + file.DownloadStatus = string.Empty; + } + + private async void UploadFileAsync(object sender) + { + string result; + string errorContent; + string errorTitle; + string folderId = currentFolderId; + var parents = new Collection() + { + currentFolderId + }; + var picker = new FileOpenPicker + { + ViewMode = PickerViewMode.Thumbnail, + SuggestedStartLocation = PickerLocationId.Downloads + }; + picker.FileTypeFilter.Add("*"); + StorageFile uploadFile = await picker.PickSingleFileAsync(); + if (uploadFile != null) + { + if (DateTime.Now.Subtract(tokenResult.LastRefreshTime).Seconds >= int.Parse(tokenResult.Expires_in)) + { + await RefreshTokenAsync().ConfigureAwait(true); + } + result = await googleDriveService.UploadFileAsync(uploadFile, parents, tokenResult.Access_token).ConfigureAwait(true); + if (result == Constants.Success) + { + if (folderId == currentFolderId) + { + _ = GetItemsAsync(currentFolderId); + } + } + else + { + errorContent = stringsResourceLoader.GetString(Constants.ConnectionErrorContent); + errorTitle = stringsResourceLoader.GetString(Constants.ConnectionError); + _ = ShowMessageDialogAsync(errorContent, errorTitle); + } + } + } + + private async void DeleteFileAsync(object sender) + { + string folderId = currentFolderId; + string result; + string errorContent; + string errorTitle; + if (selectedGridItem != null && !string.IsNullOrEmpty(selectedGridItem.DisplayName)) + { + var contentDialog = new ContentDialog() + { + Title = stringsResourceLoader.GetString(Constants.Confirmation), + Content = stringsResourceLoader.GetString(Constants.DeleteConfirmText) + $" \"{selectedGridItem.DisplayName}\"?", + PrimaryButtonText = stringsResourceLoader.GetString(Constants.YesButton), + CloseButtonText = stringsResourceLoader.GetString(Constants.CancelButton), + }; + var confirmationResult = await contentDialog.ShowAsync(); + if (confirmationResult == ContentDialogResult.Primary) + { + if (DateTime.Now.Subtract(tokenResult.LastRefreshTime).Seconds >= int.Parse(tokenResult.Expires_in)) + { + await RefreshTokenAsync().ConfigureAwait(true); + } + result = await googleDriveService.DeleteFileAsync(selectedGridItem.Id, tokenResult.Access_token).ConfigureAwait(true); + if (result == Constants.Success) + { + if (currentFolderId == folderId) + { + _ = GetItemsAsync(currentFolderId).ConfigureAwait(true); + } + } + else + { + errorContent = stringsResourceLoader.GetString(Constants.ConnectionErrorContent); + errorTitle = stringsResourceLoader.GetString(Constants.ConnectionError); + _ = ShowMessageDialogAsync(errorContent, errorTitle); + } + } + } + } + + private async void CreateNewFolderAsync(object sender) + { + string dialogTitle = stringsResourceLoader.GetString(Constants.NewFolder); + string placeHolder = stringsResourceLoader.GetString(Constants.PlaceHolderFileName); + string inputText = string.Empty; + string primaryButton = stringsResourceLoader.GetString(Constants.CreateButton); + string secondaryButton = stringsResourceLoader.GetString(Constants.CancelButton); + string result; + string errorContent; + string errorTitle; + var parents = new Collection() + { + currentFolderId + }; + var contentDialog = CreateInputContentDialog(dialogTitle, placeHolder, inputText, primaryButton, secondaryButton); + var dialogResult = await contentDialog.ShowAsync(); + var gridItem = (ContentDialogControlViewModel)contentDialog.DataContext; + var folderName = gridItem.InputText; + folderName = ValidateItemName(folderName); + if (dialogResult == ContentDialogResult.Primary && !string.IsNullOrEmpty(folderName)) + { + if (DateTime.Now.Subtract(tokenResult.LastRefreshTime).Seconds >= int.Parse(tokenResult.Expires_in)) + { + await RefreshTokenAsync().ConfigureAwait(true); + } + result = await googleDriveService.CreateNewFolderAsync(folderName, parents, tokenResult.Access_token).ConfigureAwait(true); + if (result == Constants.Success) + { + _ = GetItemsAsync(currentFolderId); + } + else + { + errorContent = stringsResourceLoader.GetString(Constants.ConnectionErrorContent); + errorTitle = stringsResourceLoader.GetString(Constants.ConnectionError); + _ = ShowMessageDialogAsync(errorContent, errorTitle); + } + } + else if (dialogResult == ContentDialogResult.Primary) + { + errorContent = stringsResourceLoader.GetString(Constants.InvalidInput); + errorTitle = stringsResourceLoader.GetString(Constants.InputError); + _ = ShowMessageDialogAsync(errorContent, errorTitle); + } + } + + private async void RenameFileAsync(object sender) + { + string dialogTitle = stringsResourceLoader.GetString(Constants.Rename); + string placeHolder = stringsResourceLoader.GetString(Constants.PlaceHolderFileName); + string primaryButton = stringsResourceLoader.GetString(Constants.YesButton); + string secondaryButton = stringsResourceLoader.GetString(Constants.CancelButton); + string result; + if (selectedGridItem != null) + { + string inputText = selectedGridItem.DisplayName; + string errorContent; + string errorTitle; + var contentDialog = CreateInputContentDialog(dialogTitle, placeHolder, inputText, primaryButton, secondaryButton); + var dialogResult = await contentDialog.ShowAsync(); + var gridItem = (ContentDialogControlViewModel)contentDialog.DataContext; + var fileName = gridItem.InputText; + fileName = ValidateItemName(fileName); + + if (dialogResult == ContentDialogResult.Primary && !string.IsNullOrEmpty(fileName)) + { + if (DateTime.Now.Subtract(tokenResult.LastRefreshTime).Seconds >= int.Parse(tokenResult.Expires_in)) + { + await RefreshTokenAsync().ConfigureAwait(true); + } + result = await googleDriveService.RenameFileAsync(selectedGridItem.Id, fileName, tokenResult.Access_token).ConfigureAwait(true); + if (result == Constants.Success) + { + _ = GetItemsAsync(currentFolderId); + } + else + { + errorContent = stringsResourceLoader.GetString(Constants.ConnectionErrorContent); + errorTitle = stringsResourceLoader.GetString(Constants.ConnectionError); + _ = ShowMessageDialogAsync(errorContent, errorTitle); + } + } + else if (dialogResult == ContentDialogResult.Primary) + { + errorContent = stringsResourceLoader.GetString(Constants.InvalidInput); + errorTitle = stringsResourceLoader.GetString(Constants.InputError); + _ = ShowMessageDialogAsync(errorContent, errorTitle); + } + } + } + private async Task ShowMessageDialogAsync(string content, string title) + { + var messageDialog = new MessageDialog(content) + { + Title = title + }; + await messageDialog.ShowAsync(); + } + private ContentDialog CreateInputContentDialog(string title, string placeHolder, string inputText, string primaryButton, string secondaryButton) + { + var parameters = new List() + { + new NamedParameter("title", title), + new NamedParameter("placeHolder", placeHolder), + new NamedParameter("primaryButtonText", primaryButton), + new NamedParameter("secondaryButtonText", secondaryButton), + new NamedParameter("inputText", inputText), + }; + var contentDialog = (ContentDialog)VMDependencies.Container.Resolve(VMDependencies.Views["ContentDialogControl"]); + contentDialog.DataContext = VMDependencies.Container.Resolve(parameters); + return contentDialog; + } + private string ValidateItemName(string itemName) + { + string result = string.Empty; + if (ItemNameValidation.Validate(itemName)) + { + while (itemName.EndsWith(' ')) + { + itemName = itemName.Remove(itemName.Length - 1); + } + while (itemName.StartsWith(' ')) + { + itemName = itemName.Remove(0, 1); + } + result = itemName; + } + return result; + } + } +} diff --git a/FileManager/App.xaml b/FileManager/App.xaml index 6cfcd7e..b66a013 100644 --- a/FileManager/App.xaml +++ b/FileManager/App.xaml @@ -3,7 +3,14 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:FileManager"> - - + + + + 16 + + + + + diff --git a/FileManager/App.xaml.cs b/FileManager/App.xaml.cs index a8a7bb7..927ab23 100644 --- a/FileManager/App.xaml.cs +++ b/FileManager/App.xaml.cs @@ -12,6 +12,11 @@ using FileManager.Views; using FileManager.Dependencies; using FileManager.Controlls; +using FileManager.Models.Interfaces; +using ThirdPartyServices.UWP.AuthorizationServices; +using ThirdPartyServices.Shared.Interfaces; +using ThirdPartyServices.UWP.CloudServices; +using ThirdPartyServices.UWP.DataAccess; namespace FileManager { @@ -34,6 +39,7 @@ public App() } private IContainer ConfigureServices() { + ThirdPartyService.Instance.InitializeThirdPartySevices(); var containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType() .AsSelf().WithParameters(new List @@ -60,6 +66,8 @@ private IContainer ConfigureServices() .AsSelf(); containerBuilder.RegisterType() .AsSelf(); + containerBuilder.RegisterType() + .AsSelf(); containerBuilder.RegisterType().AsSelf(); containerBuilder.RegisterType().AsSelf(); containerBuilder.RegisterType().AsSelf(); @@ -69,9 +77,14 @@ private IContainer ConfigureServices() containerBuilder.RegisterType().AsSelf(); containerBuilder.RegisterType().AsSelf(); containerBuilder.RegisterType().AsSelf(); + containerBuilder.RegisterType().AsSelf(); + + containerBuilder.RegisterType().As(); // + containerBuilder.RegisterType().As(); // + containerBuilder.RegisterType().As(); // VMDependencies.ConfigureServices(typeof(MainPage), typeof(MainTitlePage), typeof(FtpPage), typeof(GoogleDrivePage), typeof(InformationPage), typeof(MusicsLibraryPage), typeof(PicturesLibraryPage), typeof(VideosLibraryPage), - typeof(ContentDialogControl)); + typeof(ContentDialogControl), typeof(OneDrivePage)); var container = containerBuilder.Build(); return container; } diff --git a/FileManager/Controlls/WebViewDialog.cs b/FileManager/Controlls/WebViewDialog.cs new file mode 100644 index 0000000..1279932 --- /dev/null +++ b/FileManager/Controlls/WebViewDialog.cs @@ -0,0 +1,54 @@ +using FileManager.ViewModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml; +using FileManager.Models.Interfaces; + +namespace FileManager.Controlls +{ + [TemplatePart(Name = CancelButtonName, Type = typeof(Button))] + public class WebViewDialog : BaseDialogControl, IAuthWebViewDialog + { + #region Template + private const string CancelButtonName = "CancelButton"; + + private Button cancelButton; + #endregion + + public WebViewDialog() : base() + { + DefaultStyleKey = typeof(WebViewDialog); + Visibility = Visibility.Collapsed; + } + + protected override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + cancelButton = GetTemplateChild(CancelButtonName) as Button; + } + + protected override void OnLoaded(object sender, RoutedEventArgs e) + { + base.OnLoaded(sender, e); + + if (cancelButton != null) + { + cancelButton.Click += OnCancelled; + } + } + + private void OnCancelled(object sender, RoutedEventArgs e) + { + if (cancelButton != null) + { + base.DismissDialog(); + } + } + } +} diff --git a/FileManager/Controlls/WebViewDialog.xaml b/FileManager/Controlls/WebViewDialog.xaml new file mode 100644 index 0000000..be6bc75 --- /dev/null +++ b/FileManager/Controlls/WebViewDialog.xaml @@ -0,0 +1,39 @@ + + + + diff --git a/FileManager/FileManager.csproj b/FileManager/FileManager.csproj index 1c13e20..34aa8a8 100644 --- a/FileManager/FileManager.csproj +++ b/FileManager/FileManager.csproj @@ -132,9 +132,13 @@ FileControl.xaml + FtpPage.xaml + + OneDrivePage.xaml + GoogleDrivePage.xaml @@ -216,10 +220,18 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + MSBuild:Compile Designer + + MSBuild:Compile + Designer + MSBuild:Compile Designer diff --git a/FileManager/Strings/en-US/Resources.resw b/FileManager/Strings/en-US/Resources.resw index 9cb500f..3fd1419 100644 --- a/FileManager/Strings/en-US/Resources.resw +++ b/FileManager/Strings/en-US/Resources.resw @@ -189,6 +189,9 @@ New folder + + OneDrive + Enter file name diff --git a/FileManager/Strings/ru-RU/Resources.resw b/FileManager/Strings/ru-RU/Resources.resw index b9af8b6..85dfbe7 100644 --- a/FileManager/Strings/ru-RU/Resources.resw +++ b/FileManager/Strings/ru-RU/Resources.resw @@ -189,6 +189,9 @@ Новая папка + + OneDrive + Введите название diff --git a/FileManager/Views/MainPage.xaml b/FileManager/Views/MainPage.xaml index ab833b1..d067d2a 100644 --- a/FileManager/Views/MainPage.xaml +++ b/FileManager/Views/MainPage.xaml @@ -27,6 +27,7 @@ + diff --git a/FileManager/Views/OneDrivePage.xaml b/FileManager/Views/OneDrivePage.xaml new file mode 100644 index 0000000..f7af843 --- /dev/null +++ b/FileManager/Views/OneDrivePage.xaml @@ -0,0 +1,62 @@ + + + + + + + + + + +