mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-08-12 15:12:11 +00:00
Improved voice recording shortcut labels
This commit is contained in:
parent
d91b11e32a
commit
a41c2e3350
@ -30,6 +30,24 @@ public partial class ConfigurationShortcut : ConfigurationBaseCore
|
||||
[Parameter]
|
||||
public Action<string> ShortcutUpdate { get; set; } = _ => { };
|
||||
|
||||
/// <summary>
|
||||
/// The optional user-facing shortcut label.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<string> ShortcutDisplayName { get; set; } = () => string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The canonical shortcut value the optional user-facing label belongs to.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Func<string> ShortcutDisplaySource { get; set; } = () => string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// An action which is called when the user-facing shortcut label was changed.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Action<string, string> ShortcutDisplayUpdate { get; set; } = (_, _) => { };
|
||||
|
||||
/// <summary>
|
||||
/// The name/identifier of the shortcut (used for conflict detection and registration).
|
||||
/// </summary>
|
||||
@ -64,6 +82,14 @@ public partial class ConfigurationShortcut : ConfigurationBaseCore
|
||||
if (string.IsNullOrWhiteSpace(shortcut))
|
||||
return string.Empty;
|
||||
|
||||
var shortcutDisplayName = this.ShortcutDisplayName();
|
||||
var shortcutDisplaySource = this.ShortcutDisplaySource();
|
||||
if (!string.IsNullOrWhiteSpace(shortcutDisplayName)
|
||||
&& string.Equals(shortcutDisplaySource, shortcut, StringComparison.Ordinal))
|
||||
{
|
||||
return shortcutDisplayName;
|
||||
}
|
||||
|
||||
// Convert internal format to display format:
|
||||
return shortcut
|
||||
.Replace("CmdOrControl", OperatingSystem.IsMacOS() ? "Cmd" : "Ctrl")
|
||||
@ -93,9 +119,17 @@ public partial class ConfigurationShortcut : ConfigurationBaseCore
|
||||
if (dialogResult is null || dialogResult.Canceled)
|
||||
return;
|
||||
|
||||
if (dialogResult.Data is string newShortcut)
|
||||
if (dialogResult.Data is ShortcutDialogResult shortcutResult)
|
||||
{
|
||||
this.ShortcutUpdate(shortcutResult.Shortcut);
|
||||
this.ShortcutDisplayUpdate(shortcutResult.DisplayName, shortcutResult.DisplaySource);
|
||||
await this.SettingsManager.StoreSettings();
|
||||
await this.InformAboutChange();
|
||||
}
|
||||
else if (dialogResult.Data is string newShortcut)
|
||||
{
|
||||
this.ShortcutUpdate(newShortcut);
|
||||
this.ShortcutDisplayUpdate(string.Empty, string.Empty);
|
||||
await this.SettingsManager.StoreSettings();
|
||||
await this.InformAboutChange();
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
@if (PreviewFeatures.PRE_SPEECH_TO_TEXT_2026.IsEnabled(this.SettingsManager))
|
||||
{
|
||||
<ConfigurationSelect OptionDescription="@T("Select a transcription provider")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.UseTranscriptionProvider)" Data="@this.GetFilteredTranscriptionProviders()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.UseTranscriptionProvider = selectedValue)" OptionHelp="@T("Select a transcription provider for transcribing your voice. Without a selected provider, dictation and transcription features will be disabled.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.UseTranscriptionProvider, out var meta) && meta.IsLocked"/>
|
||||
<ConfigurationShortcut ShortcutId="Shortcut.VOICE_RECORDING_TOGGLE" OptionDescription="@T("Voice recording shortcut")" Shortcut="@(() => this.SettingsManager.ConfigurationData.App.ShortcutVoiceRecording)" ShortcutUpdate="@(shortcut => this.SettingsManager.ConfigurationData.App.ShortcutVoiceRecording = shortcut)" OptionHelp="@T("The global keyboard shortcut for toggling voice recording. This shortcut works system-wide, even when the app is not focused.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.ShortcutVoiceRecording, out var meta) && meta.IsLocked"/>
|
||||
<ConfigurationShortcut ShortcutId="Shortcut.VOICE_RECORDING_TOGGLE" OptionDescription="@T("Voice recording shortcut")" Shortcut="@(() => this.SettingsManager.ConfigurationData.App.ShortcutVoiceRecording)" ShortcutUpdate="@(shortcut => this.SettingsManager.ConfigurationData.App.ShortcutVoiceRecording = shortcut)" ShortcutDisplayName="@(() => this.SettingsManager.ConfigurationData.App.ShortcutVoiceRecordingDisplayName)" ShortcutDisplaySource="@(() => this.SettingsManager.ConfigurationData.App.ShortcutVoiceRecordingDisplaySource)" ShortcutDisplayUpdate="@this.UpdateShortcutVoiceRecordingDisplay" OptionHelp="@T("The global keyboard shortcut for toggling voice recording. This shortcut works system-wide, even when the app is not focused.")" IsLocked="() => ManagedConfiguration.TryGet(x => x.App, x => x.ShortcutVoiceRecording, out var meta) && meta.IsLocked"/>
|
||||
}
|
||||
|
||||
@if (this.SettingsManager.ConfigurationData.App.ShowAdminSettings)
|
||||
|
||||
@ -93,6 +93,12 @@ public partial class SettingsPanelApp : SettingsPanelBase
|
||||
this.SettingsManager.ConfigurationData.App.EnabledPreviewFeatures = selectedFeatures;
|
||||
}
|
||||
|
||||
private void UpdateShortcutVoiceRecordingDisplay(string displayName, string displaySource)
|
||||
{
|
||||
this.SettingsManager.ConfigurationData.App.ShortcutVoiceRecordingDisplayName = displayName;
|
||||
this.SettingsManager.ConfigurationData.App.ShortcutVoiceRecordingDisplaySource = displaySource;
|
||||
}
|
||||
|
||||
private async Task UpdateLangBehaviour(LangBehavior behavior)
|
||||
{
|
||||
this.SettingsManager.ConfigurationData.App.LanguageBehavior = behavior;
|
||||
|
||||
@ -34,6 +34,7 @@ public partial class ShortcutDialog : MSGComponentBase
|
||||
|
||||
private string currentShortcut = string.Empty;
|
||||
private string originalShortcut = string.Empty;
|
||||
private string currentDisplayName = string.Empty;
|
||||
private string validationMessage = string.Empty;
|
||||
private Severity validationSeverity = Severity.Info;
|
||||
private bool hasValidationError;
|
||||
@ -115,6 +116,7 @@ public partial class ShortcutDialog : MSGComponentBase
|
||||
{
|
||||
this.UpdateModifiers(e);
|
||||
this.currentKey = null;
|
||||
this.currentDisplayName = string.Empty;
|
||||
this.UpdateShortcutString();
|
||||
return;
|
||||
}
|
||||
@ -123,10 +125,12 @@ public partial class ShortcutDialog : MSGComponentBase
|
||||
|
||||
// Get the key:
|
||||
this.currentKey = TranslateKeyCode(e.Code);
|
||||
this.currentDisplayName = this.BuildDisplayShortcut(e.Key);
|
||||
|
||||
// Validate: must have at least one modifier + a key
|
||||
if (!this.hasCtrl && !this.hasShift && !this.hasAlt && !this.hasMeta)
|
||||
{
|
||||
this.currentDisplayName = string.Empty;
|
||||
this.validationMessage = T("Please include at least one modifier key (Ctrl, Shift, Alt, or Cmd).");
|
||||
this.validationSeverity = Severity.Warning;
|
||||
this.hasValidationError = true;
|
||||
@ -216,6 +220,9 @@ public partial class ShortcutDialog : MSGComponentBase
|
||||
|
||||
private string GetDisplayShortcut()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(this.currentDisplayName))
|
||||
return this.currentDisplayName;
|
||||
|
||||
// Convert internal format to display format:
|
||||
return this.currentShortcut
|
||||
.Replace("CmdOrControl", OperatingSystem.IsMacOS() ? "Cmd" : "Ctrl")
|
||||
@ -225,6 +232,7 @@ public partial class ShortcutDialog : MSGComponentBase
|
||||
private void ClearShortcut()
|
||||
{
|
||||
this.currentShortcut = string.Empty;
|
||||
this.currentDisplayName = string.Empty;
|
||||
this.currentKey = null;
|
||||
this.hasCtrl = false;
|
||||
this.hasShift = false;
|
||||
@ -237,7 +245,17 @@ public partial class ShortcutDialog : MSGComponentBase
|
||||
|
||||
private void Cancel() => this.MudDialog.Cancel();
|
||||
|
||||
private void Confirm() => this.MudDialog.Close(DialogResult.Ok(this.currentShortcut));
|
||||
private void Confirm()
|
||||
{
|
||||
var displaySource = string.IsNullOrWhiteSpace(this.currentDisplayName)
|
||||
? string.Empty
|
||||
: this.currentShortcut;
|
||||
|
||||
this.MudDialog.Close(DialogResult.Ok(new ShortcutDialogResult(
|
||||
this.currentShortcut,
|
||||
this.currentDisplayName,
|
||||
displaySource)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the key code represents a modifier key.
|
||||
@ -377,6 +395,36 @@ public partial class ShortcutDialog : MSGComponentBase
|
||||
_ => code,
|
||||
};
|
||||
|
||||
private string BuildDisplayShortcut(string? key)
|
||||
{
|
||||
var displayKey = GetDisplayKey(key);
|
||||
if (string.IsNullOrWhiteSpace(displayKey))
|
||||
return string.Empty;
|
||||
|
||||
var parts = new List<string>();
|
||||
|
||||
if (this.hasCtrl)
|
||||
parts.Add(OperatingSystem.IsMacOS() ? "Cmd" : "Ctrl");
|
||||
|
||||
if (this.hasShift)
|
||||
parts.Add("Shift");
|
||||
|
||||
if (this.hasAlt)
|
||||
parts.Add("Alt");
|
||||
|
||||
parts.Add(displayKey);
|
||||
return string.Join("+", parts);
|
||||
}
|
||||
|
||||
private static string GetDisplayKey(string? key) => key switch
|
||||
{
|
||||
null or "" => string.Empty,
|
||||
" " => "Space",
|
||||
"Control" or "Shift" or "Alt" or "Meta" => string.Empty,
|
||||
_ when key.Length == 1 && key[0] >= 'a' && key[0] <= 'z' => key.ToUpperInvariant(),
|
||||
_ => key,
|
||||
};
|
||||
|
||||
private void HandleBlur()
|
||||
{
|
||||
// Re-focus the input field to keep capturing keys:
|
||||
|
||||
3
app/MindWork AI Studio/Dialogs/ShortcutDialogResult.cs
Normal file
3
app/MindWork AI Studio/Dialogs/ShortcutDialogResult.cs
Normal file
@ -0,0 +1,3 @@
|
||||
namespace AIStudio.Dialogs;
|
||||
|
||||
public readonly record struct ShortcutDialogResult(string Shortcut, string DisplayName, string DisplaySource);
|
||||
@ -99,6 +99,16 @@ public sealed class DataApp(Expression<Func<Data, DataApp>>? configSelection = n
|
||||
/// </summary>
|
||||
public string ShortcutVoiceRecording { get; set; } = ManagedConfiguration.Register(configSelection, n => n.ShortcutVoiceRecording, string.Empty);
|
||||
|
||||
/// <summary>
|
||||
/// The user-facing label for the voice recording shortcut, based on the user's keyboard layout.
|
||||
/// </summary>
|
||||
public string ShortcutVoiceRecordingDisplayName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The canonical voice recording shortcut value this display label belongs to.
|
||||
/// </summary>
|
||||
public string ShortcutVoiceRecordingDisplaySource { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The HTTP timeout in seconds for external HTTP clients.
|
||||
/// </summary>
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
- Improved workspaces by highlighting the currently open chat in the workspace view.
|
||||
- Improved workspaces by adding a shortcut to start a new chat directly from each workspace row.
|
||||
- Improved workspaces by allowing new workspaces to be created while moving a chat.
|
||||
- Improved voice recording shortcut labels so they match the user's keyboard layout after being configured.
|
||||
- Improved the enterprise configuration details on the information page by showing where each configuration comes from and which configuration slot was used.
|
||||
- Fixed workspace creation and renaming to prevent new workspaces from using an existing name.
|
||||
- Fixed an issue on Microsoft Windows where reading attached documents could briefly open a terminal window while processing files.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user