Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Implementing Autocompletebox #2159

Merged
merged 32 commits into from
Apr 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
9e4d7f9
Starting to implement autocomplete functionality
StanleyGoldman Jan 4, 2019
ac4aab9
Merge branch 'autocompletebox-fix' into autocompletebox-implementation
StanleyGoldman Jan 4, 2019
8906c54
Revert "Undoing changes to PullRequestCreationViewModel"
StanleyGoldman Jan 4, 2019
bfa18c6
Undoing some changes
StanleyGoldman Jan 4, 2019
2c94748
Trying to display the control correctly
StanleyGoldman Jan 5, 2019
3dba1d9
Merge branch 'autocompletebox-fix' into autocompletebox-implementation
StanleyGoldman Jan 24, 2019
3ff1300
Merge branch 'autocompletebox-fix' into autocompletebox-implementation
StanleyGoldman Jan 24, 2019
9d2ee84
Including missing themes
StanleyGoldman Jan 24, 2019
161b85e
Commenting out event subscriptions
StanleyGoldman Jan 24, 2019
0649605
Merge branch 'autocompletebox-fix' into autocompletebox-implementation
StanleyGoldman Feb 26, 2019
b355b6c
Merge branch 'autocompletebox-fix' into autocompletebox-implementation
StanleyGoldman Feb 26, 2019
0dbabcd
Removing extra control
StanleyGoldman Feb 26, 2019
4a2657e
Merge branch 'autocompletebox-fix' into autocompletebox-implementation
StanleyGoldman Mar 11, 2019
dd5ee9c
Merge branch 'autocompletebox-fix' into autocompletebox-implementation
StanleyGoldman Mar 11, 2019
c1855d9
Merge branch 'autocompletebox-fix' into autocompletebox-implementation
StanleyGoldman Mar 15, 2019
bf381a8
Merge branch 'autocompletebox-fix' into autocompletebox-implementation
StanleyGoldman Mar 15, 2019
df979af
Merge branch 'autocompletebox-fix' into autocompletebox-implementation
StanleyGoldman Mar 15, 2019
ea8f2db
Merge branch 'autocompletebox-fix' into autocompletebox-implementation
StanleyGoldman Mar 15, 2019
df16579
Merge branch 'fixes/dialog-style-guide' into autocompletebox-implemen…
jcansdale Mar 25, 2019
3a84e78
Use VS theme colors for AutoCompleteBox
jcansdale Mar 26, 2019
dff9d67
Merge branch 'autocompletebox-fix' into autocompletebox-implementation
StanleyGoldman Mar 27, 2019
b228f02
Merge branch 'autocompletebox-fix' into autocompletebox-implementation
StanleyGoldman Mar 27, 2019
ff19239
Merge remote-tracking branch 'origin/autocompletebox-implementation' …
jcansdale Mar 27, 2019
c40b757
Merge branch 'autocompletebox-fix' into autocompletebox-implementation
StanleyGoldman Mar 28, 2019
d0a7965
Merge branch 'autocompletebox-implementation' into jcansdale/autocomp…
StanleyGoldman Mar 28, 2019
3d539c8
Merge branch 'autocompletebox-fix' into autocompletebox-implementation
StanleyGoldman Apr 5, 2019
28fc2f1
Merge branch 'autocompletebox-implementation' into jcansdale/autocomp…
StanleyGoldman Apr 5, 2019
84c4dd1
Merge pull request #2292 from github/jcansdale/autocompletebox-theme
StanleyGoldman Apr 5, 2019
0bd1903
Merge branch 'autocompletebox-fix' into autocompletebox-implementation
StanleyGoldman Apr 8, 2019
2027b5c
Undoing change
StanleyGoldman Apr 8, 2019
40a452a
Merge branch 'autocompletebox-fix' into autocompletebox-implementation
StanleyGoldman Apr 8, 2019
aa65fcc
Merge branch 'autocompletebox-fix' into autocompletebox-implementation
StanleyGoldman Apr 8, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using GitHub.Models.Drafts;
using GitHub.Primitives;
using GitHub.Services;
using GitHub.UI;
using GitHub.Validation;
using Octokit;
using ReactiveUI;
Expand Down Expand Up @@ -51,8 +52,9 @@ public PullRequestCreationViewModel(
IPullRequestService service,
INotificationService notifications,
IMessageDraftStore draftStore,
IGitService gitService)
: this(modelServiceFactory, service, notifications, draftStore, gitService, DefaultScheduler.Instance)
IGitService gitService,
IAutoCompleteAdvisor autoCompleteAdvisor)
: this(modelServiceFactory, service, notifications, draftStore, gitService, autoCompleteAdvisor, DefaultScheduler.Instance)
{
}

