Skip to content

Commit 14c9cd0

Browse files
committed
github: reimplement credential and 2FA WPF views
Reimplement WPF views for the credential and 2FA GitHub prompts. The layout is now much simpler, and matches the Avalonia-based UI.
1 parent fceae88 commit 14c9cd0

File tree

4 files changed

+274
-6
lines changed

4 files changed

+274
-6
lines changed

src/windows/GitHub.UI.Windows/Views/CredentialsView.xaml

Lines changed: 145 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,149 @@
33
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
44
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
55
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6-
mc:Ignorable="d">
6+
xmlns:viewModels="clr-namespace:GitHub.UI.ViewModels;assembly=GitHub.UI.Shared"
7+
xmlns:converters="clr-namespace:Microsoft.Git.CredentialManager.UI.Converters;assembly=Microsoft.Git.CredentialManager.UI.Windows"
8+
xmlns:controls="clr-namespace:GitHub.UI.Controls"
9+
xmlns:sharedControls="clr-namespace:Microsoft.Git.CredentialManager.UI.Controls;assembly=Microsoft.Git.CredentialManager.UI.Windows"
10+
mc:Ignorable="d"
11+
d:DataContext="{d:DesignInstance viewModels:CredentialsViewModel}"
12+
d:DesignWidth="300">
13+
<UserControl.Resources>
14+
<ResourceDictionary>
15+
<ResourceDictionary.MergedDictionaries>
16+
<ResourceDictionary Source="../Assets/Styles.xaml"/>
17+
</ResourceDictionary.MergedDictionaries>
18+
<converters:NonEmptyStringToVisibleConverter x:Key="NonEmptyStringToVisibleConverter"/>
19+
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
20+
<converters:BooleanOrToVisibilityConverter x:Key="BooleanOrToVisibilityConverter"/>
21+
<converters:BooleanOrConverter x:Key="BooleanOrConverter"/>
22+
<converters:BooleanNotConverter x:Key="BooleanNotConverter"/>
23+
</ResourceDictionary>
24+
</UserControl.Resources>
25+
26+
<DockPanel>
27+
<StackPanel DockPanel.Dock="Top" Margin="0,0,0,15">
28+
<!-- TODO: replace with GitHub logo -->
29+
<TextBlock Text="GitHub"
30+
HorizontalAlignment="Center"
31+
FontSize="20"
32+
FontWeight="Bold"/>
33+
<TextBlock Text="Sign in"
34+
HorizontalAlignment="Center"
35+
FontSize="24"
36+
FontWeight="Light"
37+
Margin="0,0,0,10" />
38+
<controls:HorizontalShadowDivider/>
39+
<StackPanel Visibility="{Binding EnterpriseUrl, Converter={StaticResource NonEmptyStringToVisibleConverter}}"
40+
Margin="0,10,0,0">
41+
<TextBlock Text="GitHub Enterprise" HorizontalAlignment="Center"
42+
FontSize="14"/>
43+
<TextBlock Text="{Binding EnterpriseUrl}"
44+
HorizontalAlignment="Center"
45+
FontSize="14"/>
46+
</StackPanel>
47+
</StackPanel>
48+
49+
<WrapPanel DockPanel.Dock="Bottom" HorizontalAlignment="Center" VerticalAlignment="Center"
50+
Margin="0,20,0,0">
51+
<TextBlock Text="Don't have an account? "
52+
Margin="0,0,5,0"
53+
FontSize="14">
54+
<Hyperlink Command="{Binding SignUpCommand}">Sign Up</Hyperlink>
55+
</TextBlock>
56+
</WrapPanel>
57+
58+
<TabControl x:Name="tabControl"
59+
BorderThickness="0"
60+
Background="Transparent"
61+
IsTabStop="False">
62+
<TabControl.Resources>
63+
<Style TargetType="TabPanel">
64+
<Setter Property="HorizontalAlignment" Value="Center"/>
65+
</Style>
66+
<Style TargetType="TabItem">
67+
<Setter Property="Template">
68+
<Setter.Value>
69+
<ControlTemplate TargetType="TabItem">
70+
<Border Name="Border" Margin="10,0,10,10"
71+
BorderThickness="0,0,0,2"
72+
BorderBrush="Transparent">
73+
<ContentPresenter x:Name="ContentSite"
74+
VerticalAlignment="Center"
75+
HorizontalAlignment="Center"
76+
ContentSource="Header"
77+
Margin="0,0,0,5"/>
78+
</Border>
79+
<ControlTemplate.Triggers>
80+
<Trigger Property="IsSelected" Value="True">
81+
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource AccentBrush}"/>
82+
</Trigger>
83+
</ControlTemplate.Triggers>
84+
</ControlTemplate>
85+
</Setter.Value>
86+
</Setter>
87+
</Style>
88+
</TabControl.Resources>
89+
90+
<TabItem IsEnabled="{Binding ShowBrowserLogin}"
91+
Visibility="{Binding ShowBrowserLogin, Converter={StaticResource BooleanToVisibilityConverter}}">
92+
<TabItem.Header>
93+
<TextBlock Text="Browser" FontSize="12" />
94+
</TabItem.Header>
95+
<StackPanel x:Name="oauthPanel"
96+
Margin="0,10">
97+
<Button x:Name="browserButton"
98+
Content="Sign in with your browser"
99+
IsDefault="True"
100+
Command="{Binding SignInBrowserCommand}"
101+
Visibility="{Binding ShowBrowserLogin}"
102+
HorizontalAlignment="Center"
103+
Margin="0,0,0,10"
104+
Style="{StaticResource AccentButton}"/>
105+
</StackPanel>
106+
</TabItem>
107+
108+
<TabItem IsEnabled="{Binding ShowTokenLogin}"
109+
Visibility="{Binding ShowTokenLogin, Converter={StaticResource BooleanToVisibilityConverter}}">
110+
<TabItem.Header>
111+
<TextBlock Text="Token" FontSize="12" />
112+
</TabItem.Header>
113+
<StackPanel x:Name="tokenPanel"
114+
Margin="0,10">
115+
<sharedControls:PasswordPromptTextBox x:Name="tokenTextBox"
116+
Margin="0,0,0,10"
117+
PromptText="Personal access token"
118+
Password="{Binding Token, UpdateSourceTrigger=PropertyChanged, Delay=300, Mode=OneWayToSource}"/>
119+
<Button Content="Sign in"
120+
IsDefault="True"
121+
Command="{Binding SignInTokenCommand}"
122+
HorizontalAlignment="Center"
123+
Style="{StaticResource AccentButton}"/>
124+
</StackPanel>
125+
</TabItem>
126+
127+
<TabItem IsEnabled="{Binding ShowBasicLogin}"
128+
Visibility="{Binding ShowBasicLogin, Converter={StaticResource BooleanToVisibilityConverter}}">
129+
<TabItem.Header>
130+
<TextBlock Text="Password" FontSize="12" />
131+
</TabItem.Header>
132+
<StackPanel x:Name="basicPanel"
133+
Margin="0,10">
134+
<sharedControls:PromptTextBox x:Name="userNameTextBox"
135+
Margin="0,0,0,10"
136+
PromptText="Username or email"
137+
Text="{Binding UserName}"/>
138+
<sharedControls:PasswordPromptTextBox x:Name="passwordTextBox"
139+
Margin="0,0,0,10"
140+
PromptText="Password"
141+
Password="{Binding Password, UpdateSourceTrigger=PropertyChanged, Delay=300, Mode=OneWayToSource}"/>
142+
<Button Content="Sign in"
143+
IsDefault="True"
144+
Command="{Binding SignInBasicCommand}"
145+
HorizontalAlignment="Center"
146+
Style="{StaticResource AccentButton}"/>
147+
</StackPanel>
148+
</TabItem>
149+
</TabControl>
150+
</DockPanel>
7151
</UserControl>
Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,78 @@
1-
using System;
1+
using System.Windows;
22
using System.Windows.Controls;
33
using System.Windows.Input;
4-
using System.Windows.Threading;
54
using GitHub.UI.ViewModels;
5+
using Microsoft.Git.CredentialManager.UI.Controls;
66

