Skip to content

Commit e04f087

Browse files
RichCommands: Switch tabs command (#11916)
1 parent 794fd79 commit e04f087

File tree

9 files changed

+162
-61
lines changed

9 files changed

+162
-61
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using CommunityToolkit.Mvvm.ComponentModel;
2+
using CommunityToolkit.Mvvm.DependencyInjection;
3+
using Files.App.Commands;
4+
using Files.App.Contexts;
5+
using Files.App.Extensions;
6+
using System.ComponentModel;
7+
using System.Threading.Tasks;
8+
using Windows.System;
9+
10+
namespace Files.App.Actions
11+
{
12+
internal class CloseSelectedTabAction : ObservableObject, IAction
13+
{
14+
private readonly IMultitaskingContext context = Ioc.Default.GetRequiredService<IMultitaskingContext>();
15+
16+
public string Label { get; } = "CloseTab".GetLocalizedResource();
17+
18+
public string Description { get; } = "TODO: Need to be described.";
19+
20+
public HotKey HotKey { get; } = new(VirtualKey.W, VirtualKeyModifiers.Control);
21+
22+
public HotKey SecondHotKey { get; } = new(VirtualKey.F4, VirtualKeyModifiers.Control);
23+
24+
public RichGlyph Glyph { get; } = new();
25+
26+
public bool IsExecutable =>
27+
context.Control is not null &&
28+
context.TabCount > 0 &&
29+
context.CurrentTabItem is not null;
30+
31+
public CloseSelectedTabAction()
32+
{
33+
context.PropertyChanged += Context_PropertyChanged;
34+
}
35+
36+
public Task ExecuteAsync()
37+
{
38+
context.Control!.CloseTab(context.CurrentTabItem);
39+
40+
return Task.CompletedTask;
41+
}
42+
43+
private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
44+
{
45+
switch (e.PropertyName)
46+
{
47+
case nameof(IMultitaskingContext.CurrentTabItem):
48+
case nameof(IMultitaskingContext.Control):
49+
case nameof(IMultitaskingContext.TabCount):
50+
OnPropertyChanged(nameof(IsExecutable));
51+
break;
52+
}
53+
}
54+
}
55+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using CommunityToolkit.Mvvm.ComponentModel;
2+
using CommunityToolkit.Mvvm.DependencyInjection;
3+
using Files.App.Commands;
4+
using Files.App.Contexts;
5+
using Files.App.Extensions;
6+
using System.ComponentModel;
7+
using System.Threading.Tasks;
8+
using Windows.System;
9+
10+
namespace Files.App.Actions
11+
{
12+
internal class NextTabAction : ObservableObject, IAction
13+
{
14+
private readonly IMultitaskingContext multitaskingContext = Ioc.Default.GetRequiredService<IMultitaskingContext>();
15+
16+
public string Label { get; } = "NextTab".GetLocalizedResource();
17+
18+
public string Description { get; } = "TODO: Need to be described.";
19+
20+
public bool IsExecutable => multitaskingContext.TabCount > 1;
21+
22+
public HotKey HotKey { get; } = new(VirtualKey.Tab, VirtualKeyModifiers.Control);
23+
24+
public NextTabAction()
25+
{
26+
multitaskingContext.PropertyChanged += MultitaskingContext_PropertyChanged;
27+
}
28+
29+
public Task ExecuteAsync()
30+
{
31+
App.AppModel.TabStripSelectedIndex = (App.AppModel.TabStripSelectedIndex + 1) % multitaskingContext.TabCount;
32+
return Task.CompletedTask;
33+
}
34+
35+
private void MultitaskingContext_PropertyChanged(object? sender, PropertyChangedEventArgs e)
36+
{
37+
if (e.PropertyName == nameof(IMultitaskingContext.TabCount))
38+
OnPropertyChanged(nameof(IsExecutable));
39+
}
40+
}
41+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using CommunityToolkit.Mvvm.ComponentModel;
2+
using CommunityToolkit.Mvvm.DependencyInjection;
3+
using Files.App.Commands;
4+
using Files.App.Contexts;
5+
using Files.App.Extensions;
6+
using System.ComponentModel;
7+
using System.Threading.Tasks;
8+
using Windows.System;
9+
10+
namespace Files.App.Actions
11+
{
12+
internal class PreviousTabAction : ObservableObject, IAction
13+
{
14+
private readonly IMultitaskingContext multitaskingContext = Ioc.Default.GetRequiredService<IMultitaskingContext>();
15+
16+
public string Label { get; } = "PreviousTab".GetLocalizedResource();
17+
18+
public string Description { get; } = "TODO: Need to be described.";
19+
20+
public bool IsExecutable => multitaskingContext.TabCount > 1;
21+
22+
public HotKey HotKey { get; } = new(VirtualKey.Tab, VirtualKeyModifiers.Control | VirtualKeyModifiers.Shift);
23+
24+
public PreviousTabAction()
25+
{
26+
multitaskingContext.PropertyChanged += MultitaskingContext_PropertyChanged;
27+
}
28+
29+
public Task ExecuteAsync()
30+
{
31+
if (App.AppModel.TabStripSelectedIndex is 0)
32+
App.AppModel.TabStripSelectedIndex = multitaskingContext.TabCount - 1;
33+
else
34+
App.AppModel.TabStripSelectedIndex--;
35+
36+
return Task.CompletedTask;
37+
}
38+
39+
private void MultitaskingContext_PropertyChanged(object? sender, PropertyChangedEventArgs e)
40+
{
41+
if (e.PropertyName == nameof(IMultitaskingContext.TabCount))
42+
OnPropertyChanged(nameof(IsExecutable));
43+
}
44+
}
45+
}

src/Files.App/Commands/CommandCodes.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,5 +145,8 @@ public enum CommandCodes
145145
CloseOtherTabsCurrent,
146146
CloseOtherTabsSelected,
147147
ReopenClosedTab,
148+
PreviousTab,
149+
NextTab,
150+
CloseSelectedTab,
148151
}
149152
}

src/Files.App/Commands/Manager/CommandManager.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ internal class CommandManager : ICommandManager
127127
public IRichCommand CloseOtherTabsCurrent => commands[CommandCodes.CloseOtherTabsCurrent];
128128
public IRichCommand CloseOtherTabsSelected => commands[CommandCodes.CloseOtherTabsSelected];
129129
public IRichCommand ReopenClosedTab => commands[CommandCodes.ReopenClosedTab];
130+
public IRichCommand PreviousTab => commands[CommandCodes.PreviousTab];
131+
public IRichCommand NextTab => commands[CommandCodes.NextTab];
132+
public IRichCommand CloseSelectedTab => commands[CommandCodes.CloseSelectedTab];
130133

131134
public CommandManager()
132135
{
@@ -260,6 +263,9 @@ public CommandManager()
260263
[CommandCodes.CloseOtherTabsCurrent] = new CloseOtherTabsCurrentAction(),
261264
[CommandCodes.CloseOtherTabsSelected] = new CloseOtherTabsSelectedAction(),
262265
[CommandCodes.ReopenClosedTab] = new ReopenClosedTabAction(),
266+
[CommandCodes.PreviousTab] = new PreviousTabAction(),
267+
[CommandCodes.NextTab] = new NextTabAction(),
268+
[CommandCodes.CloseSelectedTab] = new CloseSelectedTabAction(),
263269
};
264270

265271
[DebuggerDisplay("Command None")]

src/Files.App/Commands/Manager/ICommandManager.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,5 +128,8 @@ public interface ICommandManager : IEnumerable<IRichCommand>
128128
IRichCommand CloseOtherTabsCurrent { get; }
129129
IRichCommand CloseOtherTabsSelected { get; }
130130
IRichCommand ReopenClosedTab { get; }
131+
IRichCommand PreviousTab { get; }
132+
IRichCommand NextTab { get; }
133+
IRichCommand CloseSelectedTab { get; }
131134
}
132135
}