Expand All @@ -62,19 +64,22 @@ public PullRequestCreationViewModel(
INotificationService notifications,
IMessageDraftStore draftStore,
IGitService gitService,
IAutoCompleteAdvisor autoCompleteAdvisor,
IScheduler timerScheduler)
{
Guard.ArgumentNotNull(modelServiceFactory, nameof(modelServiceFactory));
Guard.ArgumentNotNull(service, nameof(service));
Guard.ArgumentNotNull(notifications, nameof(notifications));
Guard.ArgumentNotNull(draftStore, nameof(draftStore));
Guard.ArgumentNotNull(gitService, nameof(gitService));
Guard.ArgumentNotNull(autoCompleteAdvisor, nameof(autoCompleteAdvisor));
Guard.ArgumentNotNull(timerScheduler, nameof(timerScheduler));

this.service = service;
this.modelServiceFactory = modelServiceFactory;
this.draftStore = draftStore;
this.gitService = gitService;
this.AutoCompleteAdvisor = autoCompleteAdvisor;
this.timerScheduler = timerScheduler;

this.WhenAnyValue(x => x.Branches)
Expand Down Expand Up @@ -336,6 +341,7 @@ protected string GetDraftKey()

public RemoteRepositoryModel GitHubRepository { get { return githubRepository?.Value; } }
bool IsExecuting { get { return isExecuting.Value; } }
public IAutoCompleteAdvisor AutoCompleteAdvisor { get; }

bool initialized;
bool Initialized
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public interface IPullRequestCreationViewModel : IPanePageViewModel
ReactiveCommand<Unit, Unit> Cancel { get; }
string PRTitle { get; set; }
ReactivePropertyValidator TitleValidator { get; }
IAutoCompleteAdvisor AutoCompleteAdvisor { get; }

Task InitializeAsync(LocalRepositoryModel repository, IConnection connection);
}
Expand Down
91 changes: 41 additions & 50 deletions src/GitHub.UI/Assets/Controls/AutoCompleteBox.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:vs="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.14.0"
xmlns:ui="clr-namespace:GitHub.UI">

<!-- CommonValidationToolTipTemplate -->
Expand Down Expand Up @@ -59,62 +60,51 @@
</Grid>
</ControlTemplate>


<ControlTemplate x:Key="ListViewItemControlTemplate" TargetType="{x:Type ListBoxItem}">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True"
Padding="{TemplateBinding Padding}">
<ContentPresenter Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}" />
</Border>
</ControlTemplate>

<Style x:Key="AutoCompleteListItemContainerStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="Padding" Value="5,0,10,0"/>
<Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="Background" Value="{DynamicResource GHBoxBackgroundBrush}"/>
<Setter Property="Foreground" Value="{DynamicResource GHBoxTextBrush}"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="FocusVisualStyle" Value="{DynamicResource NoMarginFocusVisual}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="Bd" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="BorderBrush" TargetName="Bd" Value="{DynamicResource GHBoxHoverBackgroundBrush}"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Selector.IsSelectionActive" Value="False"/>
<Condition Property="IsSelected" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Background" Value="{DynamicResource GHBoxSelectedBackgroundBrush}"/>
<Setter Property="Foreground" Value="{DynamicResource GHBoxSelectedTextBrush}"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Selector.IsSelectionActive" Value="True"/>
<Condition Property="IsSelected" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Background" Value="{DynamicResource GHBoxActiveSelectionBackgroundBrush}"/>
<Setter Property="Foreground" Value="{DynamicResource GHBoxActiveSelectionTextBrush}"/>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" TargetName="Bd" Value="0.3"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Padding" Value="5,3,3,3" />
<Setter Property="Template" Value="{StaticResource ListViewItemControlTemplate}" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource {x:Static vs:ThemedDialogColors.ListItemMouseOverBrushKey}}" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static vs:ThemedDialogColors.ListItemMouseOverTextBrushKey}}" />
</Trigger>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" Value="{DynamicResource {x:Static vs:ThemedDialogColors.SelectedItemInactiveBrushKey}}" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static vs:ThemedDialogColors.SelectedItemInactiveTextBrushKey}}" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="True" />
<Condition Property="Selector.IsSelectionActive" Value="True" />
</MultiTrigger.Conditions>
<Setter Property="Background" Value="{DynamicResource {x:Static vs:ThemedDialogColors.SelectedItemActiveBrushKey}}" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static vs:ThemedDialogColors.SelectedItemActiveTextBrushKey}}" />
</MultiTrigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource {x:Static vs:ThemedDialogColors.ListItemDisabledTextBrushKey}}" />
</Trigger>
</Style.Triggers>
</Style>


<!-- input:AutoCompleteBox -->
<Style TargetType="ui:AutoCompleteBox">
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Padding" Value="2" />
<Setter Property="Background" Value="{DynamicResource DefaultBackgroundBrush}" />
<Setter Property="Foreground" Value="{DynamicResource GHTextBrush}" />
<Setter Property="Background" Value="{DynamicResource {x:Static vs:ThemedDialogColors.WindowPanelBrushKey}}" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static vs:ThemedDialogColors.WindowPanelTextBrushKey}}" />
<Setter Property="MinWidth" Value="45" />
<Setter Property="ItemContainerStyle" Value="{StaticResource AutoCompleteListItemContainerStyle}" />

Expand All @@ -125,6 +115,7 @@
<ContentPresenter
x:Name="Text"
Content="{Binding InputElement.Control, RelativeSource={RelativeSource TemplatedParent}}"/>
<!-- TODO: What should we use for validation BorderBrush? -->
<Border
x:Name="ValidationErrorElement"
Visibility="Collapsed"
Expand Down Expand Up @@ -174,7 +165,7 @@
x:Name="PopupBorder"
HorizontalAlignment="Stretch"
Opacity="0"
BorderBrush="#B0B0B0"
BorderBrush="{DynamicResource {x:Static vs:CommonControlsColors.TextBoxBorderFocusedBrushKey}}"
BorderThickness="1">
<ListBox
x:Name="Selector"
Expand Down
4 changes: 2 additions & 2 deletions src/GitHub.UI/Views/AutoCompleteSuggestionView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
<RectangleGeometry Rect="0,0,24,24" RadiusX="2" RadiusY="2" />
</Image.Clip>
</Image>
<TextBlock x:Name="suggestionText" Style="{DynamicResource GitHubTextBlock}" VerticalAlignment="Center">
<Run x:Name="name" Foreground="{DynamicResource GHTextBrush}" Text="Name" /> <Run x:Name="description" Foreground="{DynamicResource GHTextSecondaryBrush}" Text="Description" />
<TextBlock x:Name="suggestionText" VerticalAlignment="Center">
<Run x:Name="name" Text="Name" /> <Run x:Name="description" Text="Description" />
</TextBlock>
</StackPanel>
</UserControl>
Original file line number Diff line number Diff line change
Expand Up @@ -150,18 +150,30 @@
SpellCheck.IsEnabled="True"
AutomationProperties.AutomationId="{x:Static ghfvs:AutomationIDs.PullRequestCreationTitleTextBox}"/>