77
namespace GitHub.UI.Views
88
{
9-
public partial class CredentialsView : UserControl
9+
public partial class CredentialsView : UserControl, IFocusable
1010
{
1111
public CredentialsView()
1212
{
1313
InitializeComponent();
1414
}
15+
16+
// Set focus on a UIElement the next time it becomes visible
17+
private static void OnIsVisibleChangedOneTime(object sender, DependencyPropertyChangedEventArgs e)
18+
{
19+
if (sender is UIElement element)
20+
{
21+
// Unsubscribe to prevent re-triggering
22+
element.IsVisibleChanged -= OnIsVisibleChangedOneTime;
23+
24+
// Set logical focus
25+
element.Focus();
26+
27+
// Set keyboard focus
28+
Keyboard.Focus(element);
29+
}
30+
}
31+
32+
public void SetFocus()
33+
{
34+
if (!(DataContext is CredentialsViewModel vm))
35+
{
36+
return;
37+
}
38+
39+
//
40+
// Select the best available authentication mechanism that is visible
41+
// and make the textbox/button focused when it next made visible.
42+
//
43+
// In WPF the controls in a TabItem are not part of the visual tree until
44+
// the TabControl has been switched to that tab, so we must delay focusing
45+
// on the textbox/button until it becomes visible.
46+
//
47+
// This means as the user first moves through the tabs, the "correct" control
48+
// will be given focus in that tab.
49+
//
50+
void SetFocusOnNextVisible(UIElement element)
51+
{
52+
element.IsVisibleChanged += OnIsVisibleChangedOneTime;
53+
}
54+
55+
// Set up focus events on all controls
56+
SetFocusOnNextVisible(
57+
string.IsNullOrWhiteSpace(vm.UserName)
58+
? userNameTextBox
59+
: passwordTextBox);
60+
SetFocusOnNextVisible(tokenTextBox);
61+
SetFocusOnNextVisible(browserButton);
62+
63+
// Switch to the preferred tab
64+
if (vm.ShowBrowserLogin)
65+
{
66+
tabControl.SelectedIndex = 0;
67+
}
68+
else if (vm.ShowTokenLogin)
69+
{
70+
tabControl.SelectedIndex = 1;
71+
}
72+
else if (vm.ShowBasicLogin)
73+
{
74+
tabControl.SelectedIndex = 2;
75+
}
76+
}
77+
}
1578
}