src/Files.App/Strings/en-US/Resources.resw

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2860,4 +2860,13 @@
28602860
<data name="Untagged" xml:space="preserve">
28612861
<value>Untagged</value>
28622862
</data>
2863+
<data name="PreviousTab" xml:space="preserve">
2864+
<value>Moves to the previous tab</value>
2865+
</data>
2866+
<data name="NextTab" xml:space="preserve">
2867+
<value>Moves to the next tab</value>
2868+
</data>
2869+
<data name="CloseTab" xml:space="preserve">
2870+
<value>Closes current tab</value>
2871+
</data>
28632872
</root>

src/Files.App/ViewModels/MainPageViewModel.cs

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ public TabItem? SelectedTabItem
4444

4545
public ICommand NavigateToNumberedTabKeyboardAcceleratorCommand { get; private set; }
4646
public IAsyncRelayCommand OpenNewWindowAcceleratorCommand { get; private set; }
47-
public ICommand CloseSelectedTabKeyboardAcceleratorCommand { get; private set; }
4847

4948
public MainPageViewModel(
5049
IUserSettingsService userSettings,
@@ -57,7 +56,6 @@ public MainPageViewModel(
5756
// Create commands
5857
NavigateToNumberedTabKeyboardAcceleratorCommand = new RelayCommand<KeyboardAcceleratorInvokedEventArgs>(NavigateToNumberedTabKeyboardAccelerator);
5958
OpenNewWindowAcceleratorCommand = new AsyncRelayCommand<KeyboardAcceleratorInvokedEventArgs>(OpenNewWindowAccelerator);
60-
CloseSelectedTabKeyboardAcceleratorCommand = new RelayCommand<KeyboardAcceleratorInvokedEventArgs>(CloseSelectedTabKeyboardAccelerator);
6159
}
6260

6361
private void NavigateToNumberedTabKeyboardAccelerator(KeyboardAcceleratorInvokedEventArgs? e)
@@ -101,26 +99,6 @@ private void NavigateToNumberedTabKeyboardAccelerator(KeyboardAcceleratorInvoked
10199
// Select the last tab
102100
indexToSelect = AppInstances.Count - 1;
103101
break;
104-
105-
case VirtualKey.Tab:
106-
bool shift = e.KeyboardAccelerator.Modifiers.HasFlag(VirtualKeyModifiers.Shift);
107-
108-
if (!shift) // ctrl + tab, select next tab
109-
{
110-
if ((App.AppModel.TabStripSelectedIndex + 1) < AppInstances.Count)
111-
indexToSelect = App.AppModel.TabStripSelectedIndex + 1;
112-
else
113-
indexToSelect = 0;
114-
}
115-
else // ctrl + shift + tab, select previous tab
116-
{
117-
if ((App.AppModel.TabStripSelectedIndex - 1) >= 0)
118-
indexToSelect = App.AppModel.TabStripSelectedIndex - 1;
119-
else
120-
indexToSelect = AppInstances.Count - 1;
121-
}
122-
123-
break;
124102
}
125103

126104
// Only select the tab if it is in the list
@@ -136,17 +114,6 @@ private async Task OpenNewWindowAccelerator(KeyboardAcceleratorInvokedEventArgs?
136114
e!.Handled = true;
137115
}
138116

139-
private void CloseSelectedTabKeyboardAccelerator(KeyboardAcceleratorInvokedEventArgs? e)
140-
{
141-
var index = App.AppModel.TabStripSelectedIndex >= AppInstances.Count
142-
? AppInstances.Count - 1
143-
: App.AppModel.TabStripSelectedIndex;
144-
145-
var tabItem = AppInstances[index];
146-
MultitaskingControl?.CloseTab(tabItem);
147-
e!.Handled = true;
148-
}
149-
150117
public static async Task AddNewTabByPathAsync(Type type, string? path, int atIndex = -1)
151118
{
152119
if (string.IsNullOrEmpty(path))

src/Files.App/Views/MainPage.xaml

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -96,41 +96,13 @@
9696
</icore:EventTriggerBehavior>
9797
</i:Interaction.Behaviors>
9898
</KeyboardAccelerator>
99-
<KeyboardAccelerator Key="Tab" Modifiers="Control,Shift">
100-
<i:Interaction.Behaviors>
101-
<icore:EventTriggerBehavior EventName="Invoked">
102-
<icore:InvokeCommandAction Command="{x:Bind ViewModel.NavigateToNumberedTabKeyboardAcceleratorCommand}" />
103-
</icore:EventTriggerBehavior>
104-
</i:Interaction.Behaviors>
105-
</KeyboardAccelerator>
106-
<KeyboardAccelerator Key="Tab" Modifiers="Control">
107-
<i:Interaction.Behaviors>
108-
<icore:EventTriggerBehavior EventName="Invoked">
109-
<icore:InvokeCommandAction Command="{x:Bind ViewModel.NavigateToNumberedTabKeyboardAcceleratorCommand}" />
110-
</icore:EventTriggerBehavior>
111-
</i:Interaction.Behaviors>
112-
</KeyboardAccelerator>
11399
<KeyboardAccelerator Key="N" Modifiers="Control">
114100
<i:Interaction.Behaviors>
115101
<icore:EventTriggerBehavior EventName="Invoked">
116102
<icore:InvokeCommandAction Command="{x:Bind ViewModel.OpenNewWindowAcceleratorCommand}" />
117103
</icore:EventTriggerBehavior>
118104
</i:Interaction.Behaviors>
119105
</KeyboardAccelerator>
120-
<KeyboardAccelerator Key="F4" Modifiers="Control">
121-
<i:Interaction.Behaviors>
122-
<icore:EventTriggerBehavior EventName="Invoked">
123-
<icore:InvokeCommandAction Command="{x:Bind ViewModel.CloseSelectedTabKeyboardAcceleratorCommand}" />
124-
</icore:EventTriggerBehavior>
125-
</i:Interaction.Behaviors>
126-
</KeyboardAccelerator>
127-
<KeyboardAccelerator Key="W" Modifiers="Control">
128-
<i:Interaction.Behaviors>
129-
<icore:EventTriggerBehavior EventName="Invoked">
130-
<icore:InvokeCommandAction Command="{x:Bind ViewModel.CloseSelectedTabKeyboardAcceleratorCommand}" />
131-
</icore:EventTriggerBehavior>
132-
</i:Interaction.Behaviors>
133-
</KeyboardAccelerator>
134106
</Page.KeyboardAccelerators>
135107

136108
<Border>

0 commit comments

Comments
 (0)