<ghfvs:PromptTextBox Grid.Row="2"
MinHeight="100"
Margin="10,5"
AcceptsReturn="True"
PromptText="{x:Static ghfvs:Resources.Description}"
Text="{Binding Description, UpdateSourceTrigger=PropertyChanged}"
Style="{DynamicResource GitHubVsPromptTextBox}"
VerticalScrollBarVisibility="Auto"
TextWrapping="Wrap"
SpellCheck.IsEnabled="True"
AutomationProperties.AutomationId="{x:Static ghfvs:AutomationIDs.PullRequestCreationDescriptionTextBox}"/>

<ghfvs:AutoCompleteBox
Grid.Row="3"
MinHeight="100"
Margin="10,5"
Advisor="{Binding AutoCompleteAdvisor}"
>
<ghfvs:AutoCompleteBox.ItemTemplate>
<DataTemplate>
<ghfvs:AutoCompleteSuggestionView ViewModel="{Binding}" />
</DataTemplate>
</ghfvs:AutoCompleteBox.ItemTemplate>
<ghfvs:AutoCompleteBox.InputElement>
<ghfvs:TextBoxAutoCompleteTextInput>
<ghfvs:PromptTextBox AcceptsReturn="True"
PromptText="{x:Static ghfvs:Resources.Description}"
Text="{Binding Description, UpdateSourceTrigger=PropertyChanged}"
Style="{DynamicResource GitHubVsPromptTextBox}"
VerticalScrollBarVisibility="Auto"
TextWrapping="Wrap"
SpellCheck.IsEnabled="True"/>
</ghfvs:TextBoxAutoCompleteTextInput>
</ghfvs:AutoCompleteBox.InputElement>
</ghfvs:AutoCompleteBox>

<ghfvs:ValidationMessage x:Name="titleValidationMessage"
Grid.Row="3"
Fill="{StaticResource GitHubWarningBrush}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ struct TestData
public IConnection Connection;
public IApiClient ApiClient;
public IModelService ModelService;
public IAutoCompleteAdvisor AutoCompleteAdvisor { get; set; }

public IModelServiceFactory GetModelServiceFactory()
{
Expand All @@ -78,6 +79,7 @@ static TestData PrepareTestData(
var connection = Substitute.For<IConnection>();
var api = Substitute.For<IApiClient>();
var ms = Substitute.For<IModelService>();
var autoCompleteAdvisor = Substitute.For<IAutoCompleteAdvisor>();

connection.HostAddress.Returns(HostAddress.Create("https://github.com"));

Expand Down Expand Up @@ -121,7 +123,8 @@ static TestData PrepareTestData(
NotificationService = notifications,
Connection = connection,
ApiClient = api,
ModelService = ms
ModelService = ms,
AutoCompleteAdvisor = autoCompleteAdvisor
};
}

Expand All @@ -147,7 +150,7 @@ public async Task TargetBranchDisplayNameIncludesRepoOwnerWhenForkAsync()
var prservice = new PullRequestService(data.GitClient, data.GitService, Substitute.For<IVSGitExt>(), Substitute.For<IApiClientFactory>(), Substitute.For<IGraphQLClientFactory>(), data.ServiceProvider.GetOperatingSystem(), Substitute.For<IUsageTracker>());
prservice.GetPullRequestTemplate(data.ActiveRepo).Returns(Observable.Empty<string>());
var vm = new PullRequestCreationViewModel(data.GetModelServiceFactory(), prservice, data.NotificationService,
Substitute.For<IMessageDraftStore>(), data.GitService);
Substitute.For<IMessageDraftStore>(), data.GitService, data.AutoCompleteAdvisor);
await vm.InitializeAsync(data.ActiveRepo, data.Connection);
Assert.That("octokit/master", Is.EqualTo(vm.TargetBranch.DisplayName));
}
Expand Down Expand Up @@ -183,7 +186,7 @@ public async Task CreatingPRsAsync(

var prservice = new PullRequestService(data.GitClient, data.GitService, Substitute.For<IVSGitExt>(), Substitute.For<IApiClientFactory>(), Substitute.For<IGraphQLClientFactory>(), data.ServiceProvider.GetOperatingSystem(), Substitute.For<IUsageTracker>());
var vm = new PullRequestCreationViewModel(data.GetModelServiceFactory(), prservice, data.NotificationService,
Substitute.For<IMessageDraftStore>(), data.GitService);
Substitute.For<IMessageDraftStore>(), data.GitService, data.AutoCompleteAdvisor);
await vm.InitializeAsync(data.ActiveRepo, data.Connection);

// the TargetBranch property gets set to whatever the repo default is (we assume master here),
Expand Down Expand Up @@ -226,7 +229,7 @@ public async Task TemplateIsUsedIfPresentAsync()
prservice.GetPullRequestTemplate(data.ActiveRepo).Returns(Observable.Return("Test PR template"));

var vm = new PullRequestCreationViewModel(data.GetModelServiceFactory(), prservice, data.NotificationService,
Substitute.For<IMessageDraftStore>(), data.GitService);
Substitute.For<IMessageDraftStore>(), data.GitService, data.AutoCompleteAdvisor);
await vm.InitializeAsync(data.ActiveRepo, data.Connection);

Assert.That("Test PR template", Is.EqualTo(vm.Description));
Expand All @@ -246,7 +249,7 @@ public async Task LoadsDraft()

var prservice = Substitute.For<IPullRequestService>();
var vm = new PullRequestCreationViewModel(data.GetModelServiceFactory(), prservice, data.NotificationService,
draftStore, data.GitService);
draftStore, data.GitService, data.AutoCompleteAdvisor);
await vm.InitializeAsync(data.ActiveRepo, data.Connection);

Assert.That(vm.PRTitle, Is.EqualTo("This is a Title."));
Expand All @@ -261,7 +264,7 @@ public async Task UpdatesDraftWhenDescriptionChanges()
var draftStore = Substitute.For<IMessageDraftStore>();
var prservice = Substitute.For<IPullRequestService>();
var vm = new PullRequestCreationViewModel(data.GetModelServiceFactory(), prservice, data.NotificationService,
draftStore, data.GitService, scheduler);
draftStore, data.GitService, data.AutoCompleteAdvisor, scheduler);
await vm.InitializeAsync(data.ActiveRepo, data.Connection);

vm.Description = "Body changed.";
Expand All @@ -284,7 +287,7 @@ public async Task UpdatesDraftWhenTitleChanges()
var draftStore = Substitute.For<IMessageDraftStore>();
var prservice = Substitute.For<IPullRequestService>();
var vm = new PullRequestCreationViewModel(data.GetModelServiceFactory(), prservice, data.NotificationService,
draftStore, data.GitService, scheduler);
draftStore, data.GitService, data.AutoCompleteAdvisor, scheduler);
await vm.InitializeAsync(data.ActiveRepo, data.Connection);

vm.PRTitle = "Title changed.";
Expand All @@ -307,7 +310,7 @@ public async Task DeletesDraftWhenPullRequestSubmitted()
var draftStore = Substitute.For<IMessageDraftStore>();
var prservice = Substitute.For<IPullRequestService>();
var vm = new PullRequestCreationViewModel(data.GetModelServiceFactory(), prservice, data.NotificationService, draftStore,
data.GitService, scheduler);
data.GitService, data.AutoCompleteAdvisor, scheduler);
await vm.InitializeAsync(data.ActiveRepo, data.Connection);

await vm.CreatePullRequest.Execute();
Expand All @@ -323,7 +326,7 @@ public async Task DeletesDraftWhenCanceled()
var draftStore = Substitute.For<IMessageDraftStore>();
var prservice = Substitute.For<IPullRequestService>();
var vm = new PullRequestCreationViewModel(data.GetModelServiceFactory(), prservice, data.NotificationService, draftStore,
data.GitService, scheduler);
data.GitService, data.AutoCompleteAdvisor, scheduler);
await vm.InitializeAsync(data.ActiveRepo, data.Connection);

await vm.Cancel.Execute();
Expand Down