From b40d85c707dfddbe4faa7e7b5316ac851559ab29 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Wed, 26 Oct 2016 20:47:48 +0200 Subject: [PATCH] wip: new Start Page, async loading, P5 support --- .gitignore | 1 - GitHubVS.sln | 44 ++++++++- src/DesignTimeStyleHelper/MainWindow.xaml.cs | 2 +- .../ViewModels/RepositoryCloneViewModel.cs | 41 +++++++- .../Extensions/ServiceProviderExtensions.cs | 52 +++------- src/GitHub.Exports/Services/IMenuProvider.cs | 2 +- .../Settings/generated/IPackageSettings.cs | 30 ++++++ src/GitHub.Extensions/TaskExtensions.cs | 15 +++ .../Base/EnsureLoggedInSection.cs | 2 +- .../Connect/GitHubConnectSection.cs | 2 +- .../Connect/GitHubInvitationSection.cs | 2 +- .../Sync/GitHubPublishSection.cs | 4 +- .../GitHub.VisualStudio.csproj | 30 ++++-- .../GitHub.VisualStudio.vsct | 6 ++ src/GitHub.VisualStudio/GitHubPackage.cs | 96 ++++++++++++++----- .../Menus/AddConnection.cs | 15 +-- src/GitHub.VisualStudio/Menus/CopyLink.cs | 26 ++--- src/GitHub.VisualStudio/Menus/CreateGist.cs | 23 ++--- src/GitHub.VisualStudio/Menus/LinkMenuBase.cs | 16 ++-- .../{Base => Menus}/MenuBase.cs | 56 ++++------- src/GitHub.VisualStudio/Menus/MenuProvider.cs | 23 +++-- src/GitHub.VisualStudio/Menus/OpenLink.cs | 23 ++--- .../Menus/OpenPullRequests.cs | 5 +- .../Menus/ShowGitHubPane.cs | 7 +- .../Services/UIProvider.cs | 81 +++++++++------- .../Services/UsageTracker.cs | 49 +++++----- .../Settings/generated/PackageSettingsGen.cs | 57 +++++++++++ .../UI/Views/GitHubPaneViewModel.cs | 2 +- submodules/externalpackages/StartPage | 2 +- 29 files changed, 459 insertions(+), 255 deletions(-) create mode 100644 src/GitHub.Exports/Settings/generated/IPackageSettings.cs rename src/GitHub.VisualStudio/{Base => Menus}/MenuBase.cs (66%) create mode 100644 src/GitHub.VisualStudio/Settings/generated/PackageSettingsGen.cs diff --git a/.gitignore b/.gitignore index 7660f4211..c7c50193b 100644 --- a/.gitignore +++ b/.gitignore @@ -239,4 +239,3 @@ WiX.Toolset.DummyFile.txt nunit-UnitTests.xml nunit-TrackingCollectionTests.xml GitHubVS.sln.DotSettings -**/generated/*.cs diff --git a/GitHubVS.sln b/GitHubVS.sln index 46b5b6733..f8dac70cb 100644 --- a/GitHubVS.sln +++ b/GitHubVS.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.25807.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitHub.VisualStudio", "src\GitHub.VisualStudio\GitHub.VisualStudio.csproj", "{11569514-5AE5-4B5B-92A2-F10B0967DE5F}" EndProject @@ -107,6 +107,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitHub.TeamFoundation.15", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitHub.VisualStudio.UI", "src\GitHub.VisualStudio.UI\GitHub.VisualStudio.UI.csproj", "{D1DFBB0C-B570-4302-8F1E-2E3A19C41961}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Subpackages", "Subpackages", "{7F25BDD5-474F-4EC1-A624-ED946B91F34E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitHub.StartPage.Preview5", "submodules\externalpackages\StartPage\preview5\GitHub.StartPage.Preview5.csproj", "{1BC94B6A-B021-4207-A70E-936EE272AD3E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitHub.StartPage.Preview4", "submodules\externalpackages\StartPage\preview4\GitHub.StartPage.Preview4.csproj", "{1BC94B6A-B021-4207-A70E-936EE272AD3D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -542,6 +548,38 @@ Global {D1DFBB0C-B570-4302-8F1E-2E3A19C41961}.XamlDesign|Any CPU.Build.0 = Debug|Any CPU {D1DFBB0C-B570-4302-8F1E-2E3A19C41961}.XamlDesign|x86.ActiveCfg = Release|Any CPU {D1DFBB0C-B570-4302-8F1E-2E3A19C41961}.XamlDesign|x86.Build.0 = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3E}.Debug|x86.ActiveCfg = Debug|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3E}.Debug|x86.Build.0 = Debug|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3E}.Publish|Any CPU.ActiveCfg = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3E}.Publish|Any CPU.Build.0 = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3E}.Publish|x86.ActiveCfg = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3E}.Publish|x86.Build.0 = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3E}.Release|Any CPU.Build.0 = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3E}.Release|x86.ActiveCfg = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3E}.Release|x86.Build.0 = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3E}.XamlDesign|Any CPU.ActiveCfg = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3E}.XamlDesign|Any CPU.Build.0 = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3E}.XamlDesign|x86.ActiveCfg = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3E}.XamlDesign|x86.Build.0 = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3D}.Debug|x86.ActiveCfg = Debug|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3D}.Debug|x86.Build.0 = Debug|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3D}.Publish|Any CPU.ActiveCfg = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3D}.Publish|Any CPU.Build.0 = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3D}.Publish|x86.ActiveCfg = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3D}.Publish|x86.Build.0 = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3D}.Release|Any CPU.Build.0 = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3D}.Release|x86.ActiveCfg = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3D}.Release|x86.Build.0 = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3D}.XamlDesign|Any CPU.ActiveCfg = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3D}.XamlDesign|Any CPU.Build.0 = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3D}.XamlDesign|x86.ActiveCfg = Release|Any CPU + {1BC94B6A-B021-4207-A70E-936EE272AD3D}.XamlDesign|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -566,5 +604,7 @@ Global {0EC8DBA1-D745-4EE5-993A-6026440EC3BF} = {1E7F7253-A6AF-43C4-A955-37BEDDA01AF9} {DD99FD0F-82F6-4C30-930E-4A1D0DF01D65} = {1E7F7253-A6AF-43C4-A955-37BEDDA01AB9} {7B835A7D-CF94-45E8-B191-96F5A4FE26A8} = {8A7DA2E7-262B-4581-807A-1C45CE79CDFD} + {1BC94B6A-B021-4207-A70E-936EE272AD3E} = {7F25BDD5-474F-4EC1-A624-ED946B91F34E} + {1BC94B6A-B021-4207-A70E-936EE272AD3D} = {7F25BDD5-474F-4EC1-A624-ED946B91F34E} EndGlobalSection EndGlobal diff --git a/src/DesignTimeStyleHelper/MainWindow.xaml.cs b/src/DesignTimeStyleHelper/MainWindow.xaml.cs index 9ca122416..0e52d5a34 100644 --- a/src/DesignTimeStyleHelper/MainWindow.xaml.cs +++ b/src/DesignTimeStyleHelper/MainWindow.xaml.cs @@ -47,7 +47,7 @@ namespace DesignTimeStyleHelper void ShowDialog(UIControllerFlow flow) { - var ui = App.ServiceProvider.GetExportedValue(); + var ui = App.ServiceProvider.GetService(); var factory = ui.GetService(); var d = factory.UIControllerFactory.CreateExport(); diff --git a/src/GitHub.App/ViewModels/RepositoryCloneViewModel.cs b/src/GitHub.App/ViewModels/RepositoryCloneViewModel.cs index a97c24931..c5ae9ffac 100644 --- a/src/GitHub.App/ViewModels/RepositoryCloneViewModel.cs +++ b/src/GitHub.App/ViewModels/RepositoryCloneViewModel.cs @@ -53,7 +53,46 @@ namespace GitHub.ViewModels IUsageTracker usageTracker) : this(connectionRepositoryHostMap.CurrentRepositoryHost, repositoryCloneService, operatingSystem, notificationService, usageTracker) { } - + + public RepositoryCloneViewModel( + IRepositoryHost repositoryHost, + IRepositoryModel repositoryToClone, + IRepositoryCloneService cloneService, + IOperatingSystem operatingSystem, + INotificationService notificationService, + IUsageTracker usageTracker) + { + this.repositoryHost = repositoryHost; + this.cloneService = cloneService; + this.operatingSystem = operatingSystem; + this.notificationService = notificationService; + this.usageTracker = usageTracker; + this.SelectedRepository = repositoryToClone; + + Title = string.Format(CultureInfo.CurrentCulture, Resources.CloneTitle, repositoryHost.Title); + + var baseRepositoryPath = this.WhenAnyValue(x => x.BaseRepositoryPath); + + BaseRepositoryPathValidator = ReactivePropertyValidator.ForObservable(baseRepositoryPath) + .IfNullOrEmpty(Resources.RepositoryCreationClonePathEmpty) + .IfTrue(x => x.Length > 200, Resources.RepositoryCreationClonePathTooLong) + .IfContainsInvalidPathChars(Resources.RepositoryCreationClonePathInvalidCharacters) + .IfPathNotRooted(Resources.RepositoryCreationClonePathInvalid) + .IfTrue(IsAlreadyRepoAtPath, Resources.RepositoryNameValidatorAlreadyExists); + + var canCloneObservable = this.WhenAny( + x => x.SelectedRepository, + x => x.BaseRepositoryPathValidator.ValidationResult.IsValid, + (x, y) => x.Value != null && y.Value); + canClone = canCloneObservable.ToProperty(this, x => x.CanClone); + CloneCommand = ReactiveCommand.CreateAsyncObservable(canCloneObservable, OnCloneRepository); + + browseForDirectoryCommand.Subscribe(_ => ShowBrowseForDirectoryDialog()); + this.WhenAny(x => x.BaseRepositoryPathValidator.ValidationResult, x => x.Value) + .Subscribe(); + BaseRepositoryPath = cloneService.DefaultClonePath; + } + public RepositoryCloneViewModel( IRepositoryHost repositoryHost, IRepositoryCloneService cloneService, diff --git a/src/GitHub.Exports/Extensions/ServiceProviderExtensions.cs b/src/GitHub.Exports/Extensions/ServiceProviderExtensions.cs index 6b4d0d68a..d85f76558 100644 --- a/src/GitHub.Exports/Extensions/ServiceProviderExtensions.cs +++ b/src/GitHub.Exports/Extensions/ServiceProviderExtensions.cs @@ -9,8 +9,6 @@ namespace GitHub.Extensions { public static class IServiceProviderExtensions { - static IUIProvider cachedUIProvider = null; - /// /// Safe variant of GetService that doesn't throw exceptions if the service is /// not found. @@ -18,13 +16,21 @@ namespace GitHub.Extensions /// The service, or null if not found public static object TryGetService(this IServiceProvider serviceProvider, Type type) { - if (cachedUIProvider != null && type == typeof(IUIProvider)) - return cachedUIProvider; - var ui = serviceProvider as IUIProvider; - return ui != null - ? ui.TryGetService(type) - : GetServiceAndCache(serviceProvider, type, ref cachedUIProvider); + if (ui != null) + return ui.TryGetService(type); + + object ret = null; + try + { + ret = serviceProvider.GetService(type); + } + catch (Exception ex) + { + Debug.Print(ex.ToString()); + VisualStudio.VsOutputLogger.WriteLine("GetServiceAndCache: Could not obtain instance of '{0}'", type); + } + return ret; } /// @@ -42,13 +48,10 @@ namespace GitHub.Extensions } public static T GetExportedValue(this IServiceProvider serviceProvider) where T : class { - if (cachedUIProvider != null && typeof(T) == typeof(IUIProvider)) - return (T)cachedUIProvider; - var ui = serviceProvider as IUIProvider; return ui != null ? ui.TryGetService(typeof(T)) as T - : GetExportedValueAndCache(ref cachedUIProvider); + : VisualStudio.Services.ComponentModel.DefaultExportProvider.GetExportedValueOrDefault(); } /// @@ -71,31 +74,6 @@ namespace GitHub.Extensions return serviceProvider.TryGetService(typeof(T)) as T; } - static object GetServiceAndCache(IServiceProvider provider, Type type, ref CacheType cache) - { - object ret = null; - try - { - ret = provider.GetService(type); - } - catch (Exception ex) - { - Debug.Print(ex.ToString()); - VisualStudio.VsOutputLogger.WriteLine("GetServiceAndCache: Could not obtain instance of '{0}'", type); - } - if (ret != null && type == typeof(CacheType)) - cache = (CacheType)ret; - return ret; - } - - static T GetExportedValueAndCache(ref CacheType cache) where T : class - { - object ret = VisualStudio.Services.ComponentModel.DefaultExportProvider.GetExportedValueOrDefault(); - if (ret != null && typeof(T) == typeof(CacheType)) - cache = (CacheType)ret; - return ret as T; - } - public static void AddCommandHandler(this IServiceProvider provider, Guid guid, int cmdId, diff --git a/src/GitHub.Exports/Services/IMenuProvider.cs b/src/GitHub.Exports/Services/IMenuProvider.cs index 1492bfbfa..ca94a0250 100644 --- a/src/GitHub.Exports/Services/IMenuProvider.cs +++ b/src/GitHub.Exports/Services/IMenuProvider.cs @@ -8,7 +8,7 @@ namespace GitHub.VisualStudio /// Container for static and dynamic visibility menus (context, toolbar, top, etc) /// Get a reference to this via MEF and register the menus /// - [Guid(Guids.MenuProviderId)] + [Guid("76904E1A-9D58-41AB-8957-C23B9F50727B")] public interface IMenuProvider { /// diff --git a/src/GitHub.Exports/Settings/generated/IPackageSettings.cs b/src/GitHub.Exports/Settings/generated/IPackageSettings.cs new file mode 100644 index 000000000..c2057457d --- /dev/null +++ b/src/GitHub.Exports/Settings/generated/IPackageSettings.cs @@ -0,0 +1,30 @@ +// This is an automatically generated file, based on settings.json and PackageSettingsGen.tt +/* settings.json content: +{ + "settings": [ + { + "name": "CollectMetrics", + "type": "bool", + "default": 'true' + }, + { + "name": "UIState", + "type": "object", + "typename": "UIState", + "default": 'null' + } + ] +} +*/ + +using System.ComponentModel; + +namespace GitHub.Settings +{ + public interface IPackageSettings : INotifyPropertyChanged + { + void Save(); + bool CollectMetrics { get; set; } + UIState UIState { get; set; } + } +} diff --git a/src/GitHub.Extensions/TaskExtensions.cs b/src/GitHub.Extensions/TaskExtensions.cs index 4e404dc12..09d87feb4 100644 --- a/src/GitHub.Extensions/TaskExtensions.cs +++ b/src/GitHub.Extensions/TaskExtensions.cs @@ -20,6 +20,21 @@ namespace GitHub.Extensions return default(T); } } + + [return: AllowNull] + public static async Task Catch(this Task source, Action handler = null) + { + try + { + await source; + } + catch (Exception ex) + { + if (handler != null) + handler(ex); + } + } + public static void Forget(this Task task) { } diff --git a/src/GitHub.TeamFoundation.14/Base/EnsureLoggedInSection.cs b/src/GitHub.TeamFoundation.14/Base/EnsureLoggedInSection.cs index ba18190e4..af042ff66 100644 --- a/src/GitHub.TeamFoundation.14/Base/EnsureLoggedInSection.cs +++ b/src/GitHub.TeamFoundation.14/Base/EnsureLoggedInSection.cs @@ -64,7 +64,7 @@ namespace GitHub.VisualStudio.TeamExplorer.Sync void StartFlow(UIControllerFlow controllerFlow) { - var uiProvider = ServiceProvider.GetExportedValue(); + var uiProvider = ServiceProvider.GetService(); var ret = uiProvider.SetupUI(controllerFlow, null); ret.Subscribe(c => { }, () => CheckLogin().Forget()); uiProvider.RunUI(); diff --git a/src/GitHub.TeamFoundation.14/Connect/GitHubConnectSection.cs b/src/GitHub.TeamFoundation.14/Connect/GitHubConnectSection.cs index a6694e5a3..a56948c00 100644 --- a/src/GitHub.TeamFoundation.14/Connect/GitHubConnectSection.cs +++ b/src/GitHub.TeamFoundation.14/Connect/GitHubConnectSection.cs @@ -342,7 +342,7 @@ namespace GitHub.VisualStudio.TeamExplorer.Connect var teServices = ServiceProvider.GetExportedValue(); notifications.AddListener(teServices); - var uiProvider = ServiceProvider.GetExportedValue(); + var uiProvider = ServiceProvider.GetService(); uiProvider.GitServiceProvider = ServiceProvider; uiProvider.SetupUI(controllerFlow, SectionConnection); uiProvider.ListenToCompletionState() diff --git a/src/GitHub.TeamFoundation.14/Connect/GitHubInvitationSection.cs b/src/GitHub.TeamFoundation.14/Connect/GitHubInvitationSection.cs index 9a54e5440..1db0f4976 100644 --- a/src/GitHub.TeamFoundation.14/Connect/GitHubInvitationSection.cs +++ b/src/GitHub.TeamFoundation.14/Connect/GitHubInvitationSection.cs @@ -57,7 +57,7 @@ namespace GitHub.VisualStudio.TeamExplorer.Connect void StartFlow(UIControllerFlow controllerFlow) { - var uiProvider = ServiceProvider.GetExportedValue(); + var uiProvider = ServiceProvider.GetService(); uiProvider.RunUI(controllerFlow, null); } diff --git a/src/GitHub.TeamFoundation.14/Sync/GitHubPublishSection.cs b/src/GitHub.TeamFoundation.14/Sync/GitHubPublishSection.cs index b01b7301d..9de20eddc 100644 --- a/src/GitHub.TeamFoundation.14/Sync/GitHubPublishSection.cs +++ b/src/GitHub.TeamFoundation.14/Sync/GitHubPublishSection.cs @@ -100,7 +100,7 @@ namespace GitHub.VisualStudio.TeamExplorer.Sync void StartFlow(UIControllerFlow controllerFlow) { - var uiProvider = ServiceProvider.GetExportedValue(); + var uiProvider = ServiceProvider.GetService(); var ret = uiProvider.SetupUI(controllerFlow, null); ret.Subscribe((c) => { }, async () => { @@ -114,7 +114,7 @@ namespace GitHub.VisualStudio.TeamExplorer.Sync public void ShowPublish() { IsBusy = true; - var uiProvider = ServiceProvider.GetExportedValue(); + var uiProvider = ServiceProvider.GetService(); var factory = uiProvider.GetService(); var uiflow = factory.UIControllerFactory.CreateExport(); disposable = uiflow; diff --git a/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj b/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj index 89c516c79..f291bdf4c 100644 --- a/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj +++ b/src/GitHub.VisualStudio/GitHub.VisualStudio.csproj @@ -11,6 +11,7 @@ Internal 2.0.15.2 ..\..\build\$(Configuration)\ + true @@ -276,7 +277,7 @@ Properties\SolutionInfo.cs - + @@ -659,18 +660,33 @@ - - GitHub.StartPage.pkgdef + + GitHub.StartPage.Preview4.pkgdef PreserveNewest true - - GitHub.StartPage.dll + + GitHub.StartPage.Preview4.dll PreserveNewest true - - GitHub.StartPage.pdb + + GitHub.StartPage.Preview4.pdb + PreserveNewest + true + + + GitHub.StartPage.Preview5.pkgdef + PreserveNewest + true + + + GitHub.StartPage.Preview5.dll + PreserveNewest + true + + + GitHub.StartPage.Preview5.pdb PreserveNewest true diff --git a/src/GitHub.VisualStudio/GitHub.VisualStudio.vsct b/src/GitHub.VisualStudio/GitHub.VisualStudio.vsct index 3908508b9..c20ffe73f 100644 --- a/src/GitHub.VisualStudio/GitHub.VisualStudio.vsct +++ b/src/GitHub.VisualStudio/GitHub.VisualStudio.vsct @@ -215,6 +215,10 @@ + + + + @@ -262,6 +266,8 @@ + + diff --git a/src/GitHub.VisualStudio/GitHubPackage.cs b/src/GitHub.VisualStudio/GitHubPackage.cs index 857fcda51..30159f349 100644 --- a/src/GitHub.VisualStudio/GitHubPackage.cs +++ b/src/GitHub.VisualStudio/GitHubPackage.cs @@ -10,15 +10,17 @@ using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Octokit; using GitHub.Helpers; -using System.ComponentModel.Design; using System.Diagnostics; using System.Threading; -using tasks = System.Threading.Tasks; +using System.Threading.Tasks; +using Task = System.Threading.Tasks.Task; +using Microsoft.VisualStudio.Threading; using Microsoft.VisualStudio.ComponentModelHost; +using GitHub.VisualStudio.Menus; namespace GitHub.VisualStudio { - [PackageRegistration(UseManagedResourcesOnly = true)] + [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)] [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] [Guid(GuidList.guidGitHubPkgString)] [ProvideMenuResource("Menus.ctmenu", 1)] @@ -29,6 +31,7 @@ namespace GitHub.VisualStudio public class GitHubPackage : AsyncPackage { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] readonly IServiceProvider serviceProvider; static GitHubPackage() @@ -46,10 +49,12 @@ namespace GitHub.VisualStudio this.serviceProvider = serviceProvider; } - protected override async tasks.Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) + protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) { - var usageTracker = await GetServiceAsync(typeof(IUsageTracker)) as IUsageTracker; - await tasks.Task.Run(() => usageTracker.IncrementLaunchCount()); + await base.InitializeAsync(cancellationToken, progress); + + //var usageTracker = await GetServiceAsync(typeof(IUsageTracker)) as IUsageTracker; + //usageTracker.IncrementLaunchCount(); var menus = await GetServiceAsync(typeof(IMenuProvider)) as IMenuProvider; await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); @@ -59,8 +64,6 @@ namespace GitHub.VisualStudio foreach (var menu in menus.DynamicMenus) serviceProvider.AddCommandHandler(menu.Guid, menu.CmdId, menu.CanShow, () => menu.Activate()); - - await base.InitializeAsync(cancellationToken, progress); } } @@ -75,10 +78,32 @@ namespace GitHub.VisualStudio } } + //[NullGuard.NullGuard(NullGuard.ValidationFlags.None)] + //[PackageRegistration(UseManagedResourcesOnly = true)] + //[ProvideAutoLoad(MenuLoadingContextId)] + //[ProvideUIContextRule(MenuLoadingContextId, + // name: "GitHub context menus", + // expression: "FileOpen", + // termNames: new[] { "FileOpen" }, + // termValues: new[] { "ActiveEditorContentType:CSharp" } + //)] + //[Guid(MenuRegistrationPackageId)] + //public sealed class MenuRegistrationPackage : Package + //{ + // const string MenuRegistrationPackageId = "E37D3B17-2255-4144-9802-349530796693"; + // const string MenuLoadingContextId = "F2CC8C27-AF24-4BA6-80BC-4819A0E8844F"; + + // protected override void Initialize() + // { + // base.Initialize(); + + + // } + //} + [NullGuard.NullGuard(NullGuard.ValidationFlags.None)] [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)] [ProvideService(typeof(IUIProvider), IsAsyncQueryable = true)] - [ProvideService(typeof(IMenuProvider), IsAsyncQueryable = true)] [ProvideService(typeof(IUsageTracker), IsAsyncQueryable = true)] [ProvideAutoLoad(UIContextGuids.NoSolution)] [ProvideAutoLoad(UIContextGuids.SolutionExists)] @@ -87,6 +112,7 @@ namespace GitHub.VisualStudio { const string ServiceProviderPackageId = "D5CE1488-DEDE-426D-9E5B-BFCCFBE33E53"; const string StartPagePreview4PackageId = "3b764d23-faf7-486f-94c7-b3accc44a70d"; + const string StartPagePreview5PackageId = "3b764d23-faf7-486f-94c7-b3accc44a70e"; Version vsversion; Version VSVersion @@ -113,33 +139,57 @@ namespace GitHub.VisualStudio } } - protected override async tasks.Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) + protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) { AddService(typeof(IUIProvider), CreateService, true); - AddService(typeof(IMenuProvider), CreateService, true); AddService(typeof(IUsageTracker), CreateService, true); + AddService(typeof(IMenuProvider), CreateService, true); - // Load the start page package only for Dev15 Preview 4 - if (VSVersion.Major == 15 && VSVersion.Build == 25618) + if (VSVersion.Major == 15) { - var shell = await GetServiceAsync(typeof(SVsShell)) as IVsShell; - IVsPackage startPagePackage; - if (ErrorHandler.Failed(shell?.LoadPackage(new Guid(StartPagePreview4PackageId), out startPagePackage) ?? -1)) + // Load the start page package only for Dev15 Preview 4 + if (VSVersion.Build == 25618) { - // ¯\_(ツ)_/¯ + var shell = await GetServiceAsync(typeof(SVsShell)) as IVsShell; + IVsPackage startPagePackage; + if (ErrorHandler.Failed(shell?.LoadPackage(new Guid(StartPagePreview4PackageId), out startPagePackage) ?? -1)) + { + // ¯\_(ツ)_/¯ + } + } + // Load the start page package only for Dev15 Preview 5 + else if (VSVersion.Build == 25807) + { + var shell = await GetServiceAsync(typeof(SVsShell)) as IVsShell; + IVsPackage startPagePackage; + if (ErrorHandler.Failed(shell?.LoadPackage(new Guid(StartPagePreview5PackageId), out startPagePackage) ?? -1)) + { + // ¯\_(ツ)_/¯ + } } } } - async tasks.Task CreateService(IAsyncServiceContainer container, CancellationToken cancellationToken, Type serviceType) + async Task CreateService(IAsyncServiceContainer container, CancellationToken cancellationToken, Type serviceType) { if (serviceType == null) return null; - string contract = AttributedModelServices.GetContractName(serviceType); - var cm = await GetServiceAsync(typeof(SComponentModel)) as IComponentModel; - if (cm == null) - return null; - return await tasks.Task.Run(() => cm.DefaultExportProvider.GetExportedValueOrDefault(contract)); + + if (serviceType == typeof(IUIProvider)) + { + return new UIProvider(this); + } + else if (serviceType == typeof(IMenuProvider)) + { + var sp = await GetServiceAsync(typeof(IUIProvider)) as IUIProvider; + return new MenuProvider(sp); + } + // go the mef route + else + { + var sp = await GetServiceAsync(typeof(IUIProvider)) as IUIProvider; + return sp.TryGetService(serviceType); + } } } } diff --git a/src/GitHub.VisualStudio/Menus/AddConnection.cs b/src/GitHub.VisualStudio/Menus/AddConnection.cs index 2c78c91dc..ffc12353d 100644 --- a/src/GitHub.VisualStudio/Menus/AddConnection.cs +++ b/src/GitHub.VisualStudio/Menus/AddConnection.cs @@ -1,21 +1,14 @@ -using Microsoft.VisualStudio.Shell; -using System; -using System.ComponentModel.Composition; -using GitHub.Services; +using GitHub.Services; using GitHub.UI; -using GitHub.Extensions; using NullGuard; -using GitHub.Api; +using System; namespace GitHub.VisualStudio.Menus { - [Export(typeof(IMenuHandler))] - [PartCreationPolicy(CreationPolicy.Shared)] public class AddConnection: MenuBase, IMenuHandler { - [ImportingConstructor] - public AddConnection([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, ISimpleApiClientFactory apiFactory) - : base(serviceProvider, apiFactory) + public AddConnection(IUIProvider serviceProvider) + : base(serviceProvider) { } diff --git a/src/GitHub.VisualStudio/Menus/CopyLink.cs b/src/GitHub.VisualStudio/Menus/CopyLink.cs index bc8077656..889906000 100644 --- a/src/GitHub.VisualStudio/Menus/CopyLink.cs +++ b/src/GitHub.VisualStudio/Menus/CopyLink.cs @@ -1,27 +1,17 @@ -using Microsoft.VisualStudio.Shell; -using System; -using System.ComponentModel.Composition; -using System.Windows; -using GitHub.Extensions; -using GitHub.Services; +using GitHub.Services; using GitHub.VisualStudio.UI; using NullGuard; -using GitHub.Api; +using System; +using System.Windows; namespace GitHub.VisualStudio.Menus { - [Export(typeof(IDynamicMenuHandler))] - [PartCreationPolicy(CreationPolicy.Shared)] public class CopyLink : LinkMenuBase, IDynamicMenuHandler { - readonly IUsageTracker usageTracker; - [ImportingConstructor] - public CopyLink([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, - IUsageTracker usageTracker, ISimpleApiClientFactory apiFactory) - : base(serviceProvider, apiFactory) + public CopyLink(IUIProvider serviceProvider) + : base(serviceProvider) { - this.usageTracker = usageTracker; } public Guid Guid => GuidList.guidContextMenuSet; @@ -39,13 +29,13 @@ namespace GitHub.VisualStudio.Menus try { Clipboard.SetText(link); - var ns = ServiceProvider.GetExportedValue(); + var ns = ServiceProvider.TryGetService(); ns?.ShowMessage(Resources.LinkCopiedToClipboardMessage); - this.usageTracker.IncrementLinkToGitHubCount(); + UsageTracker.IncrementLinkToGitHubCount(); } catch { - var ns = ServiceProvider.GetExportedValue(); + var ns = ServiceProvider.TryGetService(); ns?.ShowMessage(Resources.Error_FailedToCopyToClipboard); } } diff --git a/src/GitHub.VisualStudio/Menus/CreateGist.cs b/src/GitHub.VisualStudio/Menus/CreateGist.cs index fb95413ad..1a5021534 100644 --- a/src/GitHub.VisualStudio/Menus/CreateGist.cs +++ b/src/GitHub.VisualStudio/Menus/CreateGist.cs @@ -1,26 +1,20 @@ -using Microsoft.VisualStudio.Shell; -using System; -using System.ComponentModel.Composition; -using GitHub.Services; +using GitHub.Services; using GitHub.UI; -using GitHub.Extensions; -using System.Diagnostics; using NullGuard; +using System; +using System.Diagnostics; namespace GitHub.VisualStudio.Menus { - [Export(typeof(IDynamicMenuHandler))] - [PartCreationPolicy(CreationPolicy.Shared)] public class CreateGist : MenuBase, IDynamicMenuHandler { readonly Lazy selectedTextProvider; + ISelectedTextProvider SelectedTextProvider => selectedTextProvider.Value; - [ImportingConstructor] - public CreateGist([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, - Lazy selectedTextProvider) + public CreateGist(IUIProvider serviceProvider) : base(serviceProvider) { - this.selectedTextProvider = selectedTextProvider; + selectedTextProvider = new Lazy(() => ServiceProvider.TryGetService()); } public Guid Guid { get { return GuidList.guidContextMenuSet; } } @@ -28,9 +22,8 @@ namespace GitHub.VisualStudio.Menus public bool CanShow() { - var stp = selectedTextProvider.Value; - Debug.Assert(stp != null, "Could not get an instance of ISelectedTextProvider"); - return !String.IsNullOrWhiteSpace(stp?.GetSelectedText()); + Debug.Assert(SelectedTextProvider != null, "Could not get an instance of ISelectedTextProvider"); + return !String.IsNullOrWhiteSpace(SelectedTextProvider?.GetSelectedText()); } public void Activate([AllowNull] object data) diff --git a/src/GitHub.VisualStudio/Menus/LinkMenuBase.cs b/src/GitHub.VisualStudio/Menus/LinkMenuBase.cs index 2e5d38c28..6540d6bf3 100644 --- a/src/GitHub.VisualStudio/Menus/LinkMenuBase.cs +++ b/src/GitHub.VisualStudio/Menus/LinkMenuBase.cs @@ -1,21 +1,25 @@ -using GitHub.Api; -using GitHub.Extensions; -using GitHub.Primitives; +using GitHub.Primitives; +using GitHub.Services; using System; namespace GitHub.VisualStudio.Menus { public class LinkMenuBase: MenuBase { - public LinkMenuBase(IServiceProvider serviceProvider, ISimpleApiClientFactory apiFactory) - : base(serviceProvider, apiFactory) + readonly Lazy usageTracker; + + protected IUsageTracker UsageTracker => usageTracker.Value; + + public LinkMenuBase(IUIProvider serviceProvider) + : base(serviceProvider) { + usageTracker = new Lazy(() => ServiceProvider.TryGetService()); } protected UriString GenerateLink() { var repo = ActiveRepo; - var activeDocument = ServiceProvider.GetExportedValue(); + var activeDocument = ServiceProvider.TryGetService(); if (activeDocument == null) return null; return repo.GenerateUrl(activeDocument.Name, activeDocument.StartLine, activeDocument.EndLine); diff --git a/src/GitHub.VisualStudio/Base/MenuBase.cs b/src/GitHub.VisualStudio/Menus/MenuBase.cs similarity index 66% rename from src/GitHub.VisualStudio/Base/MenuBase.cs rename to src/GitHub.VisualStudio/Menus/MenuBase.cs index 5c06640f5..b8f118b1f 100644 --- a/src/GitHub.VisualStudio/Base/MenuBase.cs +++ b/src/GitHub.VisualStudio/Menus/MenuBase.cs @@ -1,24 +1,22 @@ -using System; -using System.Diagnostics; -using System.Globalization; -using System.Linq; -using GitHub.Extensions; +using GitHub.Api; using GitHub.Models; using GitHub.Primitives; using GitHub.Services; -using System.Threading.Tasks; -using GitHub.Api; -using NullGuard; using GitHub.UI; +using NullGuard; +using System; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; namespace GitHub.VisualStudio { public abstract class MenuBase { - readonly IServiceProvider serviceProvider; - readonly ISimpleApiClientFactory apiFactory; + readonly IUIProvider serviceProvider; + readonly Lazy apiFactory; - protected IServiceProvider ServiceProvider { get { return serviceProvider; } } + protected IUIProvider ServiceProvider { get { return serviceProvider; } } protected ISimpleRepositoryModel ActiveRepo { get; private set; } @@ -32,35 +30,29 @@ namespace GitHub.VisualStudio set { if (simpleApiClient != value && value == null) - apiFactory.ClearFromCache(simpleApiClient); + ApiFactory.ClearFromCache(simpleApiClient); simpleApiClient = value; } } - protected ISimpleApiClientFactory ApiFactory => apiFactory; + protected ISimpleApiClientFactory ApiFactory => apiFactory.Value; protected MenuBase() - { - } + {} - protected MenuBase(IServiceProvider serviceProvider, ISimpleApiClientFactory apiFactory) - { - this.serviceProvider = serviceProvider; - this.apiFactory = apiFactory; - } - - protected MenuBase(IServiceProvider serviceProvider) + protected MenuBase(IUIProvider serviceProvider) { this.serviceProvider = serviceProvider; + apiFactory = new Lazy(() => ServiceProvider.TryGetService()); } protected ISimpleRepositoryModel GetActiveRepo() { - var activeRepo = ServiceProvider.GetExportedValue()?.ActiveRepo; + var activeRepo = ServiceProvider.TryGetService()?.ActiveRepo; // activeRepo can be null at this point because it is set elsewhere as the result of async operation that may not have completed yet. if (activeRepo == null) { - var path = ServiceProvider.GetExportedValue()?.GetActiveRepoPath() ?? String.Empty; + var path = ServiceProvider.TryGetService()?.GetActiveRepoPath() ?? String.Empty; try { activeRepo = !string.IsNullOrEmpty(path) ? new SimpleRepositoryModel(path) : null; @@ -75,28 +67,23 @@ namespace GitHub.VisualStudio protected void StartFlow(UIControllerFlow controllerFlow) { - var uiProvider = ServiceProvider.GetExportedValue(); - Debug.Assert(uiProvider != null, "MenuBase:StartFlow:No UIProvider available."); - if (uiProvider == null) - return; - IConnection connection = null; if (controllerFlow != UIControllerFlow.Authentication) { var activeRepo = GetActiveRepo(); - connection = ServiceProvider.GetExportedValue()?.Connections + connection = ServiceProvider.TryGetService()?.Connections .FirstOrDefault(c => activeRepo?.CloneUrl?.RepositoryName != null && c.HostAddress.Equals(HostAddress.Create(activeRepo.CloneUrl))); } - uiProvider.RunUI(controllerFlow, connection); + ServiceProvider.RunUI(controllerFlow, connection); } void RefreshRepo() { - ActiveRepo = ServiceProvider.GetExportedValue().ActiveRepo; + ActiveRepo = ServiceProvider.TryGetService().ActiveRepo; if (ActiveRepo == null) { - var vsGitServices = ServiceProvider.GetExportedValue(); + var vsGitServices = ServiceProvider.TryGetService(); string path = vsGitServices?.GetActiveRepoPath() ?? String.Empty; try { @@ -117,8 +104,7 @@ namespace GitHub.VisualStudio if (uri == null) return false; - Debug.Assert(apiFactory != null, "apiFactory cannot be null. Did you call the right constructor?"); - SimpleApiClient = apiFactory.Create(uri); + SimpleApiClient = ApiFactory.Create(uri); var isdotcom = HostAddress.IsGitHubDotComUri(uri.ToRepositoryUrl()); if (!isdotcom) diff --git a/src/GitHub.VisualStudio/Menus/MenuProvider.cs b/src/GitHub.VisualStudio/Menus/MenuProvider.cs index 082130dde..1e0d49ca2 100644 --- a/src/GitHub.VisualStudio/Menus/MenuProvider.cs +++ b/src/GitHub.VisualStudio/Menus/MenuProvider.cs @@ -1,23 +1,32 @@ -using System.Collections.Generic; +using GitHub.Services; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel.Composition; using System.Linq; namespace GitHub.VisualStudio.Menus { - [Export(typeof(IMenuProvider))] - [PartCreationPolicy(CreationPolicy.Shared)] public class MenuProvider : IMenuProvider { public IReadOnlyCollection Menus { get; } public IReadOnlyCollection DynamicMenus { get; } - [ImportingConstructor] - public MenuProvider([ImportMany] IEnumerable menus, [ImportMany] IEnumerable dynamicMenus) + public MenuProvider(IUIProvider serviceProvider) { - Menus = new ReadOnlyCollection(menus.ToList()); - DynamicMenus = new ReadOnlyCollection(dynamicMenus.ToList()); + Menus = new List + { + new AddConnection(serviceProvider), + new OpenPullRequests(), + new ShowGitHubPane() + }; + + DynamicMenus = new List + { + new CopyLink(serviceProvider), + new CreateGist(serviceProvider), + new OpenLink(serviceProvider) + }; } } } diff --git a/src/GitHub.VisualStudio/Menus/OpenLink.cs b/src/GitHub.VisualStudio/Menus/OpenLink.cs index 7488f00e7..dac26b948 100644 --- a/src/GitHub.VisualStudio/Menus/OpenLink.cs +++ b/src/GitHub.VisualStudio/Menus/OpenLink.cs @@ -1,25 +1,14 @@ -using GitHub.Extensions; -using GitHub.Services; -using Microsoft.VisualStudio.Shell; -using System; -using System.ComponentModel.Composition; +using GitHub.Services; using NullGuard; -using GitHub.Api; +using System; namespace GitHub.VisualStudio.Menus { - [Export(typeof(IDynamicMenuHandler))] - [PartCreationPolicy(CreationPolicy.Shared)] public class OpenLink: LinkMenuBase, IDynamicMenuHandler { - readonly IUsageTracker usageTracker; - - [ImportingConstructor] - public OpenLink([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, - IUsageTracker usageTracker, ISimpleApiClientFactory apiFactory) - : base(serviceProvider, apiFactory) + public OpenLink(IUIProvider serviceProvider) + : base(serviceProvider) { - this.usageTracker = usageTracker; } public Guid Guid => GuidList.guidContextMenuSet; @@ -34,10 +23,10 @@ namespace GitHub.VisualStudio.Menus var link = GenerateLink(); if (link == null) return; - var browser = ServiceProvider.GetExportedValue(); + var browser = ServiceProvider.TryGetService(); browser?.OpenUrl(link.ToUri()); - usageTracker.IncrementOpenInGitHubCount(); + UsageTracker.IncrementOpenInGitHubCount(); } public bool CanShow() diff --git a/src/GitHub.VisualStudio/Menus/OpenPullRequests.cs b/src/GitHub.VisualStudio/Menus/OpenPullRequests.cs index 64192ee7d..557e560d3 100644 --- a/src/GitHub.VisualStudio/Menus/OpenPullRequests.cs +++ b/src/GitHub.VisualStudio/Menus/OpenPullRequests.cs @@ -3,13 +3,10 @@ using GitHub.UI; using GitHub.VisualStudio.UI; using NullGuard; using System; -using System.ComponentModel.Composition; namespace GitHub.VisualStudio.Menus { - [ExportMenu(MenuType = MenuType.OpenPullRequests)] - [PartCreationPolicy(CreationPolicy.Shared)] - public class OpenPullRequests: MenuBase, IMenuHandler + public class OpenPullRequests : MenuBase, IMenuHandler { public Guid Guid => GuidList.guidGitHubCmdSet; public int CmdId => PkgCmdIDList.openPullRequestsCommand; diff --git a/src/GitHub.VisualStudio/Menus/ShowGitHubPane.cs b/src/GitHub.VisualStudio/Menus/ShowGitHubPane.cs index eb9b70aab..f7fa9269f 100644 --- a/src/GitHub.VisualStudio/Menus/ShowGitHubPane.cs +++ b/src/GitHub.VisualStudio/Menus/ShowGitHubPane.cs @@ -1,14 +1,9 @@ -using GitHub.Exports; -using GitHub.UI; -using GitHub.VisualStudio.UI; +using GitHub.VisualStudio.UI; using NullGuard; using System; -using System.ComponentModel.Composition; namespace GitHub.VisualStudio.Menus { - [ExportMenu(MenuType = MenuType.GitHubPane)] - [PartCreationPolicy(CreationPolicy.Shared)] public class ShowGitHubPane: MenuBase, IMenuHandler { public Guid Guid => GuidList.guidGitHubCmdSet; diff --git a/src/GitHub.VisualStudio/Services/UIProvider.cs b/src/GitHub.VisualStudio/Services/UIProvider.cs index 30991dae9..1d9e4842c 100644 --- a/src/GitHub.VisualStudio/Services/UIProvider.cs +++ b/src/GitHub.VisualStudio/Services/UIProvider.cs @@ -9,7 +9,6 @@ using System.Globalization; using System.Linq; using System.Reactive.Disposables; using System.Reactive.Linq; -using System.Windows.Controls; using GitHub.Infrastructure; using GitHub.Models; using GitHub.Services; @@ -18,6 +17,10 @@ using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.Shell; using NLog; using NullGuard; +using System.Threading; +using System.Threading.Tasks; +using Task = System.Threading.Tasks.Task; +using Microsoft.VisualStudio.Threading; namespace GitHub.VisualStudio { @@ -39,30 +42,7 @@ namespace GitHub.VisualStudio readonly Version currentVersion; bool initializingLogging = false; - ExportProvider exportProvider = null; - [AllowNull] - public ExportProvider ExportProvider - { - get - { - if (exportProvider == null) - { - var componentModel = serviceProvider.GetService(typeof(SComponentModel)) as IComponentModel; - Debug.Assert(componentModel != null, "Service of type SComponentModel not found"); - if (componentModel == null) - { - log.Error("Service of type SComponentModel not found"); - } - exportProvider = componentModel.DefaultExportProvider; - - if (ExportProvider == null) - { - log.Error("DefaultExportProvider could not be obtained."); - } - } - return exportProvider; - } - } + public ExportProvider ExportProvider { get; } CompositionContainer tempContainer; CompositionContainer TempContainer @@ -83,7 +63,7 @@ namespace GitHub.VisualStudio [AllowNull] public IServiceProvider GitServiceProvider { get; set; } - bool Initialized { get { return exportProvider != null; } } + public bool Initialized { get { return ExportProvider != null; } } [ImportingConstructor] public UIProvider([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider) @@ -92,13 +72,39 @@ namespace GitHub.VisualStudio this.serviceProvider = serviceProvider; tempParts = new Dictionary(); + + var asyncProvider = serviceProvider as IAsyncServiceProvider; + IComponentModel componentModel = null; + if (asyncProvider != null) + { + componentModel = asyncProvider.GetServiceAsync(typeof(SComponentModel)) as IComponentModel; + } + else + { + componentModel = serviceProvider.GetService(typeof(SComponentModel)) as IComponentModel; + } + + Debug.Assert(componentModel != null, "Service of type SComponentModel not found"); + if (componentModel == null) + { + log.Error("Service of type SComponentModel not found"); + } + + ExportProvider = componentModel.DefaultExportProvider; + if (ExportProvider == null) + { + log.Error("DefaultExportProvider could not be obtained."); + } } [return: AllowNull] public object TryGetService(Type serviceType) { if (!Initialized) + { + log.Error("ExportProvider is not initialized, cannot add service."); return null; + } if (!initializingLogging && log.Factory.Configuration == null) { @@ -118,7 +124,19 @@ namespace GitHub.VisualStudio if (instance != null) return instance; - instance = AddToDisposables(ExportProvider.GetExportedValues(contract).FirstOrDefault(x => contract.StartsWith("github.", StringComparison.OrdinalIgnoreCase) ? x.GetType().Assembly.GetName().Version == currentVersion : true)); + instance = TryGetServiceOnMainThread(serviceType, contract); + if (instance == null) + { + // we need to log these things + } + return instance; + } + + async Task TryGetServiceOnMainThread(Type serviceType, string contract) + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); + + var instance = AddToDisposables(ExportProvider.GetExportedValues(contract).FirstOrDefault(x => contract.StartsWith("github.", StringComparison.OrdinalIgnoreCase) ? x.GetType().Assembly.GetName().Version == currentVersion : true)); if (instance != null) return instance; @@ -127,12 +145,9 @@ namespace GitHub.VisualStudio if (instance != null) return instance; - if (GitServiceProvider != null) - { - instance = GitServiceProvider.GetService(serviceType); - if (instance != null) - return instance; - } + instance = GitServiceProvider?.GetService(serviceType); + if (instance != null) + return instance; return null; } diff --git a/src/GitHub.VisualStudio/Services/UsageTracker.cs b/src/GitHub.VisualStudio/Services/UsageTracker.cs index 116a3b0c4..b166b2c7f 100644 --- a/src/GitHub.VisualStudio/Services/UsageTracker.cs +++ b/src/GitHub.VisualStudio/Services/UsageTracker.cs @@ -182,7 +182,17 @@ namespace GitHub.Services timer.Start(); } - async void TimerTick(object sender, EventArgs e) + void TimerTick(object sender, EventArgs e) + { + TimerTick() + .Catch(ex => + { + //log.Warn("Failed submitting usage data", ex); + }) + .Forget(); + } + + async Task TimerTick() { Debug.Assert(client != null, "TimerTick should not be triggered when there is no IMetricsService"); @@ -204,30 +214,23 @@ namespace GitHub.Services if (!userSettings.CollectMetrics) return; - try - { - // Every time we increment the launch count we increment both daily and weekly - // launch count but we only submit (and clear) the weekly launch count when we've - // transitioned into a new week. We've defined a week by the ISO8601 definition, - // i.e. week starting on Monday and ending on Sunday. - var usage = LoadUsage(); - var lastDate = usage.LastUpdated; - var currentDate = DateTimeOffset.Now; - var includeWeekly = GetIso8601WeekOfYear(lastDate) != GetIso8601WeekOfYear(currentDate); - var includeMonthly = lastDate.Month != currentDate.Month; + // Every time we increment the launch count we increment both daily and weekly + // launch count but we only submit (and clear) the weekly launch count when we've + // transitioned into a new week. We've defined a week by the ISO8601 definition, + // i.e. week starting on Monday and ending on Sunday. + var usage = LoadUsage(); + var lastDate = usage.LastUpdated; + var currentDate = DateTimeOffset.Now; + var includeWeekly = GetIso8601WeekOfYear(lastDate) != GetIso8601WeekOfYear(currentDate); + var includeMonthly = lastDate.Month != currentDate.Month; - // Only send stats once a day. - if (lastDate.Date != currentDate.Date) - { - await SendUsage(usage.Model, includeWeekly, includeMonthly); - ClearCounters(usage.Model, includeWeekly, includeMonthly); - usage.LastUpdated = DateTimeOffset.Now.UtcDateTime; - SaveUsage(usage); - } - } - catch //(Exception ex) + // Only send stats once a day. + if (lastDate.Date != currentDate.Date) { - //log.Warn("Failed submitting usage data", ex); + await SendUsage(usage.Model, includeWeekly, includeMonthly); + ClearCounters(usage.Model, includeWeekly, includeMonthly); + usage.LastUpdated = DateTimeOffset.Now.UtcDateTime; + SaveUsage(usage); } } diff --git a/src/GitHub.VisualStudio/Settings/generated/PackageSettingsGen.cs b/src/GitHub.VisualStudio/Settings/generated/PackageSettingsGen.cs new file mode 100644 index 000000000..cb6aedb8f --- /dev/null +++ b/src/GitHub.VisualStudio/Settings/generated/PackageSettingsGen.cs @@ -0,0 +1,57 @@ +// This is an automatically generated file, based on settings.json and PackageSettingsGen.tt +/* settings.json content: +{ + "settings": [ + { + "name": "CollectMetrics", + "type": "bool", + "default": 'true' + }, + { + "name": "UIState", + "type": "object", + "typename": "UIState", + "default": 'null' + } + ] +} +*/ + +using GitHub.Settings; +using GitHub.Primitives; +using GitHub.VisualStudio.Helpers; + +namespace GitHub.VisualStudio.Settings { + + public partial class PackageSettings : NotificationAwareObject, IPackageSettings + { + + bool collectMetrics; + public bool CollectMetrics + { + get { return collectMetrics; } + set { collectMetrics = value; this.RaisePropertyChange(); } + } + + UIState uIState; + public UIState UIState + { + get { return uIState; } + set { uIState = value; this.RaisePropertyChange(); } + } + + + void LoadSettings() + { + CollectMetrics = (bool)settingsStore.Read("CollectMetrics", true); + UIState = SimpleJson.DeserializeObject((string)settingsStore.Read("UIState", "{}")); + } + + void SaveSettings() + { + settingsStore.Write("CollectMetrics", CollectMetrics); + settingsStore.Write("UIState", SimpleJson.SerializeObject(UIState)); + } + + } +} \ No newline at end of file diff --git a/src/GitHub.VisualStudio/UI/Views/GitHubPaneViewModel.cs b/src/GitHub.VisualStudio/UI/Views/GitHubPaneViewModel.cs index 6efe22c9f..605c67033 100644 --- a/src/GitHub.VisualStudio/UI/Views/GitHubPaneViewModel.cs +++ b/src/GitHub.VisualStudio/UI/Views/GitHubPaneViewModel.cs @@ -225,7 +225,7 @@ namespace GitHub.VisualStudio.UI.Views break; } - var uiProvider = ServiceProvider.GetExportedValue(); + var uiProvider = ServiceProvider.GetService(); var factory = uiProvider.GetService(); var uiflow = factory.UIControllerFactory.CreateExport(); disposables.Add(uiflow); diff --git a/submodules/externalpackages/StartPage b/submodules/externalpackages/StartPage index 011585516..c41c900b6 160000 --- a/submodules/externalpackages/StartPage +++ b/submodules/externalpackages/StartPage @@ -1 +1 @@ -Subproject commit 01158551686845eaf3cd3298aabc48a2a6fde90d +Subproject commit c41c900b6f90245187a4b6d8335f85ae70a57462