Merge pull request #48 from shana/shana/dialogs

Dialog infrastructure and stubs, plus loads of refactoring
This commit is contained in:
Phil Haack 2015-02-26 13:30:05 -08:00
Родитель 42b3f229d6 97ceed081b
Коммит 6b1fdd83a7
180 изменённых файлов: 5362 добавлений и 1071 удалений

Просмотреть файл

@ -49,6 +49,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitHub.Exports", "src\GitHu
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitHub.Api", "src\GitHub.Api\GitHub.Api.csproj", "{B389ADAF-62CC-486E-85B4-2D8B078DF763}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitHub.Exports.Reactive", "src\GitHub.Exports.Reactive\GitHub.Exports.Reactive.csproj", "{E4ED0537-D1D9-44B6-9212-3096D7C3F7A1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DesignTimeStyleHelper", "src\DesignTimeStyleHelper\DesignTimeStyleHelper.csproj", "{B1F5C227-456F-437D-BD5F-4C11B7A8D1A0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -95,6 +99,14 @@ Global
{B389ADAF-62CC-486E-85B4-2D8B078DF763}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B389ADAF-62CC-486E-85B4-2D8B078DF763}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B389ADAF-62CC-486E-85B4-2D8B078DF763}.Release|Any CPU.Build.0 = Release|Any CPU
{E4ED0537-D1D9-44B6-9212-3096D7C3F7A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E4ED0537-D1D9-44B6-9212-3096D7C3F7A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E4ED0537-D1D9-44B6-9212-3096D7C3F7A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E4ED0537-D1D9-44B6-9212-3096D7C3F7A1}.Release|Any CPU.Build.0 = Release|Any CPU
{B1F5C227-456F-437D-BD5F-4C11B7A8D1A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B1F5C227-456F-437D-BD5F-4C11B7A8D1A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B1F5C227-456F-437D-BD5F-4C11B7A8D1A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B1F5C227-456F-437D-BD5F-4C11B7A8D1A0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

Просмотреть файл

@ -1 +1 @@
powershell.exe .\build\cibuild.ps1
powershell.exe .\script\cibuild.ps1

Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

Просмотреть файл

@ -0,0 +1,14 @@
<Application x:Class="DesignTimeStyleHelper.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DesignTimeStyleHelper"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/GitHub.UI;component/SharedDictionary.xaml" />
<ResourceDictionary Source="/GitHub.UI.Reactive;component/SharedDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

Просмотреть файл

@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.Globalization;
using System.Linq;
using System.Windows;
using GitHub.VisualStudio.TeamExplorerConnect;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Shell;
using Moq;
using GitHub.Services;
using GitHub.VisualStudio;
using GitHub.ViewModels;
using GitHub.Exports;
namespace DesignTimeStyleHelper
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
public static Holder ExportHolder { get; set; }
public static CustomServiceProvider ServiceProvider { get { return (CustomServiceProvider) ExportHolder.ServiceProvider; } }
public App()
{
var s = new CustomServiceProvider();
ExportHolder = new Holder(s.DefaultCompositionService);
}
}
public class Holder
{
[Import]
public SVsServiceProvider ServiceProvider;
[Import]
SComponentModel sc;
[Import]
public IBrowser Browser;
[Import]
public ExportFactoryProvider ExportFactoryProvider;
[Import]
public IUIProvider UIProvider;
public Holder(ICompositionService cc)
{
cc.SatisfyImportsOnce(this);
}
}
[Export(typeof(SVsServiceProvider))]
[Export(typeof(SComponentModel))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class CustomServiceProvider : SVsServiceProvider, IServiceProvider,
SComponentModel, IComponentModel
{
readonly CompositionContainer container;
public CompositionContainer Container { get { return container; } }
AggregateCatalog catalog;
public CustomServiceProvider()
{
catalog = new AggregateCatalog(
new AssemblyCatalog(typeof(CustomServiceProvider).Assembly),
new AssemblyCatalog(typeof(GitHub.VisualStudio.Services).Assembly), // GitHub.VisualStudio
new AssemblyCatalog(typeof(GitHub.Api.ApiClient).Assembly), // GitHub.App
new AssemblyCatalog(typeof(GitHub.Api.SimpleApiClient).Assembly), // GitHub.Api
new AssemblyCatalog(typeof(Rothko.Environment).Assembly), // Rothko
new AssemblyCatalog(typeof(GitHub.Services.EnterpriseProbeTask).Assembly) // GitHub.Exports
);
container = new CompositionContainer(catalog, CompositionOptions.IsThreadSafe | CompositionOptions.DisableSilentRejection);
DefaultCatalog = catalog;
DefaultExportProvider = container;
DefaultCompositionService = DefaultCatalog.CreateCompositionService();
var batch = new CompositionBatch();
batch.AddExportedValue<SVsServiceProvider>(this);
batch.AddExportedValue<SComponentModel>(this);
batch.AddExportedValue<ICompositionService>(DefaultCompositionService);
container.Compose(batch);
}
public object GetService(Type serviceType)
{
string contract = AttributedModelServices.GetContractName(serviceType);
var instance = container.GetExportedValues<object>(contract).FirstOrDefault();
if (instance != null)
return instance;
instance = Create(serviceType);
if (instance != null)
return instance;
throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture,
"Could not locate any instances of contract {0}.", contract));
}
T Create<T>() where T : class
{
return new Mock<T>().Object;
}
object Create(Type t)
{
var moq = typeof(Mock<>).MakeGenericType(t);
var ctor = moq.GetConstructor(new Type[] { });
var m = ctor.Invoke(new object[] { }) as Mock;
return m.Object;
}
public ExportProvider DefaultExportProvider { get; set; }
public ComposablePartCatalog DefaultCatalog { get; set; }
public ICompositionService DefaultCompositionService { get; set; }
public ComposablePartCatalog GetCatalog(string catalogName)
{
throw new NotImplementedException();
}
public IEnumerable<T> GetExtensions<T>() where T : class
{
throw new NotImplementedException();
}
public T GetService<T>() where T : class
{
throw new NotImplementedException();
}
}
}

Просмотреть файл

@ -0,0 +1,166 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{B1F5C227-456F-437D-BD5F-4C11B7A8D1A0}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DesignTimeStyleHelper</RootNamespace>
<AssemblyName>DesignTimeStyleHelper</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.ComponentModelHost, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="Microsoft.VisualStudio.Shell.Immutable.10.0, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="Moq">
<HintPath>..\..\packages\Moq.4.2.1312.1319\lib\net40\Moq.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Data" />
<Reference Include="System.Reactive.Core, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll</HintPath>
</Reference>
<Reference Include="System.Reactive.Interfaces, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll</HintPath>
</Reference>
<Reference Include="System.Reactive.Linq, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll</HintPath>
</Reference>
<Reference Include="System.Reactive.PlatformServices, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll</HintPath>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
</ApplicationDefinition>
<Compile Include="WindowController.xaml.cs">
<DependentUpon>WindowController.xaml</DependentUpon>
</Compile>
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="WindowController.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<AppDesigner Include="Properties\" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\submodules\Rothko\src\Rothko.csproj">
<Project>{4a84e568-ca86-4510-8cd0-90d3ef9b65f9}</Project>
<Name>Rothko</Name>
</ProjectReference>
<ProjectReference Include="..\GitHub.Api\GitHub.Api.csproj">
<Project>{b389adaf-62cc-486e-85b4-2d8b078df763}</Project>
<Name>GitHub.Api</Name>
</ProjectReference>
<ProjectReference Include="..\GitHub.App\GitHub.App.csproj">
<Project>{1a1da411-8d1f-4578-80a6-04576bea2dc5}</Project>
<Name>GitHub.App</Name>
</ProjectReference>
<ProjectReference Include="..\GitHub.Exports\GitHub.Exports.csproj">
<Project>{9aea02db-02b5-409c-b0ca-115d05331a6b}</Project>
<Name>GitHub.Exports</Name>
</ProjectReference>
<ProjectReference Include="..\GitHub.Exports.Reactive\GitHub.Exports.Reactive.csproj">
<Project>{e4ed0537-d1d9-44b6-9212-3096d7c3f7a1}</Project>
<Name>GitHub.Exports.Reactive</Name>
</ProjectReference>
<ProjectReference Include="..\GitHub.UI.Reactive\GitHub.UI.Reactive.csproj">
<Project>{158b05e8-fdbc-4d71-b871-c96e28d5adf5}</Project>
<Name>GitHub.UI.Reactive</Name>
</ProjectReference>
<ProjectReference Include="..\GitHub.UI\GitHub.UI.csproj">
<Project>{346384dd-2445-4a28-af22-b45f3957bd89}</Project>
<Name>GitHub.UI</Name>
</ProjectReference>
<ProjectReference Include="..\GitHub.VisualStudio\GitHub.VisualStudio.csproj">
<Project>{11569514-5ae5-4b5b-92a2-f10b0967de5f}</Project>
<Name>GitHub.VisualStudio</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Просмотреть файл

@ -0,0 +1,35 @@
<Window x:Class="DesignTimeStyleHelper.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DesignTimeStyleHelper"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/GitHub.UI;component/Assets/Styles.xaml" />
<ResourceDictionary Source="pack://application:,,,/GitHub.UI;component/Assets/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/GitHub.UI;component/Assets/TextBlocks.xaml" />
<ResourceDictionary Source="pack://application:,,,/GitHub.UI.Reactive;component/Assets/Controls.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<Grid>
<WrapPanel Orientation="Horizontal" Grid.Row="0" Margin="0,0,0,6">
<TextBlock><Hyperlink x:Name="cloneLink" Click="cloneLink_Click">Clone</Hyperlink></TextBlock>
<Label Margin="6 0 6 0"></Label>
<TextBlock><Hyperlink x:Name="createLink" Click="createLink_Click">Create</Hyperlink></TextBlock>
</WrapPanel>
</Grid>
<StackPanel x:Name="container">
</StackPanel>
</StackPanel>
</Window>

Просмотреть файл

@ -0,0 +1,49 @@
using System;
using System.Windows;
using GitHub.VisualStudio.TeamExplorerConnect;
using GitHub.VisualStudio;
using GitHub.Services;
using GitHub.UI;
using System.ComponentModel.Composition;
namespace DesignTimeStyleHelper
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void cloneLink_Click(object sender, RoutedEventArgs e)
{
var ui = App.ServiceProvider.GetExportedValue<IUIProvider>();
var factory = ui.GetService<ExportFactoryProvider>();
var d = factory.UIControllerFactory.CreateExport();
var creation = d.Value.SelectFlow(UIControllerFlow.Clone);
var x = new WindowController(creation);
creation.Subscribe(_ => { }, _ => x.Close());
x.Show();
d.Value.Start();
}
private void createLink_Click(object sender, RoutedEventArgs e)
{
var ui = App.ServiceProvider.GetExportedValue<IUIProvider>();
var factory = ui.GetService<ExportFactoryProvider>();
var d = factory.UIControllerFactory.CreateExport();
var creation = d.Value.SelectFlow(UIControllerFlow.Create);
var x = new WindowController(creation);
creation.Subscribe(_ => { }, _ => x.Close());
x.Show();
d.Value.Start();
}
}
}

Просмотреть файл

@ -0,0 +1,55 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("DesignTimeStyleHelper")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DesignTimeStyleHelper")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