src/windows/GitHub.UI.Windows/Views/TwoFactorView.xaml

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,52 @@
33
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
44
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
55
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6-
mc:Ignorable="d">
6+
xmlns:viewModels="clr-namespace:GitHub.UI.ViewModels;assembly=GitHub.UI.Shared"
7+
xmlns:controls="clr-namespace:GitHub.UI.Controls"
8+
mc:Ignorable="d"
9+
d:DataContext="{d:DesignInstance viewModels:TwoFactorViewModel}"
10+
d:DesignHeight="300" d:DesignWidth="300">
11+
<UserControl.Resources>
12+
<ResourceDictionary>
13+
<ResourceDictionary.MergedDictionaries>
14+
<ResourceDictionary Source="../Assets/Styles.xaml"/>
15+
</ResourceDictionary.MergedDictionaries>
16+
</ResourceDictionary>
17+
</UserControl.Resources>
18+
19+
<DockPanel>
20+
<StackPanel DockPanel.Dock="Top" Margin="0,0,0,15">
21+
<!-- TODO: replace with GitHub logo -->
22+
<TextBlock Text="GitHub"
23+
HorizontalAlignment="Center"
24+
FontSize="20"
25+
FontWeight="Bold"/>
26+
<TextBlock Text="Two-factor authentication"
27+
HorizontalAlignment="Center"
28+
FontSize="24"
29+
FontWeight="Light"
30+
Margin="0,0,0,10" />
31+
<controls:HorizontalShadowDivider/>
32+
</StackPanel>
33+
34+
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
35+
<TextBlock Text="{Binding Description}" Margin="0,0,0,20"
36+
TextWrapping="Wrap" TextAlignment="Center" FontSize="14"/>
37+
<controls:SixDigitInput x:Name="codeInput"
38+
TabIndex="1"
39+
Text="{Binding Code, Mode=OneWayToSource}"
40+
Margin="0,0,0,20"
41+
HorizontalAlignment="Center"/>
42+
<Button Content="Verify"
43+
IsDefault="True"
44+
Command="{Binding VerifyCommand}"
45+
HorizontalAlignment="Center"
46+
Style="{StaticResource AccentButton}"/>
47+
<TextBlock Margin="0,20,0,0"
48+
FontSize="14"
49+
HorizontalAlignment="Center">
50+
<Hyperlink Command="{Binding LearnMoreCommand}">Learn more</Hyperlink>
51+
</TextBlock>
52+
</StackPanel>
53+
</DockPanel>
754
</UserControl>
Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,28 @@
11
using System;
22
using System.Windows.Controls;
33
using System.Windows.Threading;
4+
using Microsoft.Git.CredentialManager.UI.Controls;
45

56
namespace GitHub.UI.Views
67
{
7-
public partial class TwoFactorView : UserControl
8+
public partial class TwoFactorView : UserControl, IFocusable
89
{
910
public TwoFactorView()
1011
{
1112
InitializeComponent();
13+
14+
IsVisibleChanged += (s, e) =>
15+
{
16+
if (IsVisible)
17+
{
18+
Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (Action)SetFocus);
19+
}
20+
};
21+
}
22+
23+
public void SetFocus()
24+
{
25+
codeInput.SetFocus();
1226
}
1327
}
1428
}

0 commit comments

Comments
 (0)