Skip to content

Commit a1a358a

Browse files
committed
wpfui: add a WPF-based UI for generic cred prompt
Add a WPF/Windows UI prompt for the generic/basic username and password prompt.
1 parent b141c83 commit a1a358a

File tree

10 files changed

+278
-0
lines changed

10 files changed

+278
-0
lines changed

Git-Credential-Manager.sln

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitLab.UI.Windows", "src\wi
6969
EndProject
7070
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Git-Credential-Manager.UI.Avalonia", "src\shared\Git-Credential-Manager.UI.Avalonia\Git-Credential-Manager.UI.Avalonia.csproj", "{35659127-8859-4DB9-8DD6-A08C1952632E}"
7171
EndProject
72+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Git-Credential-Manager.UI.Windows", "src\windows\Git-Credential-Manager.UI.Windows\Git-Credential-Manager.UI.Windows.csproj", "{01BF56EC-AAC1-4BCA-8204-EE51D968DF5C}"
73+
EndProject
7274
Global
7375
GlobalSection(SolutionConfigurationPlatforms) = preSolution
7476
Debug|Any CPU = Debug|Any CPU
@@ -487,6 +489,16 @@ Global
487489
{35659127-8859-4DB9-8DD6-A08C1952632E}.MacRelease|Any CPU.Build.0 = Release|Any CPU
488490
{35659127-8859-4DB9-8DD6-A08C1952632E}.WindowsRelease|Any CPU.ActiveCfg = Release|Any CPU
489491
{35659127-8859-4DB9-8DD6-A08C1952632E}.WindowsRelease|Any CPU.Build.0 = Release|Any CPU
492+
{01BF56EC-AAC1-4BCA-8204-EE51D968DF5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
493+
{01BF56EC-AAC1-4BCA-8204-EE51D968DF5C}.MacDebug|Any CPU.ActiveCfg = Debug|Any CPU
494+
{01BF56EC-AAC1-4BCA-8204-EE51D968DF5C}.MacRelease|Any CPU.ActiveCfg = Release|Any CPU
495+
{01BF56EC-AAC1-4BCA-8204-EE51D968DF5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
496+
{01BF56EC-AAC1-4BCA-8204-EE51D968DF5C}.WindowsDebug|Any CPU.ActiveCfg = Debug|Any CPU
497+
{01BF56EC-AAC1-4BCA-8204-EE51D968DF5C}.WindowsDebug|Any CPU.Build.0 = Debug|Any CPU
498+
{01BF56EC-AAC1-4BCA-8204-EE51D968DF5C}.WindowsRelease|Any CPU.ActiveCfg = Debug|Any CPU
499+
{01BF56EC-AAC1-4BCA-8204-EE51D968DF5C}.WindowsRelease|Any CPU.Build.0 = Release|Any CPU
500+
{01BF56EC-AAC1-4BCA-8204-EE51D968DF5C}.LinuxDebug|Any CPU.ActiveCfg = Debug|Any CPU
501+
{01BF56EC-AAC1-4BCA-8204-EE51D968DF5C}.LinuxRelease|Any CPU.ActiveCfg = Release|Any CPU
490502
EndGlobalSection
491503
GlobalSection(SolutionProperties) = preSolution
492504
HideSolutionNode = FALSE
@@ -524,6 +536,7 @@ Global
524536
{47186A50-8889-4FC7-8A05-F9FCE7F8F4AE} = {D5277A0E-997E-453A-8CB9-4EFCC8B16A29}
525537
{83EAC1F9-8E1F-41FC-8FC9-2C452452D64E} = {66722747-1B61-40E4-A89B-1AC8E6D62EA9}
526538
{35659127-8859-4DB9-8DD6-A08C1952632E} = {D5277A0E-997E-453A-8CB9-4EFCC8B16A29}
539+
{01BF56EC-AAC1-4BCA-8204-EE51D968DF5C} = {66722747-1B61-40E4-A89B-1AC8E6D62EA9}
527540
EndGlobalSection
528541
GlobalSection(ExtensibilityGlobals) = postSolution
529542
SolutionGuid = {0EF9FC65-E6BA-45D4-A455-262A9EA4366B}

src/windows/Core.UI.Windows/Assets/Styles.xaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,4 +193,15 @@
193193
</Trigger>
194194
</Style.Triggers>
195195
</Style>
196+
197+
<DrawingImage x:Key="GcmLogo">
198+
<DrawingImage.Drawing>
199+
<DrawingGroup>
200+
<DrawingGroup.Children>
201+
<GeometryDrawing Brush="#FFF05033" Geometry="m 127.74219 0 c -4.21881 0 -8.43843 1.6093415 -11.65821 4.828125 L 92.875 28.041016 122.31445 57.482422 c 6.84425 -2.310946 14.68947 -0.761046 20.14258 4.693359 5.48141 5.488392 7.0192 13.400136 4.65039 20.267578 l 28.37696 28.376951 c 6.86492 -2.36579 14.78398 -0.83727 20.26562 4.6543 7.66374 7.66179 7.66374 20.07642 0 27.74023 -7.66486 7.66631 -20.07893 7.66631 -27.74805 0 -5.76254 -5.76724 -7.18821 -14.23373 -4.26953 -21.33398 l -26.46289 -26.464844 -0.002 69.640624 c 1.8684 0.92496 3.63248 2.16064 5.18945 3.71094 7.66148 7.6609 7.66148 20.07236 0 27.74609 -7.66374 7.66066 -20.08459 7.66066 -27.74023 0 -7.66262 -7.67305 -7.66262 -20.08452 0 -27.74609 1.89369 -1.89039 4.08382 -3.32218 6.42187 -4.28125 V 94.199219 c -2.33912 -0.955028 -4.52734 -2.375687 -6.42383 -4.28125 -5.80409 -5.799832 -7.20125 -14.319608 -4.22461 -21.447266 L 81.466797 39.443359 4.8300781 116.08203 c -6.4393305 6.44252 -6.4393305 16.88229 0 23.32031 L 42.5 177.07227 V 162.70508 C 35.078345 157.16403 29.678851 149.02425 27.328125 140.07617 19.76286 115.647 40.902921 87.908596 66.359375 88.345703 76.747705 88.003924 87.132367 91.94485 94.875 98.837891 c 18.78493 15.372969 17.87151 47.496839 -0.888672 62.484379 l -2.566406 1.3457 0.222656 12.46503 -8.160156 8.24395 v 34.67578 l 33.119138 33.11915 c 6.43505 6.43757 16.87041 6.43757 23.31446 0 L 251.17188 139.92969 c 6.43732 -6.4407 6.43732 -16.88336 0 -23.32227 l 0.002 -0.01 L 139.39453 4.828125 C 136.1788 1.6093415 131.96099 0 127.74219 0 Z" />
202+
<GeometryDrawing Brush="#FF4D4D4D" Geometry="M 67.333984 94.333984 A 35.333332 35.333332 0 0 0 32 129.66602 A 35.333332 35.333332 0 0 0 48.5 159.54688 L 48.5 234.5 L 54.5 240 L 67 240 L 79 228 L 79 216.5 L 73 210 L 79 203.5 L 73 197 L 79 191 L 73 185.5 L 85.5 173 L 85.5 159.92188 A 35.333332 35.333332 0 0 0 102.66602 129.66602 A 35.333332 35.333332 0 0 0 67.333984 94.333984 z M 66.777344 109 A 9 9 0 0 1 75.777344 118 A 9 9 0 0 1 66.777344 127 A 9 9 0 0 1 57.777344 118 A 9 9 0 0 1 66.777344 109 z M 54.5 168 L 60.5 173 L 60.5 234.5 L 54.5 228 L 54.5 168 z " />
203+
</DrawingGroup.Children>
204+
</DrawingGroup>
205+
</DrawingImage.Drawing>
206+
</DrawingImage>
196207
</ResourceDictionary>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
3+
<ResourceDictionary.MergedDictionaries>
4+
<ResourceDictionary Source="pack://application:,,,/gcmcoreuiwpf;component/Assets/Styles.xaml"/>
5+
</ResourceDictionary.MergedDictionaries>
6+
</ResourceDictionary>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System.Threading;
2+
using System.Threading.Tasks;
3+
using GitCredentialManager.UI.ViewModels;
4+
using GitCredentialManager.UI.Views;
5+
6+
namespace GitCredentialManager.UI.Commands
7+
{
8+
public class CredentialsCommandImpl : CredentialsCommand
9+
{
10+
public CredentialsCommandImpl(ICommandContext context) : base(context) { }
11+
12+
protected override Task ShowAsync(CredentialsViewModel viewModel, CancellationToken ct)
13+
{
14+
return Gui.ShowDialogWindow(viewModel, () => new CredentialsView(), GetParentHandle());
15+
}
16+
}
17+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<Window x:Class="GitCredentialManager.UI.Controls.TesterWindow"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6+
mc:Ignorable="d"
7+
ResizeMode="NoResize" Width="550" SizeToContent="Height"
8+
Title="GitCredentialManager Authentication Dialog Tester">
9+
<TabControl Margin="5,10">
10+
<TabItem Header="Credentials">
11+
<StackPanel>
12+
<Grid>
13+
<Grid.RowDefinitions>
14+
<RowDefinition Height="Auto"/>
15+
<RowDefinition Height="Auto"/>
16+
<RowDefinition Height="Auto"/>
17+
<RowDefinition Height="Auto"/>
18+
</Grid.RowDefinitions>
19+
<Grid.ColumnDefinitions>
20+
<ColumnDefinition Width="Auto"/>
21+
<ColumnDefinition Width="*"/>
22+
</Grid.ColumnDefinitions>
23+
<Label Grid.Row="0" Grid.Column="0"
24+
Content="Window Title" />
25+
<TextBox Grid.Row="0" Grid.Column="1"
26+
x:Name="title" Text="Git Credential Manager" />
27+
<Label Grid.Row="1" Grid.Column="0"
28+
Content="Description" />
29+
<TextBox Grid.Row="1" Grid.Column="1"
30+
x:Name="description" Text="Enter credentials for 'https://example.com'" />
31+
<Label Grid.Row="2" Grid.Column="0"
32+
Content="Username" />
33+
<TextBox Grid.Row="2" Grid.Column="1"
34+
x:Name="username" />
35+
<Label Grid.Row="3" Grid.Column="0"
36+
Content="Show Logo" />
37+
<CheckBox Grid.Row="3" Grid.Column="1"
38+
x:Name="showLogo" IsChecked="True" />
39+
</Grid>
40+
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right"
41+
Margin="0,10">
42+
<Button Content="Show" Click="ShowBasic"
43+
Padding="8,4"/>
44+
</StackPanel>
45+
</StackPanel>
46+
</TabItem>
47+
</TabControl>
48+
</Window>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System.Windows;
2+
using GitCredentialManager.UI.ViewModels;
3+
using GitCredentialManager.UI.Views;
4+
using GitCredentialManager.Interop.Windows;
5+
using GitCredentialManager.UI.Controls;
6+
7+
namespace GitCredentialManager.UI.Controls
8+
{
9+
public partial class TesterWindow : Window
10+
{
11+
public TesterWindow()
12+
{
13+
InitializeComponent();
14+
}
15+
16+
private void ShowBasic(object sender, RoutedEventArgs e)
17+
{
18+
var vm = new CredentialsViewModel
19+
{
20+
Title = title.Text,
21+
Description = description.Text,
22+
UserName = username.Text,
23+
ShowProductHeader = showLogo.IsChecked ?? false
24+
};
25+
var view = new CredentialsView();
26+
var window = new DialogWindow(view) {DataContext = vm};
27+
window.ShowDialog();
28+
}
29+
}
30+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net472</TargetFramework>
6+
<UseWPF>true</UseWPF>
7+
<RootNamespace>GitCredentialManager.UI</RootNamespace>
8+
<AssemblyName>git-credential-manager-ui</AssemblyName>
9+
<ApplicationIcon>$(RepoAssetsPath)gcmicon.ico</ApplicationIcon>
10+
<StartupObject>GitCredentialManager.UI.Program</StartupObject>
11+
</PropertyGroup>
12+
13+
<ItemGroup>
14+
<ProjectReference Include="..\..\shared\Core.UI\Core.UI.csproj" />
15+
<ProjectReference Include="..\Core.UI.Windows\Core.UI.Windows.csproj" />
16+
</ItemGroup>
17+
18+
<ItemGroup Condition="'$(OSPlatform)' != 'windows'">
19+
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" />
20+
</ItemGroup>
21+
22+
</Project>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using GitCredentialManager.UI.Commands;
4+
using GitCredentialManager.UI.Controls;
5+
using GitCredentialManager;
6+
using GitCredentialManager.UI;
7+
8+
namespace GitCredentialManager.UI
9+
{
10+
public static class Program
11+
{
12+
public static async Task Main(string[] args)
13+
{
14+
string appPath = ApplicationBase.GetEntryApplicationPath();
15+
using (var context = new CommandContext(appPath))
16+
using (var app = new HelperApplication(context))
17+
{
18+
if (args.Length == 0)
19+
{
20+
await Gui.ShowWindow(() => new TesterWindow(), IntPtr.Zero);
21+
return;
22+
}
23+
24+
app.RegisterCommand(new CredentialsCommandImpl(context));
25+
26+
int exitCode = app.RunAsync(args)
27+
.ConfigureAwait(false)
28+
.GetAwaiter()
29+
.GetResult();
30+
31+
Environment.Exit(exitCode);
32+
}
33+
}
34+
}
35+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<UserControl x:Class="GitCredentialManager.UI.Views.CredentialsView"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6+
xmlns:converters="clr-namespace:GitCredentialManager.UI.Converters;assembly=gcmcoreuiwpf"
7+
xmlns:sharedControls="clr-namespace:GitCredentialManager.UI.Controls;assembly=gcmcoreuiwpf"
8+
xmlns:viewModels="clr-namespace:GitCredentialManager.UI.ViewModels;assembly=gcmcoreui"
9+
mc:Ignorable="d"
10+
d:DataContext="{d:DesignInstance viewModels:CredentialsViewModel}"
11+
d:DesignWidth="300"
12+
x:Name="view">
13+
<UserControl.Resources>
14+
<ResourceDictionary>
15+
<ResourceDictionary.MergedDictionaries>
16+
<ResourceDictionary Source="../Assets/Styles.xaml"/>
17+
</ResourceDictionary.MergedDictionaries>
18+
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
19+
</ResourceDictionary>
20+
</UserControl.Resources>
21+
22+
<DockPanel>
23+
<StackPanel DockPanel.Dock="Top" Margin="10,0,0,10">
24+
<StackPanel Margin="0"
25+
Orientation="Horizontal"
26+
HorizontalAlignment="Center"
27+
Visibility="{Binding ShowProductHeader, Converter={StaticResource BooleanToVisibilityConverter}}">
28+
<Image Source="{StaticResource GcmLogo}"
29+
Height="32" VerticalAlignment="Center"
30+
Margin="0,0,10,0"/>
31+
<TextBlock Text="Git Credential Manager"
32+
VerticalAlignment="Center"
33+
FontSize="18"
34+
FontWeight="Light" />
35+
</StackPanel>
36+
37+
<TextBlock Text="{Binding Description}"
38+
HorizontalAlignment="Center"
39+
FontSize="14"
40+
Margin="0,15,0,15"/>
41+
</StackPanel>
42+
43+
<StackPanel Margin="20,0">
44+
<sharedControls:PromptTextBox x:Name="userNameTextBox"
45+
Margin="0,0,0,10"
46+
PromptText="Username"
47+
Text="{Binding UserName}"/>
48+
<sharedControls:PasswordPromptTextBox x:Name="passwordTextBox"
49+
Margin="0,0,0,20"
50+
PromptText="Password"
51+
Password="{Binding Password, UpdateSourceTrigger=PropertyChanged, Delay=50, Mode=OneWayToSource}"/>
52+
<Button Content="Continue"
53+
IsDefault="True"
54+
Command="{Binding SignInCommand}"
55+
HorizontalAlignment="Center"
56+
Style="{StaticResource AccentButton}"/>
57+
</StackPanel>
58+
</DockPanel>
59+
</UserControl>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System.Windows.Controls;
2+
using System.Windows.Input;
3+
using GitCredentialManager.UI.Controls;
4+
using GitCredentialManager.UI.ViewModels;
5+
6+
namespace GitCredentialManager.UI.Views
7+
{
8+
public partial class CredentialsView : UserControl, IFocusable
9+
{
10+
public CredentialsView()
11+
{
12+
InitializeComponent();
13+
}
14+
15+
public void SetFocus()
16+
{
17+
if (!(DataContext is CredentialsViewModel vm))
18+
{
19+
return;
20+
}
21+
22+
//
23+
// Select the best available authentication mechanism that is visible
24+
// and make the textbox/button focused when it next made visible.
25+
//
26+
Control element = string.IsNullOrWhiteSpace(vm.UserName)
27+
? userNameTextBox
28+
: passwordTextBox;
29+
30+
// Set logical focus
31+
element.Focus();
32+
33+
// Set keyboard focus
34+
Keyboard.Focus(element);
35+
}
36+
}
37+
}

0 commit comments

Comments
 (0)