71
src/DesignTimeStyleHelper/Properties/Resources.Designer.cs сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace DesignTimeStyleHelper.Properties
{
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DesignTimeStyleHelper.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

Просмотреть файл

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

30
src/DesignTimeStyleHelper/Properties/Settings.Designer.cs сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace DesignTimeStyleHelper.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

Просмотреть файл

@ -0,0 +1,12 @@
<Window x:Class="DesignTimeStyleHelper.WindowController"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DesignTimeStyleHelper"
mc:Ignorable="d"
Title="WindowController" Height="300" Width="300">
<Grid x:Name="Container">
</Grid>
</Window>

Просмотреть файл

@ -0,0 +1,35 @@
using System;
using System.Windows;
using System.Windows.Controls;
namespace DesignTimeStyleHelper
{
/// <summary>
/// Interaction logic for WindowController.xaml
/// </summary>
public partial class WindowController : Window
{
IDisposable disposable;
public WindowController(IObservable<UserControl> controls)
{
InitializeComponent();
disposable = controls.Subscribe(c => Load(c),
Close
);
}
protected override void OnClosed(EventArgs e)
{
disposable.Dispose();
base.OnClosed(e);
}
public void Load(UserControl control)
{
Container.Children.Clear();
Container.Children.Add(control);
}
}
}

Просмотреть файл

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Moq" version="4.2.1312.1319" targetFramework="net45" />
<package id="Rx-Core" version="2.2.5" targetFramework="net45" />
<package id="Rx-Interfaces" version="2.2.5" targetFramework="net45" />
<package id="Rx-Linq" version="2.2.5" targetFramework="net45" />
<package id="Rx-Main" version="2.2.5" targetFramework="net45" />
<package id="Rx-PlatformServices" version="2.2.5" targetFramework="net45" />
</packages>

Просмотреть файл

@ -1,11 +1,10 @@
using GitHub.Exports;
using GitHub.Extensions;
using GitHub.Services;
using Octokit;
using System;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using GitHub.Extensions;
using GitHub.Primitives;
using GitHub.Services;
using Octokit;
namespace GitHub.Api
{

Просмотреть файл

@ -1,12 +1,9 @@
using GitHub.Models;
using System;
using System.ComponentModel.Composition;
using GitHub.Models;
using GitHub.Primitives;
using GitHub.Services;
using Octokit;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GitHub.Api
{

Просмотреть файл

@ -5,12 +5,12 @@ using System.Net;
using System.Reactive.Linq;
using GitHub.Authentication;
using GitHub.Extensions;
using GitHub.Primitives;
using NLog;
using Octokit;
using Octokit.Reactive;
using ReactiveUI;
using Authorization = Octokit.Authorization;
using LogManager = NLog.LogManager;
namespace GitHub.Api
{

Просмотреть файл

@ -2,7 +2,6 @@
using System.ComponentModel.Composition;
using System.Reactive.Linq;
using GitHub.ViewModels;
using Microsoft.VisualStudio.PlatformUI;
using Octokit;
using ReactiveUI;
@ -11,23 +10,25 @@ namespace GitHub.Authentication
[Export(typeof(ITwoFactorChallengeHandler))]
public class TwoFactorChallengeHandler : ITwoFactorChallengeHandler
{
readonly IServiceProvider serviceProvider;
//readonly IServiceProvider serviceProvider;
readonly Lazy<ITwoFactorViewModel> lazyTwoFactorDialog;
[ImportingConstructor]
public TwoFactorChallengeHandler(IServiceProvider serviceProvider)
public TwoFactorChallengeHandler(Lazy<ITwoFactorViewModel> twoFactorDialog)
{
this.serviceProvider = serviceProvider;
//this.serviceProvider = serviceProvider;
this.lazyTwoFactorDialog = twoFactorDialog;
}
public IObservable<TwoFactorChallengeResult> HandleTwoFactorException(TwoFactorRequiredException exception)
{
var twoFactorDialog = (TwoFactorDialogViewModel)serviceProvider.GetService(typeof(TwoFactorDialogViewModel));
var twoFactorView = (IViewFor<TwoFactorDialogViewModel>)serviceProvider.GetService(typeof(IViewFor<TwoFactorDialogViewModel>));
var twoFactorDialog = lazyTwoFactorDialog.Value as TwoFactorDialogViewModel;
//var twoFactorView = (IViewFor<TwoFactorDialogViewModel>)serviceProvider.GetService(typeof(IViewFor<TwoFactorDialogViewModel>));
return Observable.Start(() =>
{
twoFactorView.ViewModel = twoFactorDialog;
((DialogWindow)twoFactorView).Show();
//twoFactorView.ViewModel = twoFactorDialog;
//((DialogWindow)twoFactorView).Show();
var userError = new TwoFactorRequiredUserError(exception);
return twoFactorDialog.Show(userError)
@ -37,8 +38,9 @@ namespace GitHub.Authentication
: Observable.Throw<TwoFactorChallengeResult>(exception));
}, RxApp.MainThreadScheduler)
.SelectMany(x => x)
.Finally(() =>
((DialogWindow)twoFactorView).Hide());
//.Finally(() =>
// ((DialogWindow)twoFactorView).Hide());
;
}
}
}

Просмотреть файл

@ -6,9 +6,10 @@ using System.Reactive.Linq;
using Akavache;
using GitHub.Extensions;
using GitHub.Extensions.Reactive;
using GitHub.Models;
using Octokit;
namespace GitHub
namespace GitHub.Caches
{
public class HostCache : IHostCache
{

Просмотреть файл

@ -1,8 +1,9 @@
using System;
using System.Reactive;
using Akavache;
using GitHub.Primitives;
namespace GitHub
namespace GitHub.Caches
{
public interface ILoginCache : IDisposable
{

Просмотреть файл

@ -3,7 +3,7 @@ using System.Linq.Expressions;
using System.Reactive;
using Akavache;
namespace GitHub
namespace GitHub.Caches
{
/// <summary>
/// A cache for data that's not host specific

Просмотреть файл

@ -5,9 +5,10 @@ using System.Reactive;
using System.Reactive.Linq;
using Akavache;
using GitHub.Extensions;
using GitHub.Primitives;
using NLog;
namespace GitHub
namespace GitHub.Caches
{
[Export(typeof(ILoginCache))]
public sealed class LoginCache : ILoginCache

Просмотреть файл

@ -8,7 +8,7 @@ using System.Reflection;
using Akavache;
using ReactiveUI;
namespace GitHub
namespace GitHub.Caches
{
/// <summary>
/// A cache for data that's not host specific
@ -108,9 +108,9 @@ namespace GitHub
TSource source)
{
var member = expression.Body as MemberExpression;
Debug.Assert(member != null, "Expression should be a property and not method or some other shit.");
Debug.Assert(member != null, "Expression should be a property and not method or some other thing.");
var property = member.Member as PropertyInfo;
Debug.Assert(property != null, "Expression should be a property and not field or some other shit.");
Debug.Assert(property != null, "Expression should be a property and not field or some other thing.");
var propertySetterAction = new Action<TProperty>(value => property.SetValue(source, value));
return Tuple.Create(property.Name, propertySetterAction);
}

Просмотреть файл

@ -0,0 +1,181 @@
using System;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using GitHub.Authentication;
using GitHub.Exports;
using GitHub.Models;
using GitHub.Services;
using GitHub.UI;
using GitHub.ViewModels;
using ReactiveUI;
using Stateless;
using System.Windows.Controls;
namespace GitHub.Controllers
{
[Export(typeof(IUIController))]
public class UIController : IUIController, IDisposable
{
enum Trigger { Auth = 1, Create = 2, Clone = 3, Next, Previous }
readonly ExportFactoryProvider factory;
readonly IUIProvider uiProvider;
CompositeDisposable disposables = new CompositeDisposable();
Subject<UserControl> transition;
UIControllerFlow currentFlow;
StateMachine<UIViewType, Trigger> machine;
[ImportingConstructor]
public UIController(IUIProvider uiProvider, IRepositoryHosts hosts,
ExportFactoryProvider factory)
{
this.factory = factory;
this.uiProvider = uiProvider;
machine = new StateMachine<UIViewType, Trigger>(UIViewType.None);
machine.Configure(UIViewType.None)
.Permit(Trigger.Auth, UIViewType.Login)
.PermitIf(Trigger.Create, UIViewType.Create, () => hosts.IsLoggedInToAnyHost)
.PermitIf(Trigger.Create, UIViewType.Login, () => !hosts.IsLoggedInToAnyHost)
.PermitIf(Trigger.Clone, UIViewType.Clone, () => hosts.IsLoggedInToAnyHost)
.PermitIf(Trigger.Clone, UIViewType.Login, () => !hosts.IsLoggedInToAnyHost);
machine.Configure(UIViewType.Login)
.OnEntry(() =>
{
var dvm = factory.GetViewModel(UIViewType.Login);
disposables.Add(dvm);
var viewModel = dvm.Value as ILoginViewModel;
viewModel.AuthenticationResults.Subscribe(result =>
{
if (result == AuthenticationResult.Success)
Fire(Trigger.Next);
});
var dv = factory.GetView(UIViewType.Login);
disposables.Add(dv);
var view = dv.Value;
view.ViewModel = viewModel;
var twofa = uiProvider.GetService<ITwoFactorViewModel>();
twofa.WhenAny(x => x.IsShowing, x => x.Value)
.Where(x => x)
.Subscribe(_ =>
{
Fire(Trigger.Next);
});
LoadView(view);
})
.Permit(Trigger.Next, UIViewType.TwoFactor);
machine.Configure(UIViewType.TwoFactor)
.SubstateOf(UIViewType.Login)
.OnEntry(() =>
{
var view = SetupView(UIViewType.TwoFactor);
LoadView(view);
})
.PermitIf(Trigger.Next, UIViewType.End, () => currentFlow == UIControllerFlow.Authentication)
.PermitIf(Trigger.Next, UIViewType.Create, () => currentFlow == UIControllerFlow.Create)
.PermitIf(Trigger.Next, UIViewType.Clone, () => currentFlow == UIControllerFlow.Clone);
machine.Configure(UIViewType.Create)
.OnEntry(() =>
{
var view = SetupView(UIViewType.Create);
LoadView(view);
})
.Permit(Trigger.Next, UIViewType.End);
machine.Configure(UIViewType.Clone)
.OnEntry(() =>
{
var view = SetupView(UIViewType.Clone);
LoadView(view);
})
.Permit(Trigger.Next, UIViewType.End);
machine.Configure(UIViewType.End)
.OnEntry(() =>
{
transition.OnCompleted();
transition.Dispose();
})
.Permit(Trigger.Next, UIViewType.None);
}
private void LoadView(IView view)
{
transition.OnNext(view as UserControl);
}
IView SetupView(UIViewType viewType)
{
IViewModel viewModel;
if (viewType == UIViewType.TwoFactor)
viewModel = uiProvider.GetService<ITwoFactorViewModel>();
else
{
var dvm = factory.GetViewModel(viewType);
disposables.Add(dvm);
viewModel = dvm.Value;
}
var dv = factory.GetView(viewType);
disposables.Add(dv);
var view = dv.Value;
view.ViewModel = viewModel;
return view;
}
void Fire(Trigger next)
{
Debug.WriteLine("Firing {0}", next);
machine.Fire(next);
}
public IObservable<UserControl> SelectFlow(UIControllerFlow choice)
{
currentFlow = choice;
transition = new Subject<UserControl>();
transition.Subscribe((o) => { }, _ => Fire(Trigger.Next));
return transition;
}
public void Start()
{
Fire((Trigger)(int)currentFlow);
}
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
disposables.Dispose();
transition.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
}

Просмотреть файл

@ -1,22 +1,23 @@
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition;
using GitHub.Models;
using Octokit;
using Account = GitHub.Models.Account;
namespace GitHub
namespace GitHub.Factories
{
[Export(typeof(IAccountFactory))]
public class AccountFactory : IAccountFactory
{
public IAccount CreateAccount(
IRepositoryHost repositoryHost,
Octokit.User user)
User user)
{
return new Account(repositoryHost, user);
}
public IAccount CreateAccount(
IRepositoryHost repositoryHost,
Octokit.Organization organization)
Organization organization)
{
return new Account(repositoryHost, organization);
}

Просмотреть файл

@ -1,11 +1,15 @@
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition;
using GitHub.Api;
using GitHub.Authentication;
using GitHub.Caches;
using GitHub.Models;
using GitHub.Primitives;
using GitHub.Services;
using Octokit;
using Octokit.Reactive;
using ApiClient = GitHub.Api.ApiClient;
namespace GitHub.Api
namespace GitHub.Factories
{
[Export(typeof(IApiClientFactory))]
[PartCreationPolicy(CreationPolicy.Shared)]

Просмотреть файл

@ -1,9 +1,12 @@
using System;
using System.ComponentModel.Composition;
using System.IO;
using GitHub.Caches;
using GitHub.Info;
using GitHub.Primitives;
using Rothko;
namespace GitHub
namespace GitHub.Factories
{
[Export(typeof(IHostCacheFactory))]
[PartCreationPolicy(CreationPolicy.Shared)]

Просмотреть файл

@ -1,6 +1,6 @@
using Akavache;
namespace GitHub
namespace GitHub.Factories
{
public interface IBlobCacheFactory
{

Просмотреть файл

@ -1,6 +1,7 @@
using System;
using GitHub.Caches;
using GitHub.Primitives;
namespace GitHub
namespace GitHub.Factories
{
public interface IHostCacheFactory
{

Просмотреть файл

@ -1,7 +1,9 @@
using System.ComponentModel.Composition;
using GitHub.Caches;
using GitHub.Models;
using GitHub.Primitives;
namespace GitHub
namespace GitHub.Factories
{
[Export(typeof(IRepositoryHostFactory))]
[PartCreationPolicy(CreationPolicy.Shared)]

Просмотреть файл

@ -1,9 +1,8 @@
using System.ComponentModel.Composition;
using Akavache;
using Akavache.Sqlite3;
using GitHub.Extensions;
namespace GitHub
namespace GitHub.Factories
{
[Export(typeof(IBlobCacheFactory))]
[PartCreationPolicy(CreationPolicy.Shared)]

Просмотреть файл

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Weavers>
<NullGuard />
<NullGuard ExcludeRegex="^GitHub.SampleData.*$" />
</Weavers>

Просмотреть файл

@ -11,6 +11,7 @@
<AssemblyName>GitHub.App</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<NuGetPackageImportStamp>5547d2f4</NuGetPackageImportStamp>
<WarningLevel>4</WarningLevel>
<RunCodeAnalysis>true</RunCodeAnalysis>
@ -41,7 +42,9 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\akavache.sqlite3.4.1.0\lib\Portable-Net45+Win8+WP8+Wpa81\Akavache.Sqlite3.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.ComponentModelHost, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="Microsoft.VisualStudio.Shell.12.0, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="Microsoft.VisualStudio.Shell.Immutable.10.0, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
@ -74,6 +77,9 @@
<Reference Include="SQLitePCL.raw">
<HintPath>..\..\packages\SQLitePCL.raw_basic.0.7.1\lib\net45\SQLitePCL.raw.dll</HintPath>
</Reference>
<Reference Include="Stateless">
<HintPath>..\..\packages\Stateless.2.5.11.0\lib\portable-net40+sl50+win+wp80\Stateless.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.ComponentModel.DataAnnotations" />
@ -107,20 +113,18 @@
<Link>Properties\SolutionInfo.cs</Link>
</Compile>
<None Include="AkavacheSqliteLinkerOverride.cs" />
<Compile Include="Authentication\IAccount.cs" />
<Compile Include="Authentication\ITwoFactorChallengeHandler.cs" />
<Compile Include="Authentication\TwoFactorChallengeHandler.cs" />
<Compile Include="Authentication\TwoFactorRequiredUserError.cs" />
<Compile Include="Caches\HostCache.cs" />
<Compile Include="Caches\HostCacheFactory.cs" />
<Compile Include="Caches\IBlobCacheFactory.cs" />
<Compile Include="Caches\IHostCache.cs" />
<Compile Include="Caches\IHostCacheFactory.cs" />
<Compile Include="Factories\HostCacheFactory.cs" />
<Compile Include="Factories\IBlobCacheFactory.cs" />
<Compile Include="Factories\IHostCacheFactory.cs" />
<Compile Include="Caches\ILoginCache.cs" />
<Compile Include="Caches\ISharedCache.cs" />
<Compile Include="Caches\LoginCache.cs" />
<Compile Include="Caches\SharedCache.cs" />
<Compile Include="Caches\SqlitePersistentBlobCacheFactory.cs" />
<Compile Include="Factories\SqlitePersistentBlobCacheFactory.cs" />
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="Info\EnvironmentExtensions.cs" />
<Compile Include="Info\GitHubUrls.cs" />
<Compile Include="Infrastructure\AppModeDetector.cs" />
@ -131,33 +135,45 @@
<Compile Include="Models\LocalRepositoriesHost.cs" />
<Compile Include="Models\RepositoryHost.cs" />
<Compile Include="Models\RepositoryHosts.cs" />
<Compile Include="Models\IRepositoryHost.cs" />
<Compile Include="Models\IRepositoryHosts.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Services\AccountFactory.cs" />
<Compile Include="Services\ApiClient.cs" />
<Compile Include="Services\ApiClientFactory.cs" />
<Compile Include="SampleData\SampleViewModels.cs" />
<Compile Include="Factories\AccountFactory.cs" />
<Compile Include="Api\ApiClient.cs" />
<Compile Include="Factories\ApiClientFactory.cs" />
<None Include="Services\Browser.cs" />
<Compile Include="Services\EnterpriseProbe.cs" />
<Compile Include="Services\ErrorMap.cs" />
<Compile Include="Services\ErrorMessage.cs" />
<Compile Include="Services\ErrorMessageTranslator.cs" />
<Compile Include="Services\GitHubCredentialStore.cs" />
<Compile Include="Services\IAccountFactory.cs" />
<Compile Include="Services\IApiClient.cs" />
<Compile Include="Services\IApiClientFactory.cs" />
<Compile Include="Services\IEnterpriseProbe.cs" />
<Compile Include="Services\IRepositoryHostFactory.cs" />
<Compile Include="Services\RepositoryHostFactory.cs" />
<Compile Include="Factories\RepositoryHostFactory.cs" />
<Compile Include="Services\StandardUserErrors.cs" />
<Compile Include="Controllers\UIController.cs" />
<Compile Include="Services\Translation.cs" />
<Compile Include="UserErrors\PublishRepositoryUserError.cs" />
<Compile Include="UserErrors\PrivateRepositoryOnFreeAccountUserError.cs" />
<Compile Include="UserErrors\PrivateRepositoryQuotaExceededUserError.cs" />
<Compile Include="ViewModels\CreateRepoViewModel.cs" />
<Compile Include="ViewModels\CloneRepoViewModel.cs" />
<Compile Include="ViewModels\LoginControlViewModel.cs" />
<Compile Include="ViewModels\TwoFactorDialogViewModel.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="FodyWeavers.xml" />
<Resource Include="Images\default_org_avatar.png" />
<Resource Include="Images\default_user_avatar.png" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GitHub.Exports.Reactive\GitHub.Exports.Reactive.csproj">
<Project>{e4ed0537-d1d9-44b6-9212-3096d7c3f7a1}</Project>
<Name>GitHub.Exports.Reactive</Name>
</ProjectReference>
<ProjectReference Include="..\GitHub.Exports\GitHub.Exports.csproj">
<Project>{9aea02db-02b5-409c-b0ca-115d05331a6b}</Project>
<Name>GitHub.Exports</Name>
@ -179,7 +195,6 @@
<Name>Rothko</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>

Двоичные данные
src/GitHub.App/GlobalSuppressions.cs Normal file

Двоичный файл не отображается.

Двоичные данные
src/GitHub.App/Images/default_org_avatar.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.7 KiB

Двоичные данные
src/GitHub.App/Images/default_user_avatar.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.9 KiB

Просмотреть файл

@ -1,25 +1,24 @@
using System.IO;
using Rothko;
using Environment = System.Environment;
using System;
namespace GitHub
namespace GitHub.Info
{
public static class EnvironmentExtensions
{
const string applicationName = "GitHub";
public static string GetLocalGitHubApplicationDataPath(this IEnvironment environment)
public static string GetLocalGitHubApplicationDataPath(this Rothko.IEnvironment environment)
{
return Path.Combine(environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
applicationName);
}
public static string GetApplicationDataPath(this IEnvironment environment)
public static string GetApplicationDataPath(this Rothko.IEnvironment environment)
{
return Path.Combine(environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), applicationName);
}
public static string GetProgramFilesPath(this IEnvironment environment)
public static string GetProgramFilesPath(this Rothko.IEnvironment environment)
{
return environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
}

Просмотреть файл

@ -1,5 +1,6 @@
using System;
using System.Globalization;
using GitHub.Models;
namespace GitHub.Info
{

Просмотреть файл

@ -1,13 +1,13 @@

using System;
using System.Diagnostics;
using System.Reactive;
using System.Reactive.Linq;
using Akavache;
using GitHub.Api;
using GitHub.Authentication;
using GitHub.Caches;
using GitHub.Primitives;
using NullGuard;
using ReactiveUI;
using GitHub.Exports;
namespace GitHub.Models
{

Просмотреть файл

@ -1,7 +1,8 @@
using System;
using GitHub.Authentication;
using GitHub.Factories;
using GitHub.Primitives;
using ReactiveUI;
using GitHub.Exports;
namespace GitHub.Models
{

Просмотреть файл

@ -1,9 +1,11 @@
using System;
using System.Reactive;
using System.Reactive.Linq;
using GitHub.Api;
using GitHub.Authentication;
using GitHub.Caches;
using GitHub.Primitives;
using ReactiveUI;
using GitHub.Exports;
namespace GitHub.Models
{

Просмотреть файл

@ -7,15 +7,18 @@ using System.Linq;
using System.Net;
using System.Reactive;
using System.Reactive.Linq;
using GitHub.Api;
using GitHub.Authentication;
using GitHub.Caches;
using GitHub.Extensions;
using GitHub.Extensions.Reactive;
using GitHub.Factories;
using GitHub.Primitives;
using GitHub.Services;
using NLog;
using Octokit;
using ReactiveUI;
using Authorization = Octokit.Authorization;
using GitHub.Exports;
namespace GitHub.Models
{

Просмотреть файл

@ -5,9 +5,11 @@ using System.Reactive;
using System.Reactive.Linq;
using Akavache;
using GitHub.Authentication;
using GitHub.Caches;
using GitHub.Extensions.Reactive;
using GitHub.Factories;
using GitHub.Primitives;
using ReactiveUI;
using GitHub.Exports;
namespace GitHub.Models
{

Просмотреть файл

@ -0,0 +1,193 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reactive;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using GitHub.Helpers;
using GitHub.Models;
using GitHub.Primitives;
using GitHub.Services;
using GitHub.Validation;
using GitHub.ViewModels;
using Octokit;
using ReactiveUI;
using Account = Octokit.Account;
namespace GitHub.SampleData
{
[ExcludeFromCodeCoverage]
public class CreateRepoViewModelDesigner : ReactiveObject, ICreateRepoViewModel
{
public CreateRepoViewModelDesigner()
{
RepositoryName = "Hello-World";
Description = "A description";
KeepPrivate = true;
Accounts = new ReactiveList<IAccount> { new AccountDesigner("GitHub") };
}
public string RepositoryName { get; private set; }
public string SafeRepositoryName { get; private set; }
public bool ShowRepositoryNameWarning { get; private set; }
public string RepositoryNameWarningText { get; private set; }
public ReactivePropertyValidator<string> RepositoryNameValidator { get; private set; }
public string Description { get; set; }
public ReactivePropertyValidator<IAccount> SelectedAccountValidator { get; private set; }
public bool KeepPrivate { get; set; }
public bool CanKeepPrivate { get; private set; }
public bool ShowUpgradeToMicroPlanWarning { get; private set; }
public bool ShowUpgradePlanWarning { get; private set; }
public ReactiveCommand<Unit> CreateRepository { get; private set; }
public bool IsPublishing { get; private set; }
public ReactiveCommand<Object> UpgradeAccountPlan { get; private set; }
public ReactiveCommand<Object> Reset { get; private set; }
public ReactiveList<IAccount> Accounts { get; private set; }
public IAccount SelectedAccount { get; private set; }
public ICommand OkCmd { get; private set; }
public ICommand CancelCmd { get; private set; }
}
[ExcludeFromCodeCoverage]
public sealed class AccountDesigner : ReactiveObject, IAccount
{
public AccountDesigner()
{
}
public AccountDesigner(string name)
{
Name = name;
Avatar = new AvatarProviderDesigner().DefaultOrgBitmapImage;
IsGitHubStaff = false;
IsSiteAdmin = false;
}
public object Avatar { get; set; }
public string Email { get; set; }
public int Id { get; set; }
public bool IsEnterprise { get; set; }
public bool IsGitHub { get; set; }
public bool IsLocal { get; set; }
public bool IsOnFreePlan { get; set; }
public bool HasMaximumPrivateRepositories { get; private set; }
public bool IsSelected { get; set; }
public bool IsUser { get; set; }
public bool IsSiteAdmin { get; private set; }
public bool IsGitHubStaff { get; private set; }
public IRepositoryHost Host { get; set; }
public string Login { get; set; }
public string Name { get; set; }
public int OwnedPrivateRepos { get; set; }
public long PrivateReposInPlan { get; set; }
public void Update(User ghUser)
{
throw new NotImplementedException();
}
public void Update(Organization org)
{
throw new NotImplementedException();
}
}
[ExcludeFromCodeCoverage]
public class AvatarProviderDesigner : IAvatarProvider
{
public AvatarProviderDesigner()
{
DefaultUserBitmapImage = ImageHelper.CreateBitmapImage("pack://application:,,,/GitHub.App;component/Images/default_user_avatar.png");
DefaultOrgBitmapImage = ImageHelper.CreateBitmapImage("pack://application:,,,/GitHub.App;component/Images/default_org_avatar.png");
}
public BitmapImage DefaultUserBitmapImage { get; private set; }
public BitmapImage DefaultOrgBitmapImage { get; private set; }
public IObservable<BitmapSource> GetAvatar(Account apiAccount)
{
throw new NotImplementedException();
}
public IObservable<Unit> InvalidateAvatar(Account apiAccount)
{
throw new NotImplementedException();
}
public IObservable<BitmapSource> GetAvatar(string email)
{
throw new NotImplementedException();
}
}
[ExcludeFromCodeCoverage]
public class RepositoryModelDesigner : ReactiveObject, IRepositoryModel
{
public RepositoryModelDesigner()
{
}
public RepositoryModelDesigner(string name)
{
Name = name;
}
public RepositoryModelDesigner(string name, string owner)
{
Owner = owner;
Name = name;
OwnerWithSlash = owner + "/";
NameWithOwner = OwnerWithSlash + name;
HasRemote = IsHosted = true;
AdditionalClones = new HashSet<string>();
ToolTip = "Repo Tooltip";
IsPrivate = true;
CanViewOnHost = true;
}
public DateTimeOffset? LastShadowBackupTime { get; set; }
public string LastShadowBackupSha1 { get; set; }
public bool IsSelected { get; set; }
public HostAddress HostAddress { get; private set; }
public int? Id { get; set; }
public bool IsLostOnDisk { get; set; }
public string LocalWorkingDirectory { get; set; }
public string LocalDotGitPath { get; set; }
public UriString CloneUrl { get; set; }
public UriString HttpsUrl { get; set; }
public UriString SshUrl { get; set; }
public UriString UpstreamCloneUrl { get; set; }
public bool HasRemote { get; set; }
public bool IsHosted { get; set; }
public bool HasLocal { get; set; }
public bool CanViewOnHost { get; private set; }
public IRepositoryHost RepositoryHost { get; set; }
string IRepositoryModel.Owner
{
get { return Owner; }
set { Owner = value; }
}
public int? OwnerId { get; set; }
public string Owner { get; set; }
public string OwnerWithSlash { get; set; }
public string Name { get; set; }
public string NameWithOwner { get; set; }
public string Description { get; set; }
public string ToolTip { get; set; }
public Uri HostUri { get; set; }
public bool IsCollaborator { get; set; }
public bool IsCloning { get; set; }
public bool IsFork { get; private set; }
public bool HasDeployedGitIgnore { get; set; }
public string NonGitHubRemoteHost { get; set; }
public HashSet<string> AdditionalClones { get; private set; }
public bool IsPrivate { get; set; }
}
}

Просмотреть файл

@ -1,9 +1,8 @@
using System;
using System.ComponentModel.Composition;
using System.Reactive.Threading.Tasks;
using GitHub.Models;
using Octokit.Internal;
using System.Reactive.Linq;
using System.Reactive.Threading.Tasks;
namespace GitHub.Services
{

Просмотреть файл

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ReactiveUI;
namespace GitHub.Services
{
public class ErrorMap
{
public ErrorMap(ErrorMessage defaultMessage) : this(defaultMessage, null, null)
{
}
public ErrorMap(ErrorMessage defaultMessage, IEnumerable<Translation> translations, IEnumerable<IRecoveryCommand> recoveryCommands)
{
this.defaultMessage = defaultMessage;
this.translations = translations;
RecoveryCommands = recoveryCommands;
}
readonly ErrorMessage defaultMessage;
readonly IEnumerable<Translation> translations;
public IEnumerable<IRecoveryCommand> RecoveryCommands { get; private set; }
public ErrorMessage GetErrorInfo(Exception exception)
{
if (exception != null && translations != null)
{
var translated = (from t in translations
let result = t.Translate(exception)
where result != null
select result).FirstOrDefault();
if (translated != null)
return translated;
}
return defaultMessage;
}
}
}

Просмотреть файл

@ -0,0 +1,33 @@
using System;
using System.Text.RegularExpressions;
namespace GitHub.Services
{
public class ErrorMessage
{
static readonly Regex placeholderRegex = new Regex(@"\$\d", RegexOptions.Compiled);
readonly Lazy<bool> headingHasPlaceholders;
readonly Lazy<bool> messageHasPlaceholders;
public ErrorMessage(string heading, string message)
{
Heading = heading;
headingHasPlaceholders = new Lazy<bool>(() => placeholderRegex.IsMatch(heading));
Message = message;
messageHasPlaceholders = new Lazy<bool>(() => placeholderRegex.IsMatch(message));
}
public string Heading { get; private set; }
public string Message { get; private set; }
public bool HeadingHasPlaceholders
{
get { return headingHasPlaceholders.Value; }
}
public bool MessageHasPlaceholders
{
get { return messageHasPlaceholders.Value; }
}
}
}

Просмотреть файл

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using ReactiveUI;
namespace GitHub.Services
{
public class ErrorMessageTranslator
{
readonly IDictionary<ErrorType, ErrorMap> userErrorMappings;
public ErrorMessageTranslator(IDictionary<ErrorType, ErrorMap> userErrors)
{
userErrorMappings = userErrors;
}
public UserError GetUserError(ErrorType errorType, Exception exception, params object[] context)
{
var translation = GetUserErrorTranslation(errorType, exception, context);
return new UserError(translation.ErrorMessage, translation.CauseOrResolution, translation.RecoveryCommands, null, exception)
{
UserErrorIcon = StockUserErrorIcon.Error
};
}
public UserErrorTranslation GetUserErrorTranslation(ErrorType errorType, Exception exception, params object[] context)
{
ErrorMessage errorMessage = null;
ErrorMap errorMap;
if (userErrorMappings.TryGetValue(ErrorType.Global, out errorMap) && errorMap != null)
{
errorMessage = errorMap.GetErrorInfo(exception);
}
if (errorMessage == null)
{
if (!userErrorMappings.TryGetValue(errorType, out errorMap) || errorMap == null)
throw new InvalidOperationException("This should never happen!");
}
errorMessage = errorMap.GetErrorInfo(exception) ?? new ErrorMessage("error", "Unknown error occurred");
string details = errorMessage.Message;
string heading = errorMessage.Heading;
if (context != null && context.Any())
{
heading = String.Format(CultureInfo.InvariantCulture, heading, context);
details = String.Format(CultureInfo.InvariantCulture, details, context);
}
return new UserErrorTranslation(heading, details, errorMap.RecoveryCommands);
}
public class UserErrorTranslation
{
public UserErrorTranslation(string errorMessage, string causeOrResolution, IEnumerable<IRecoveryCommand> recoveryCommands)
{
ErrorMessage = errorMessage;
CauseOrResolution = causeOrResolution;
RecoveryCommands = recoveryCommands;
}
public string ErrorMessage { get; private set; }
public string CauseOrResolution { get; private set; }
public IEnumerable<IRecoveryCommand> RecoveryCommands { get; private set; }
}
}
}

Просмотреть файл

@ -2,12 +2,13 @@
using System.Reactive.Linq;
using System.Threading.Tasks;
using Akavache;
using GitHub.Caches;
using GitHub.Extensions.Reactive;
using GitHub.Primitives;
using NLog;
using Octokit;
using LogManager = NLog.LogManager;
namespace GitHub
namespace GitHub.Services
{
public class GitHubCredentialStore : ICredentialStore
{

Просмотреть файл

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GitHub.Services
{

Просмотреть файл

@ -1,7 +1,17 @@
using System;
using System.Reactive.Linq;
using System.Windows;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Net.Http;
using GitHub.Extensions;
using GitHub.Info;
using GitHub.Models;
using NLog;
using Octokit;
using ReactiveUI;
using ApiClient = GitHub.Api.ApiClient;
namespace GitHub.Services
{
@ -14,6 +24,7 @@ namespace GitHub.Services
BranchUnpublishFailed,
BranchListFailed,
CannotDropFolder,
CannotDropFolderUnauthorizedAccess,
ClipboardFailed,
ClonedFailed,
CloneFailedNotLoggedIn,
@ -44,6 +55,7 @@ namespace GitHub.Services
ShellFailed,
CustomShellFailed,
WorkingDirectoryDoesNotExist,
DefaultClonePathInvalid,
MergeFailed,
PowerShellNotFound,
LoadingCommitsFailed,
@ -56,14 +68,227 @@ namespace GitHub.Services
public static class StandardUserErrors
{
public static IObservable<RecoveryOptionResult> ShowUserErrorMessage(
this Exception ex, ErrorType errorType, params object[] messageArgs)
internal static readonly Lazy<ErrorMessageTranslator> Translator = new Lazy<ErrorMessageTranslator>(() => new ErrorMessageTranslator(new Dictionary<ErrorType, ErrorMap>
{
// TODO: Fix this. This is just placeholder logic. -@haacked
Console.WriteLine(errorType);
Console.WriteLine(messageArgs);
MessageBox.Show(ex.Message);
return Observable.Return(new RecoveryOptionResult());
{
// Exceptions are matched against global *FIRST* before they are matched against
// specific operations.
ErrorType.Global, Map(null,
new Translation("Cannot find config file '(.*?)'", "The Git configuration file is missing.", "The global Git configuration file '$1' could not be found. Please open the options menu from the dashboard and update your name and email settings to create a new one."),
new Translation<AuthorizationException>("Authentication failed", "Your credentials may be out of date. Please log out of the application and then log back in before retrying the operation."),
new Translation<LoginAttemptsExceededException>("Maximum login attempts exceeded", "Please log out of the application and then log back in before retrying the operation. You may need to wait a few minutes."),
new Translation("fatal: Authentication failed", "Authentication failed", "Your credentials may be out of date. Please log out of the application and then log back in before retrying the operation."),
new Translation(@"({""message"":""Bad credentials.?""}|Bad credentials.?)", "Authentication failed", "Your credentials may be out of date. Please log out of the application and then log back in before retrying the operation."),
new Translation<DirectoryNotFoundException>("Directory not found", "The directory does not exist"),
new Translation<UnauthorizedAccessException>("Access denied", "You do not have permissions to access this file or folder"),
new Translation("EPOLICYKEYAGE", "Unverified SSH Key", "{0}", ParseUnverifiedSshKeyMessageFromExceptionMessage))
},
{
ErrorType.BranchCreateFailed, Map(Defaults("Failed to create new branch"),
new Translation("No valid git object identified by '.+?' exists in the repository.", "Failed to create branch", "The current branch doesnt have any commits."))
},
{
ErrorType.BranchDeleteFailed, Map(Defaults("error", "Failed to delete the branch."),
new Translation(@"fatal: .*? not found: did you run git update-server-info on the server\?",
"Failed to delete the branch",
"Please make sure the repository exists and that you have permissions to change it."),
new Translation("error: The requested URL returned error: 403 while accessing .*",
"Failed to delete the branch",
"Please make sure the repository exists and that you have permissions to change it."),
new Translation("fatal: Could not read from remote repository.",
"Failed to delete the branch",
"Please make sure the repository exists and that you have permissions to change it."),
new Translation(@".*?\(deletion of the current branch prohibited\).*",
"Cannot delete the default branch",
"To delete this branch, log in to " + ApiClient.GitHubDotComHostName + " and change " +
"the repositorys default branch to another branch first."))
},
{
ErrorType.BranchUnpublishFailed, Map(Defaults("error", "Failed to unpublish the branch."),
new Translation(@"fatal: .*? not found: did you run git update-server-info on the server\?",
"Failed to unpublish the branch",
"Please make sure the repository exists and that you have permissions to change it."),
new Translation("error: The requested URL returned error: 403 while accessing .*",
"Failed to unpublish the branch",
"Please make sure the repository exists and that you have permissions to change it."),
new Translation("fatal: Could not read from remote repository.",
"Failed to unpublish the branch",
"Please make sure the repository exists and that you have permissions to change it."),
new Translation(@".*?\(deletion of the current branch prohibited\).*",
"Cannot unpublish the default branch",
"To unpublish this branch, log in to " + ApiClient.GitHubDotComHostName + " and change " +
"the repositorys default branch to another branch first."))
},
{ ErrorType.ClipboardFailed, Map(Defaults("Failed to copy text to the clipboard.")) },
{
ErrorType.ClonedFailed, Map(Defaults("Failed to clone the repository '{0}'", "Please check your log file for more details, or email support if you are still having problems."),
new[]
{
new Translation(@"fatal: bad config file line (\d+) in (.+)", "Failed to clone the repository '{0}'", @"The config file '$2' is corrupted at line $1. You may need to open the file and try to fix any errors."),
new Translation("Process timed out", "Failed to clone the repository '{0}'", "The process timed out. The repository is in an unknown state and likely corrupted. Try deleting it and cloning again."),
new Translation("Local inaccessible repositories already exist.", "Failed to clone the repository '{0}'", "Local directories with this repositorys name already exist but cant be accessed. Try deleting them and trying again."),
new Translation("Repo directory '(.*?)' already exists.", "Failed to clone the repository '{0}'", "Could not clone the repository '{0}' because the directory\n'$1' already exists and isnt empty."),
new Translation("Local clone at '(.*?)' is corrupted", "Failed to clone the repository '{0}'", "Failed to clone the repository because a local one exists already at '$1', but is corrupted. You will need to open a shell to debug the state of this repo."),
new Translation("Your local changes to the following files would be overwritten by checkout", "Failed to check out branch", "Failed to check out branch because because local changes would be overwritten. Try committing changes and then checking out the branch again")
})
},
{ ErrorType.CloneFailedNotLoggedIn, Map(Defaults("Clone failed", "Please login to your account before attempting to clone this repository.")) },
{ ErrorType.EnterpriseConnectFailed, Map(Defaults("Connecting to GitHub Enterprise instance failed", "Could not find a GitHub Enterprise instance at '{0}'. Double check the URL and your internet/intranet connection.")) },
{ ErrorType.LaunchEnterpriseConnectionFailed, Map(Defaults("Failed to launch the enterprise connection.")) },
{ ErrorType.LogFileError, Map(Defaults("Could not open the log file", "Could not find or open the log file.")) },
{ ErrorType.LoginFailed, Map(Defaults("login failed", "Unable to retrieve your user info from the server. A proxy server might be interfering with the request.")) },
{ ErrorType.RepoCreationAsPrivateNotAvailableForFreePlan, Map(Defaults("Failed to create private repository", "You are currently on a free plan and unable to create private repositories. Either make the repository public or upgrade your account on the website to a plan that allows for private repositories.")) },
{ ErrorType.RepoCreationFailed, Map(Defaults("Failed to create repository", "An error occurred while creating the repository. You might need to open a shell and debug the state of this repo.")) },
{ ErrorType.RepoExistsOnDisk, Map(Defaults("Failed to create repository", "There is already a repository named '{0}' in the directory\n'{1}'.")) },
{ ErrorType.RepositoryNotFoundOnDisk, Map(Defaults("Repository not found", "Could not find the repository '{0}' in the location '{1}'.\nDid you move it somewhere else on your filesystem?")) },
{ ErrorType.RepoExistsForUser, Map(Defaults("Failed to create repository", "There is already a repository named '{0}' in your GitHub account.")) },
{ ErrorType.RepoExistsInOrganization, Map(Defaults("Failed to create repository", "There is already a repository named '{0}' in the organization '{1}'.")) },
{ ErrorType.LoadingWorkingDirectoryFailed, Map(Defaults("Failed to refresh the working directory", "You might need to open a shell and debug the state of this repo.")) },
{
ErrorType.RefreshFailed, Map(Defaults("Refresh failed", "Refresh failed unexpectedly. Please email support@github.com if this error persists."),
new Translation<HttpRequestException>("Refresh failed", "Could not connect to the remote server. The server or your internect connection could be down")) },
}));
[SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
static readonly Logger log = LogManager.GetCurrentClassLogger();
public static IObservable<RecoveryOptionResult> ShowUserErrorMessage(this Exception exception, ErrorType errorType, params object[] messageArgs)
{
return exception.DisplayErrorMessage(errorType, messageArgs, null);
}
public static IObservable<RecoveryOptionResult> ShowUserErrorMessage(ErrorType errorType, params object[] messageArgs)
{
return DisplayErrorMessage(null, errorType, messageArgs, null);
}
public static IObservable<RecoveryOptionResult> ShowUserThatRepoAlreadyExists(string repositoryName, string fullPath)
{
return DisplayErrorMessage(ErrorType.RepoExistsOnDisk, new object[] { repositoryName, fullPath }, new[] { OpenPathInExplorer(fullPath), Cancel });
}
public static IObservable<RecoveryOptionResult> ShowCloneError(this Exception exception,
ErrorType errorType,
string displayName,
string repositoryLocalWorkingDirectory)
{
return exception.DisplayErrorMessage(errorType, new object[] { displayName }, null);
}
public static IObservable<RecoveryOptionResult> ShowUserErrorThatRequiresNavigatingToBilling(
this Exception exception,
IAccount account)
{
var errorType = (exception is PrivateRepositoryQuotaExceededException && account.IsOnFreePlan)
? ErrorType.RepoCreationAsPrivateNotAvailableForFreePlan
: ErrorType.RepoCreationOnGitHubFailed;
return exception.DisplayErrorMessage(
errorType,
new object[] { },
new[] { OpenBrowser("View Plans", account.Billing()), Cancel });
}
static IObservable<RecoveryOptionResult> DisplayErrorMessage(ErrorType errorType, object[] messageArgs, IEnumerable<IRecoveryCommand> recoveryOptions)
{
return DisplayErrorMessage(null, errorType, messageArgs, recoveryOptions);
}
static IObservable<RecoveryOptionResult> DisplayErrorMessage(this Exception exception, ErrorType errorType, object[] messageArgs, IEnumerable<IRecoveryCommand> recoveryOptions)
{
var userError = Translator.Value.GetUserError(errorType, exception, messageArgs);
if (recoveryOptions != null)
{
userError.RecoveryOptions.AddRange(recoveryOptions);
}
if (!userError.RecoveryOptions.Any())
userError.RecoveryOptions.Add(Ok);
return userError.Throw();
}
public static string ParseUnverifiedSshKeyMessageFromExceptionMessage(Exception exception)
{
var index = exception.Message.IndexOf("[EPOLICYKEYAGE]", StringComparison.OrdinalIgnoreCase);
return index != -1 ?
exception.Message.Remove(index).Trim()
: exception.Message;
}
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
static IRecoveryCommand Ok
{
get
{
return new RecoveryCommandWithIcon("OK", "check", x => RecoveryOptionResult.CancelOperation)
{
IsDefault = true,
IsCancel = true
};
}
}
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
static IRecoveryCommand Cancel
{
get
{
return new RecoveryCommandWithIcon("Cancel", "x", x => RecoveryOptionResult.CancelOperation)
{
IsCancel = true
};
}
}
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
static IRecoveryCommand OpenPathInExplorer(string path)
{
return new RecoveryCommandWithIcon("Open in Explorer", "file_directory", x =>
{
Process.Start(path);
return RecoveryOptionResult.CancelOperation;
});
}
[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "url")]
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
static IRecoveryCommand OpenBrowser(string text, string url)
{
return new RecoveryCommandWithIcon(text, "link_external", x =>
{
//IoC.Get<IBrowser>().OpenUrl(url);
return RecoveryOptionResult.CancelOperation;
})
{
IsDefault = true,
};
}
static IObservable<RecoveryOptionResult> Throw(this UserError error)
{
//log.WarnException("Showing user error " + error.ErrorCauseOrResolution, error.InnerException);
return UserError.Throw(error);
}
static ErrorMessage Defaults(string heading, string description)
{
return new ErrorMessage(heading, description);
}
static ErrorMessage Defaults(string description)
{
return new ErrorMessage("error", description);
}
static ErrorMap Map(ErrorMessage defaultMessage, params Translation[] translations)
{
return new ErrorMap(defaultMessage, translations, null);
}
static ErrorMap Map(ErrorMessage defaultMessage, IEnumerable<IRecoveryCommand> recoveryCommands)
{
return new ErrorMap(defaultMessage, null, recoveryCommands);
}
}
}

Просмотреть файл

@ -0,0 +1,122 @@
using System;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using GitHub.Extensions;
using Newtonsoft.Json;
using Octokit;
namespace GitHub.Services
{
public class Translation
{
readonly ErrorMessage defaultMessage;
readonly Func<Exception, ErrorMessage> translator;
public Translation(string original, string heading, string message)
{
Original = original;
defaultMessage = new ErrorMessage(heading, message);
}
public Translation(string original, Func<Exception, ErrorMessage> translator)
{
Original = original;
this.translator = translator;
}
public Translation(string original, string heading, string messageFormatString, Func<Exception, string> translator) : this(original, heading, messageFormatString)
{
this.translator = e => new ErrorMessage(heading, String.Format(CultureInfo.InvariantCulture, messageFormatString, translator(e)));
}
public string Original { get; private set; }
public ErrorMessage Translate(Exception exception)
{
if (exception == null) throw new ArgumentNullException("exception");
var match = Match(exception);
if (match == null) return null;
if (translator == null)
{
var exceptionMessageLine = match.Item2;
if (exceptionMessageLine != null)
{
var heading = defaultMessage.HeadingHasPlaceholders
? Regex.Replace(exceptionMessageLine, Original, defaultMessage.Heading)
: defaultMessage.Heading;
var message = defaultMessage.MessageHasPlaceholders
? Regex.Replace(exceptionMessageLine, Original, defaultMessage.Message)
: defaultMessage.Message;
return new ErrorMessage(heading, message);
}
return defaultMessage;
}
return translator(exception);
}
// Returns a tuple indicating whether this translation is a match for the exception and the regex line if existing.
protected virtual Tuple<Translation, string> Match(Exception exception)
{
string exceptionMessage = exception.Message;
var apiException = exception as ApiValidationException;
if (apiException != null && apiException.ApiError != null && apiException.ApiError.Errors != null)
{
var error = apiException.ApiError.Errors.FirstOrDefault();
if (error != null)
exceptionMessage = error.Message ?? exceptionMessage;
}
if (Original == exceptionMessage) return new Tuple<Translation, string>(this, null);
var exceptionMessageLines = exceptionMessage.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
if (exceptionMessageLines.Any(l => l == Original)) return new Tuple<Translation, string>(this, null);
try
{
// If the response is a JSON response from the API, let's
// look at all the messages for an exact match.
var githubError =
exceptionMessage.StartsWith('{') || exceptionMessage.StartsWith('[')
? JsonConvert.DeserializeObject<ApiError>(exceptionMessage)
: null;
if (githubError != null
&& (githubError.Message == Original
|| (githubError.Errors != null && githubError.Errors.Any(e => e.Message == Original))))
{
return new Tuple<Translation, string>(this, null);
}
}
catch (Exception)
{
// Ignore. We were probably wrong about this being a proper GitHubError API response.
}
var regexMatchingLine = exceptionMessageLines.FirstOrDefault(l => Regex.IsMatch(l, Original, RegexOptions.IgnoreCase));
return regexMatchingLine != null ? new Tuple<Translation, string>(this, regexMatchingLine) : null;
}
}
public class Translation<TException> : Translation where TException : Exception
{
public Translation(string heading, string message) : base(null, heading, message)
{
}
public Translation(string heading) : base(null, e => new ErrorMessage(heading, e.Message))
{
}
protected override Tuple<Translation, string> Match(Exception exception)
{
if (exception is TException) return new Tuple<Translation, string>(null, null);
return null;
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
using ReactiveUI;
namespace GitHub.UserErrors
{
public class PrivateRepositoryOnFreeAccountUserError : PublishRepositoryUserError
{
public PrivateRepositoryOnFreeAccountUserError(string errorMessage, string errorCauseOrResolution = null)
: base(errorMessage, errorCauseOrResolution)
{
UserErrorIcon = StockUserErrorIcon.Error;
}
}
}

Просмотреть файл

@ -0,0 +1,30 @@
using System;
using System.Globalization;
using GitHub.Models;
using ReactiveUI;
namespace GitHub.UserErrors
{
public class PrivateRepositoryQuotaExceededUserError : PublishRepositoryUserError
{
public PrivateRepositoryQuotaExceededUserError(IAccount account, string errorMessage, string errorCauseOrResolution = null)
: base(errorMessage, errorCauseOrResolution)
{
UserErrorIcon = StockUserErrorIcon.Error;
UsedPrivateSlots = account.OwnedPrivateRepos;
AvaliblePrivateSlots = account.PrivateReposInPlan;
}
public long AvaliblePrivateSlots { get; set; }
public int UsedPrivateSlots { get; set; }
public static IObservable<RecoveryOptionResult> Throw(IAccount account)
{
var errorMessage = string.Format(CultureInfo.InvariantCulture,
"You are using {0} out of {1} private repositories.", account.OwnedPrivateRepos, account.PrivateReposInPlan);
return Throw(new PrivateRepositoryQuotaExceededUserError(account, errorMessage));
}
}
}

Просмотреть файл

@ -0,0 +1,43 @@
using System;
using System.Diagnostics.CodeAnalysis;
using GitHub.Models;
using GitHub.Services;
using Octokit;
using ReactiveUI;
namespace GitHub.UserErrors
{
public class PublishRepositoryUserError : UserError
{
public PublishRepositoryUserError(string errorMessage, string errorCauseOrResolution = null)
: base(errorMessage, errorCauseOrResolution)
{
UserErrorIcon = StockUserErrorIcon.Error;
}
public static IObservable<RecoveryOptionResult> Throw(Exception innerException = null)
{
var translation = StandardUserErrors.Translator.Value.GetUserErrorTranslation(ErrorType.RepoCreationOnGitHubFailed, innerException);
return Throw(new PublishRepositoryUserError(translation.ErrorMessage, translation.CauseOrResolution));
}
public static IObservable<RecoveryOptionResult> Throw(string errorMessage, string errorCauseOrResolution = null)
{
return Throw(new PublishRepositoryUserError(errorMessage, errorCauseOrResolution));
}
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Because no. It's only for that kind of exception")]
public static void ThrowPrivateQuotaExceeded(PrivateRepositoryQuotaExceededException exception, IAccount account)
{
if (account.IsOnFreePlan)
{
var translation = StandardUserErrors.Translator.Value.GetUserErrorTranslation(ErrorType.RepoCreationOnGitHubFailed, exception);
Throw(new PrivateRepositoryOnFreeAccountUserError(translation.ErrorMessage, translation.CauseOrResolution));
}
else
{
PrivateRepositoryQuotaExceededUserError.Throw(account);
}
}
}
}

Просмотреть файл

@ -0,0 +1,26 @@
using System;
using System.ComponentModel.Composition;
using System.Windows.Input;
using GitHub.Exports;
using GitHub.Models;
using ReactiveUI;
namespace GitHub.ViewModels
{
[ExportViewModel(ViewType=UIViewType.Clone)]
public class CloneRepoViewModel : ICloneRepoViewModel
{
public ReactiveCommand<object> CancelCommand { get; private set; }
public ICommand CancelCmd { get { return CancelCommand; } }
public IObservable<object> Cancelling { get { return CancelCommand; } }
public ReactiveCommand<object> OkCommand { get; private set; }
public ICommand OkCmd { get { return OkCommand; } }
[ImportingConstructor]
public CloneRepoViewModel(IRepositoryHosts hosts)
{
}
}
}

Просмотреть файл

@ -0,0 +1,39 @@
using System;
using System.Reactive;
using System.Windows.Input;
using GitHub.Models;
using GitHub.Validation;
using ReactiveUI;
using GitHub.Exports;
namespace GitHub.ViewModels
{
[ExportViewModel(ViewType=UIViewType.Create)]
public class CreateRepoViewModel : ICreateRepoViewModel
{
public ReactiveCommand<object> CancelCommand { get; private set; }
public ICommand CancelCmd { get { return CancelCommand; } }
public ReactiveCommand<object> OkCommand { get; private set; }
public ICommand OkCmd { get { return OkCommand; } }
public string RepositoryName { get; private set; }
public string SafeRepositoryName { get; private set; }
public bool ShowRepositoryNameWarning { get; private set; }
public string RepositoryNameWarningText { get; private set; }
public ReactivePropertyValidator<string> RepositoryNameValidator { get; private set; }
public string Description { get; set; }
public ReactivePropertyValidator<IAccount> SelectedAccountValidator { get; private set; }
public bool KeepPrivate { get; set; }
public bool CanKeepPrivate { get; private set; }
public bool ShowUpgradeToMicroPlanWarning { get; private set; }
public bool ShowUpgradePlanWarning { get; private set; }
public ReactiveCommand<Unit> CreateRepository { get; private set; }
public bool IsPublishing { get; private set; }
public ReactiveCommand<Object> UpgradeAccountPlan { get; private set; }
public ReactiveCommand<Object> Reset { get; private set; }
public ReactiveList<IAccount> Accounts { get; private set; }
public IAccount SelectedAccount { get; private set; }
}
}

Просмотреть файл

@ -5,23 +5,24 @@ using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Windows.Input;
using GitHub.Authentication;
using GitHub.Exports;
using GitHub.Extensions;
using GitHub.Info;
using GitHub.Models;
using GitHub.Primitives;
using GitHub.Services;
using GitHub.Validation;
using GitHub.Exports;
using NullGuard;
using ReactiveUI;
using System.Windows.Input;
namespace GitHub.ViewModels
{
[SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable")]
[Export(typeof(ILoginDialog))]
[ExportViewModel(ViewType=UIViewType.Login)]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class LoginControlViewModel : ReactiveValidatableObject, ILoginDialog, IDisposable
public class LoginControlViewModel : ReactiveValidatableObject, ILoginViewModel, IDisposable
{
readonly Lazy<IEnterpriseProbe> lazyEnterpriseProbe;
const string notEnterpriseServerError = "Not an Enterprise server. Please enter an Enterprise URL";
@ -30,7 +31,7 @@ namespace GitHub.ViewModels
public ICommand LoginCmd { get { return LoginCommand; } }
public ReactiveCommand<object> CancelCommand { get; private set; }
public ICommand CancelCmd { get { return CancelCommand; } }
public IObservable<object> CancelEvt { get { return CancelCommand; } }
public IObservable<object> Cancelling { get { return CancelCommand; } }
public ReactiveCommand<object> ForgotPasswordCommand { get; private set; }
public ReactiveCommand<object> ShowDotComLoginCommand { get; set; }

Просмотреть файл

@ -2,19 +2,20 @@
using System.ComponentModel.Composition;
using System.ComponentModel.DataAnnotations;
using System.Reactive.Linq;
using System.Windows.Input;
using GitHub.Authentication;
using GitHub.Exports;
using GitHub.Services;
using GitHub.Validation;
using NullGuard;
using Octokit;
using ReactiveUI;
using GitHub.Exports;
namespace GitHub.ViewModels
{
[Export(typeof(ITwoFactorDialog))]
[Export(typeof(ITwoFactorViewModel))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class TwoFactorDialogViewModel : ReactiveValidatableObject, ITwoFactorDialog
public class TwoFactorDialogViewModel : ReactiveValidatableObject, ITwoFactorViewModel
{
bool isAuthenticationCodeSent;
string authenticationCode;
@ -106,6 +107,11 @@ namespace GitHub.ViewModels
public ReactiveCommand<RecoveryOptionResult> ShowHelpCommand { get; private set; }
public ReactiveCommand<RecoveryOptionResult> ResendCodeCommand { get; private set; }
public ICommand OkCmd { get { return OkCommand; } }
public ICommand CancelCmd { get { return CancelCommand; } }
public ICommand ShowHelpCmd { get { return ShowHelpCommand; } }
public ICommand ResendCodeCmd { get { return ResendCodeCommand; } }
public IObservable<RecoveryOptionResult> Show(TwoFactorRequiredUserError error)
{
TwoFactorType = error.TwoFactorType;

Просмотреть файл

@ -19,4 +19,5 @@
<package id="Rx-XAML" version="2.2.5" targetFramework="net45" />
<package id="Splat" version="1.6.0" targetFramework="net45" />
<package id="SQLitePCL.raw_basic" version="0.7.1" targetFramework="net45" />
<package id="Stateless" version="2.5.11.0" targetFramework="net45" />
</packages>

Просмотреть файл

@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using GitHub.Authentication;
using GitHub.Primitives;
using Octokit;
namespace GitHub
namespace GitHub.Api
{
public interface IApiClient
{

Просмотреть файл

@ -1,9 +1,10 @@
using System;
using System.Collections.Generic;
using System.Reactive;
using GitHub.Models;
using Octokit;
namespace GitHub
namespace GitHub.Caches
{
/// <summary>
/// Per host cache data.

Просмотреть файл

@ -1,15 +1,16 @@
using GitHub.Models;
using Octokit;
namespace GitHub
namespace GitHub.Factories
{
public interface IAccountFactory
{
IAccount CreateAccount(
IRepositoryHost repositoryHost,
Octokit.User user);
User user);
IAccount CreateAccount(
IRepositoryHost repositoryHost,
Octokit.Organization organization);
Organization organization);
}
}

Просмотреть файл

@ -1,4 +1,7 @@
namespace GitHub
using GitHub.Api;
using GitHub.Primitives;
namespace GitHub.Factories
{
public interface IApiClientFactory
{

Просмотреть файл

@ -1,6 +1,7 @@
using GitHub.Models;
using GitHub.Primitives;
namespace GitHub
namespace GitHub.Factories
{
public interface IRepositoryHostFactory
{

Просмотреть файл

@ -0,0 +1,112 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{E4ED0537-D1D9-44B6-9212-3096D7C3F7A1}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>GitHub</RootNamespace>
<AssemblyName>GitHub.Exports.Reactive</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Octokit">
<HintPath>..\..\packages\Octokit.0.6.2\lib\net45\Octokit.dll</HintPath>
</Reference>
<Reference Include="PresentationCore" />
<Reference Include="ReactiveUI">
<HintPath>..\..\packages\reactiveui-core.6.3.1\lib\Net45\ReactiveUI.dll</HintPath>
</Reference>
<Reference Include="Splat">
<HintPath>..\..\packages\Splat.1.6.0\lib\Net45\Splat.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Reactive.Core">
<HintPath>..\..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll</HintPath>
</Reference>
<Reference Include="System.Reactive.Interfaces">
<HintPath>..\..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll</HintPath>
</Reference>
<Reference Include="System.Reactive.Linq">
<HintPath>..\..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll</HintPath>
</Reference>
<Reference Include="System.Reactive.PlatformServices">
<HintPath>..\..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll</HintPath>
</Reference>
<Reference Include="System.Reactive.Windows.Threading">
<HintPath>..\..\packages\Rx-XAML.2.2.5\lib\net45\System.Reactive.Windows.Threading.dll</HintPath>
</Reference>
<Reference Include="Microsoft.TeamFoundation.Controls, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\Microsoft.TeamFoundation.Controls.dll</HintPath>
</Reference>
<Reference Include="System.Xaml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\script\SolutionInfo.cs">
<Link>Properties\SolutionInfo.cs</Link>
</Compile>
<Compile Include="Factories\IApiClientFactory.cs" />
<Compile Include="Factories\IAccountFactory.cs" />
<Compile Include="Authentication\ITwoFactorChallengeHandler.cs" />
<Compile Include="Caches\IHostCache.cs" />
<Compile Include="Factories\IRepositoryHostFactory.cs" />
<Compile Include="Models\IAccount.cs" />
<Compile Include="Models\IRepositoryHost.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Api\IApiClient.cs" />
<Compile Include="Services\IAvatarProvider.cs" />
<Compile Include="ViewModels\ICreateRepoViewModel.cs" />
<Compile Include="Validation\ReactivePropertyValidator.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GitHub.Exports\GitHub.Exports.csproj">
<Project>{9aea02db-02b5-409c-b0ca-115d05331a6b}</Project>
<Name>GitHub.Exports</Name>
</ProjectReference>
<ProjectReference Include="..\GitHub.Extensions\GitHub.Extensions.csproj">
<Project>{6afe2e2d-6db0-4430-a2ea-f5f5388d2f78}</Project>
<Name>GitHub.Extensions</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Просмотреть файл

@ -1,10 +1,8 @@
using GitHub.Models;
using Octokit;
using ReactiveUI;
using Octokit;
namespace GitHub
namespace GitHub.Models
{
public interface IAccount : IReactiveObject
public interface IAccount
{
string Email { get; }
int Id { get; }

Просмотреть файл

@ -1,11 +1,14 @@
using System;
using System.Reactive;
using GitHub.Api;
using GitHub.Authentication;
using GitHub.Caches;
using GitHub.Primitives;
using ReactiveUI;
using GitHub.Exports;
namespace GitHub.Models
{
public interface IRepositoryHost : IReactiveObject
public interface IRepositoryHost
{
HostAddress Address { get; }
IApiClient ApiClient { get; }

Просмотреть файл

@ -0,0 +1,6 @@
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("GitHub.Exports.Reactive")]
[assembly: AssemblyDescription("GitHub interfaces for mef exports with reactive dependencies")]
[assembly: Guid("e4ed0537-d1d9-44b6-9212-3096d7c3f7a1")]

Просмотреть файл

@ -0,0 +1,21 @@
using System;
using System.Reactive;
using System.Windows.Media.Imaging;
using Octokit;
namespace GitHub.Services
{
public interface IHostAvatarProvider
{
IAvatarProvider Get(string gitHubBaseUrl);
}
public interface IAvatarProvider
{
BitmapImage DefaultUserBitmapImage { get; }
BitmapImage DefaultOrgBitmapImage { get; }
IObservable<BitmapSource> GetAvatar(Account apiAccount);
IObservable<Unit> InvalidateAvatar(Account apiAccount);
IObservable<BitmapSource> GetAvatar(string email);
}
}

Просмотреть файл

@ -10,7 +10,7 @@ using System.Threading.Tasks;
using GitHub.Extensions;
using ReactiveUI;
namespace GitHub.UI
namespace GitHub.Validation
{
public class ReactivePropertyValidationResult
{

Просмотреть файл

@ -0,0 +1,36 @@
using System;
using System.Reactive;
using System.Windows.Input;
using GitHub.Models;
using GitHub.Validation;
using ReactiveUI;
namespace GitHub.ViewModels
{
public interface ICreateRepoViewModel : IViewModel
{
string RepositoryName { get; }
string SafeRepositoryName { get; }
bool ShowRepositoryNameWarning { get; }
string RepositoryNameWarningText { get; }
ReactivePropertyValidator<string> RepositoryNameValidator { get; }
string Description { get; set; }
ReactiveList<IAccount> Accounts { get; }
IAccount SelectedAccount { get; }
bool KeepPrivate { get; set; }
bool CanKeepPrivate { get; }
bool ShowUpgradeToMicroPlanWarning { get; }
bool ShowUpgradePlanWarning { get; }
bool IsPublishing { get; }
ReactiveCommand<Unit> CreateRepository { get; }
ReactiveCommand<Object> UpgradeAccountPlan { get; }
ReactiveCommand<Object> Reset { get; }
ICommand OkCmd { get; }
ICommand CancelCmd { get; }
}
}

Просмотреть файл

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Octokit" version="0.6.2" targetFramework="net45" />
<package id="reactiveui" version="6.3.1" targetFramework="net45" />
<package id="reactiveui-core" version="6.3.1" targetFramework="net45" />
<package id="Rx-Core" version="2.2.5" targetFramework="net45" />
<package id="Rx-Interfaces" version="2.2.5" targetFramework="net45" />
<package id="Rx-Linq" version="2.2.5" targetFramework="net45" />
<package id="Rx-Main" version="2.2.5" targetFramework="net45" />
<package id="Rx-PlatformServices" version="2.2.5" targetFramework="net45" />
<package id="Rx-XAML" version="2.2.5" targetFramework="net45" />
<package id="Splat" version="1.6.0" targetFramework="net45" />
</packages>

Просмотреть файл

@ -1,10 +1,8 @@
using GitHub.Services;
using Octokit;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
using System.Threading.Tasks;
using GitHub.Primitives;
using GitHub.Services;
using Octokit;
namespace GitHub.Api
{

Просмотреть файл

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GitHub.Api
{

Просмотреть файл

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GitHub.Exports
namespace GitHub.Authentication
{
public enum AuthenticationResult
{

Просмотреть файл

@ -1,6 +1,4 @@
using GitHub.Exports;
namespace GitHub.Authentication
namespace GitHub.Authentication
{
public static class AuthenticationResultExtensions

Просмотреть файл

@ -0,0 +1,43 @@
using System;
using System.ComponentModel.Composition;
using GitHub.UI;
using GitHub.ViewModels;
namespace GitHub.Exports {
public enum UIViewType {
None,
Login,
TwoFactor,
Create,
Clone,
End = 100
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
public sealed class ExportViewModelAttribute : ExportAttribute
{
public ExportViewModelAttribute() : base(typeof(IViewModel))
{
}
public UIViewType ViewType { get; set; }
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
public sealed class ExportViewAttribute : ExportAttribute
{
public ExportViewAttribute() : base(typeof(IView))
{
}
public UIViewType ViewType { get; set; }
}
public interface IViewModelMetadata
{
UIViewType ViewType { get; }
}
}

Просмотреть файл

@ -42,31 +42,45 @@
<Reference Include="Octokit">
<HintPath>..\..\packages\Octokit.0.6.2\lib\net45\Octokit.dll</HintPath>
</Reference>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="Authentication\AuthenticationResultExtensions.cs" />
<Compile Include="Helpers\ImageHelper.cs" />
<Compile Include="Models\IProgram.cs" />
<Compile Include="Api\ISimpleApiClient.cs" />
<Compile Include="Api\ISimpleApiClientFactory.cs" />
<Compile Include="Authentication\AuthenticationResult.cs" />
<Compile Include="Models\IRepositoryModel.cs" />
<Compile Include="Exports\ExportMetadata.cs" />
<Compile Include="Primitives\StringEquivalent.cs" />
<Compile Include="Primitives\UriString.cs" />
<Compile Include="Services\EnterpriseProbeTask.cs" />
<Compile Include="Services\ExportFactoryProvider.cs" />
<Compile Include="Services\IBrowser.cs" />
<Compile Include="Services\IEnterpriseProbeTask.cs" />
<Compile Include="Services\IUIProvider.cs" />
<Compile Include="Services\IWikiProbe.cs" />
<Compile Include="Services\WikiProbe.cs" />
<Compile Include="UI\ICloneDialog.cs" />
<Compile Include="UI\ILoginDialog.cs" />
<Compile Include="UI\ITwoFactorDialog.cs" />
<Compile Include="UI\IView.cs" />
<Compile Include="ViewModels\ICloneRepoViewModel.cs" />
<Compile Include="ViewModels\ILoginViewModel.cs" />
<Compile Include="ViewModels\ITwoFactorViewModel.cs" />
<Compile Include="Primitives\HostAddress.cs" />
<Compile Include="UI\IUIController.cs" />
<Compile Include="ViewModels\IViewModel.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="GlobalSuppressions.cs" />

Двоичные данные
src/GitHub.Exports/GlobalSuppressions.cs

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,15 @@
using System;
using System.Windows.Media.Imaging;
namespace GitHub.Helpers
{
public static class ImageHelper
{
public static BitmapImage CreateBitmapImage(string packUrl)
{
var bitmap = new BitmapImage(new Uri(packUrl));
bitmap.Freeze();
return bitmap;
}
}
}

Просмотреть файл

@ -0,0 +1,17 @@
using System;
using GitHub.Primitives;
namespace GitHub.Models
{
public interface IRepositoryModel
{
HostAddress HostAddress { get; }
int? Id { get; }
string Owner { get; set; }
string Name { get; }
string NameWithOwner { get; }
string Description { get; }
Uri HostUri { get; }
bool IsPrivate { get; }
}
}

Просмотреть файл

@ -2,7 +2,7 @@
using System.Globalization;
using GitHub.Extensions;
namespace GitHub
namespace GitHub.Primitives
{
public class HostAddress
{

Просмотреть файл

@ -0,0 +1,109 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Serialization;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace GitHub.Primitives
{
[Serializable]
public abstract class StringEquivalent<T> : ISerializable, IXmlSerializable where T : StringEquivalent<T>
{
protected string Value;
protected StringEquivalent(string value)
{
Value = value;
}
protected StringEquivalent()
{
}
public abstract T Combine(string addition);
[SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates", Justification = "Add doesn't make sense in the case of a string equivalent")]
public static T operator +(StringEquivalent<T> a, string b)
{
return a.Combine(b);
}
public static bool operator ==(StringEquivalent<T> a, StringEquivalent<T> b)
{
// If both are null, or both are same instance, return true.
if (ReferenceEquals(a, b))
{
return true;
}
// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))
{
return false;
}
// Return true if the fields match:
return a.Value.Equals(b.Value, StringComparison.OrdinalIgnoreCase);
}
public static bool operator !=(StringEquivalent<T> a, StringEquivalent<T> b)
{
return !(a == b);
}
public override bool Equals(Object obj)
{
return obj != null && Equals(obj as T) || Equals(obj as string);
}
public bool Equals(T stringEquivalent)
{
return this == stringEquivalent;
}
public override int GetHashCode()
{
return (Value ?? "").GetHashCode();
}
public virtual bool Equals(string other)
{
return other != null && Value == other;
}
public override string ToString()
{
return Value;
}
protected StringEquivalent(SerializationInfo info) : this(info.GetValue("Value", typeof(string)) as string)
{
}
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Value", Value);
}
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
Value = reader.ReadString();
}
public void WriteXml(XmlWriter writer)
{
writer.WriteString(Value);
}
public int Length
{
get { return Value != null ? Value.Length : 0; }
}
}
}

Просмотреть файл

@ -0,0 +1,275 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;
using GitHub.Extensions;
namespace GitHub.Primitives
{
/// <summary>
/// This class represents a URI given to us as a string and is implicitly
/// convertible to and from string.
/// </summary>
/// <remarks>
/// This typically represents a URI from an external source such as user input, a
/// Git Repo Remote, or an API URL. We try to preserve the original form and let
/// downstream clients validate the URL. This class doesn't validate the URL. It just
/// performs a best-effort to parse the URI into bits important to us. For example,
/// we need to know the HOST so we can compare against GitHub.com, GH:E instances, etc.
/// </remarks>
[SuppressMessage("Microsoft.Usage", "CA2240:ImplementISerializableCorrectly", Justification = "GetObjectData is implemented in the base class")]
[Serializable]
public class UriString : StringEquivalent<UriString>, IEquatable<UriString>
{
//static readonly NLog.Logger log = NLog.LogManager.GetCurrentClassLogger();
static readonly Regex sshRegex = new Regex(@"^.+@(?<host>(\[.*?\]|[a-z0-9-.]+?))(:(?<owner>.*?))?(/(?<repo>.*)(\.git)?)?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
readonly Uri url;
public UriString(string uriString) : base(NormalizePath(uriString))
{
if (uriString.Length == 0) return;
if (Uri.TryCreate(uriString, UriKind.Absolute, out url))
{
if (!url.IsFile)
SetUri(url);
else
SetFilePath(url);
}
else if (!ParseScpSyntax(uriString))
{
SetFilePath(uriString);
}
if (RepositoryName != null)
{
NameWithOwner = Owner != null
? string.Format(CultureInfo.InvariantCulture, "{0}/{1}", Owner, RepositoryName)
: RepositoryName;
}
}
static UriString ToUriString(Uri uri)
{
return uri == null ? null : new UriString(uri.ToString());
}
void SetUri(Uri uri)
{
Host = uri.Host;
if (uri.Segments.Any())
{
RepositoryName = GetRepositoryName(uri.Segments.Last());
}
if (uri.Segments.Length > 2)
{
Owner = (uri.Segments[uri.Segments.Length - 2] ?? "").TrimEnd('/').ToNullIfEmpty();
}
IsHypertextTransferProtocol = uri.IsHypertextTransferProtocol();
if (String.IsNullOrEmpty(uri.Query)) return;
try
{
var query = ParseQueryString(uri);
if (query.ContainsKey("branch") && !String.IsNullOrEmpty(query["branch"]))
{
Branch = query["branch"].Replace("%2F", "/");
}
if (query.ContainsKey("pr") && !String.IsNullOrEmpty(query["pr"]))
{
PullRequest = query["pr"].Replace("%2F", "/");
}
if (query.ContainsKey("filepath") && !String.IsNullOrEmpty(query["filepath"]))
{
RelativePathToOpen = query["filepath"].Replace("%2F", "/").Replace('/', '\\');
}
}
catch //(Exception ex)
{
//log.WarnException("Failed to read URI query", ex);
}
}
// This is not a complete query string parsing algorithm, but it's good enough for our needs.
static IDictionary<string, string> ParseQueryString(Uri uri)
{
Debug.Assert(uri.Query.StartsWith('?'),
String.Format(CultureInfo.InvariantCulture, "Uri.Query doesn't start with '?': '{0}'", uri.Query));
return uri.Query.Substring(1).Split(new[] {'&'}, StringSplitOptions.RemoveEmptyEntries)
.Select(pair => pair.Split('='))
.ToDictionary(pair => pair.First(), pair => pair.Length > 1 ? pair[1] : null,
StringComparer.OrdinalIgnoreCase);
}
void SetFilePath(Uri uri)
{
Host = "";
Owner = "";
RepositoryName = GetRepositoryName(uri.Segments.Last());
IsFileUri = true;
}
void SetFilePath(string path)
{
Host = "";
Owner = "";
RepositoryName = GetRepositoryName(path.Replace("/", @"\").RightAfterLast(@"\"));
IsFileUri = true;
}
// For xml serialization
protected UriString()
{
}
bool ParseScpSyntax(string scpString)
{
var match = sshRegex.Match(scpString);
if (match.Success)
{
Host = match.Groups["host"].Value.ToNullIfEmpty();
Owner = match.Groups["owner"].Value.ToNullIfEmpty();
RepositoryName = GetRepositoryName(match.Groups["repo"].Value);
return true;
}
return false;
}
public string Branch { get; private set; }
public string PullRequest { get; set; }
public string Host { get; private set; }
public string Owner { get; private set; }
public string RepositoryName { get; private set; }
public string NameWithOwner { get; private set; }
public string RelativePathToOpen { get; private set; }
public bool IsFileUri { get; private set; }
public bool IsValidUri
{
get { return url != null; }
}
public Uri ToUri()
{
if (url == null)
throw new InvalidOperationException("This Uri String is not a valid Uri");
return url;
}
/// <summary>
/// True if the URL is HTTP or HTTPS
/// </summary>
public bool IsHypertextTransferProtocol { get; private set; }
[SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates")]
public static implicit operator UriString(string value)
{
if (value == null) return null;
return new UriString(value);
}
[SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates")]
public static implicit operator string(UriString uriString)
{
if (uriString == null) return null;
return uriString.Value;
}
[SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings", Justification = "No.")]
public override UriString Combine(string addition)
{
if (url != null)
{
var urlBuilder = new UriBuilder(url);
if (!String.IsNullOrEmpty(urlBuilder.Query))
{
var query = urlBuilder.Query;
if (query.StartsWith("?", StringComparison.Ordinal))
{
query = query.Substring(1);
}
if (!addition.StartsWith("&", StringComparison.Ordinal) && query.Length > 0)
{
addition = "&" + addition;
}
urlBuilder.Query = query + addition;
}
else
{
var path = url.AbsolutePath;
if (path == "/") path = "";
if (!addition.StartsWith("/", StringComparison.Ordinal)) addition = "/" + addition;
urlBuilder.Path = path + addition;
}
return ToUriString(urlBuilder.Uri);
}
return String.Concat(Value, addition);
}
public override string ToString()
{
// Makes this look better in the debugger.
return Value;
}
protected UriString(SerializationInfo info, StreamingContext context)
: this(GetSerializedValue(info))
{
}
static string GetSerializedValue(SerializationInfo info)
{
// First try to get the current way it's serialized, then fall back to the older way it's serialized.
string value;
try
{
value = info.GetValue("Value", typeof(string)) as string;
}
catch (SerializationException)
{
value = info.GetValue("uriString", typeof(string)) as string;
}
return value;
}
static string NormalizePath(string path)
{
return path == null ? null : path.Replace('\\', '/');
}
static string GetRepositoryName(string repositoryNameSegment)
{
if (String.IsNullOrEmpty(repositoryNameSegment)
|| repositoryNameSegment.Equals("/", StringComparison.Ordinal))
{
return null;
}
return repositoryNameSegment.TrimEnd('/').TrimEnd(".git");
}
bool IEquatable<UriString>.Equals(UriString other)
{
return other != null && ToString().Equals(other.ToString());
}
}
}

Просмотреть файл

@ -1,13 +1,13 @@
using System;
using System.ComponentModel.Composition;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using GitHub.Extensions;
using GitHub.Models;
using Octokit;
using Octokit.Internal;
using System.Threading.Tasks;
using System.Net.Http;
using GitHub.Extensions;
using System.Threading;
using System.Net;
namespace GitHub.Services
{

Просмотреть файл

@ -0,0 +1,45 @@
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using GitHub.Exports;
using GitHub.UI;
using GitHub.ViewModels;
namespace GitHub.Services
{
[Export]
[PartCreationPolicy(CreationPolicy.Shared)]
public class ExportFactoryProvider
{
[ImportingConstructor]
public ExportFactoryProvider(ICompositionService cc)
{
cc.SatisfyImportsOnce(this);
}
[Import(AllowRecomposition = true)]
public ExportFactory<IUIController> UIControllerFactory { get; set; }
[ImportMany(AllowRecomposition = true)]
public IEnumerable<ExportFactory<IViewModel, IViewModelMetadata>> ViewModelFactory { get; set; }
[ImportMany(AllowRecomposition = true)]
public IEnumerable<ExportFactory<IView, IViewModelMetadata>> ViewFactory { get; set; }
public ExportLifetimeContext<IViewModel> GetViewModel(UIViewType viewType)
{
var f = ViewModelFactory.FirstOrDefault(x => x.Metadata.ViewType == viewType);
Debug.Assert(f != null, string.Format(CultureInfo.InvariantCulture, "Could not locate view model for {0}.", viewType));
return f.CreateExport();
}
public ExportLifetimeContext<IView> GetView(UIViewType viewType)
{
var f = ViewFactory.FirstOrDefault(x => x.Metadata.ViewType == viewType);
Debug.Assert(f != null, string.Format(CultureInfo.InvariantCulture, "Could not locate view for {0}.", viewType));
return f.CreateExport();
}
}
}

Просмотреть файл

@ -1,5 +1,4 @@
using Octokit;
using System;
using System;
using System.Threading.Tasks;
namespace GitHub.Services

Просмотреть файл

@ -0,0 +1,14 @@
using System;
using System.ComponentModel.Composition.Hosting;
namespace GitHub.Services
{
public interface IUIProvider
{
ExportProvider ExportProvider { get; }
object GetService(Type t);
T GetService<T>();
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
Ret GetService<T, Ret>() where Ret : class;
}
}

Просмотреть файл

@ -1,9 +1,5 @@
using Octokit;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading.Tasks;
using Octokit;
namespace GitHub.Services
{

Просмотреть файл

@ -40,7 +40,7 @@ namespace GitHub.Services
var ret = await httpClient
.Send<object>(request, CancellationToken.None)
.Catch(ex => null);
.Catch();
if (ret == null)
return WikiProbeResult.Failed;

Просмотреть файл

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GitHub.Exports
{
public interface ICloneDialog
{
}
}

Просмотреть файл

@ -0,0 +1,22 @@
using System;
using System.Windows.Controls;
namespace GitHub.UI
{
public interface IUIController
{
//IObservable<object> Transition { get; }
IObservable<UserControl> SelectFlow(UIControllerFlow choice);
void Start();
}
public enum UIControllerFlow
{
None = 0,
Authentication = 1,
Create = 2,
Clone = 3
}
}

Просмотреть файл

@ -0,0 +1,7 @@
namespace GitHub.UI
{
public interface IView
{
object ViewModel { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,12 @@
using System;
using System.Windows.Input;
namespace GitHub.ViewModels
{
public interface ICloneRepoViewModel : IViewModel
{
ICommand OkCmd { get; }
ICommand CancelCmd { get; }
IObservable<object> Cancelling { get; }
}
}

Просмотреть файл

@ -1,15 +1,16 @@
using System;
using System.Windows.Input;
using GitHub.Authentication;
namespace GitHub.Exports
namespace GitHub.ViewModels
{
public interface ILoginDialog
public interface ILoginViewModel : IViewModel
{
string UsernameOrEmail { get; set; }
string Password { get; set; }
ICommand LoginCmd { get; }
ICommand CancelCmd { get; }
IObservable<object> CancelEvt { get; }
IObservable<object> Cancelling { get; }
IObservable<AuthenticationResult> AuthenticationResults { get; }
}
}

Просмотреть файл

@ -0,0 +1,18 @@
using System.Windows.Input;
namespace GitHub.ViewModels
{
public interface ITwoFactorViewModel : IViewModel
{
ICommand OkCmd { get; }
ICommand CancelCmd { get; }
ICommand ShowHelpCmd { get; }
ICommand ResendCodeCmd { get; }
bool IsShowing { get; }
bool IsSms { get; }
bool IsAuthenticationCodeSent { get; }
string Description { get; }
string AuthenticationCode { get; set; }
}
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше