Skip to content

Commit 10567fd

Browse files
authored
Merge branch 'dev' into administrator_mode
2 parents 81667d0 + 5e026c0 commit 10567fd

File tree

5 files changed

+122
-48
lines changed

5 files changed

+122
-48
lines changed

Flow.Launcher.Core/Resource/Internationalization.cs

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Globalization;
34
using System.IO;
45
using System.Linq;
56
using System.Reflection;
7+
using System.Threading;
8+
using System.Threading.Tasks;
69
using System.Windows;
10+
using CommunityToolkit.Mvvm.DependencyInjection;
711
using Flow.Launcher.Core.Plugin;
812
using Flow.Launcher.Infrastructure;
913
using Flow.Launcher.Infrastructure.UserSettings;
1014
using Flow.Launcher.Plugin;
11-
using System.Globalization;
12-
using System.Threading.Tasks;
13-
using CommunityToolkit.Mvvm.DependencyInjection;
1415

1516
namespace Flow.Launcher.Core.Resource
1617
{
@@ -29,13 +30,12 @@ public class Internationalization
2930
private readonly Settings _settings;
3031
private readonly List<string> _languageDirectories = new();
3132
private readonly List<ResourceDictionary> _oldResources = new();
32-
private readonly string SystemLanguageCode;
33+
private static string SystemLanguageCode;
3334

3435
public Internationalization(Settings settings)
3536
{
3637
_settings = settings;
3738
AddFlowLauncherLanguageDirectory();
38-
SystemLanguageCode = GetSystemLanguageCodeAtStartup();
3939
}
4040

4141
private void AddFlowLauncherLanguageDirectory()
@@ -44,7 +44,7 @@ private void AddFlowLauncherLanguageDirectory()
4444
_languageDirectories.Add(directory);
4545
}
4646

47-
private static string GetSystemLanguageCodeAtStartup()
47+
public static void InitSystemLanguageCode()
4848
{
4949
var availableLanguages = AvailableLanguages.GetAvailableLanguages();
5050

@@ -65,11 +65,11 @@ private static string GetSystemLanguageCodeAtStartup()
6565
string.Equals(languageCode, threeLetterCode, StringComparison.OrdinalIgnoreCase) ||
6666
string.Equals(languageCode, fullName, StringComparison.OrdinalIgnoreCase))
6767
{
68-
return languageCode;
68+
SystemLanguageCode = languageCode;
6969
}
7070
}
7171

72-
return DefaultLanguageCode;
72+
SystemLanguageCode = DefaultLanguageCode;
7373
}
7474

7575
private void AddPluginLanguageDirectories()
@@ -173,15 +173,33 @@ private async Task ChangeLanguageAsync(Language language)
173173
LoadLanguage(language);
174174
}
175175

176-
// Culture of main thread
177-
// Use CreateSpecificCulture to preserve possible user-override settings in Windows, if Flow's language culture is the same as Windows's
178-
CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture(language.LanguageCode);
179-
CultureInfo.CurrentUICulture = CultureInfo.CurrentCulture;
176+
// Change culture info
177+
ChangeCultureInfo(language.LanguageCode);
180178

181179
// Raise event for plugins after culture is set
182180
await Task.Run(UpdatePluginMetadataTranslations);
183181
}
184182

183+
public static void ChangeCultureInfo(string languageCode)
184+
{
185+
// Culture of main thread
186+
// Use CreateSpecificCulture to preserve possible user-override settings in Windows, if Flow's language culture is the same as Windows's
187+
CultureInfo currentCulture;
188+
try
189+
{
190+
currentCulture = CultureInfo.CreateSpecificCulture(languageCode);
191+
}
192+
catch (CultureNotFoundException)
193+
{
194+
currentCulture = CultureInfo.CreateSpecificCulture(SystemLanguageCode);
195+
}
196+
CultureInfo.CurrentCulture = currentCulture;
197+
CultureInfo.CurrentUICulture = currentCulture;
198+
var thread = Thread.CurrentThread;
199+
thread.CurrentCulture = currentCulture;
200+
thread.CurrentUICulture = currentCulture;
201+
}
202+
185203
public bool PromptShouldUsePinyin(string languageCodeToSet)
186204
{
187205
var languageToSet = GetLanguageByLanguageCode(languageCodeToSet);

Flow.Launcher.Infrastructure/UserSettings/Settings.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,13 @@ public void SetStorage(FlowLauncherJsonStorage<Settings> storage)
2525

2626
public void Initialize()
2727
{
28+
// Initialize dependency injection instances after Ioc.Default is created
2829
_stringMatcher = Ioc.Default.GetRequiredService<StringMatcher>();
30+
31+
// Initialize application resources after application is created
32+
var settingWindowFont = new FontFamily(SettingWindowFont);
33+
Application.Current.Resources["SettingWindowFont"] = settingWindowFont;
34+
Application.Current.Resources["ContentControlThemeFontFamily"] = settingWindowFont;
2935
}
3036

3137
public void Save()
@@ -119,8 +125,11 @@ public string SettingWindowFont
119125
{
120126
_settingWindowFont = value;
121127
OnPropertyChanged();
122-
Application.Current.Resources["SettingWindowFont"] = new FontFamily(value);
123-
Application.Current.Resources["ContentControlThemeFontFamily"] = new FontFamily(value);
128+
if (Application.Current != null)
129+
{
130+
Application.Current.Resources["SettingWindowFont"] = new FontFamily(value);
131+
Application.Current.Resources["ContentControlThemeFontFamily"] = new FontFamily(value);
132+
}
124133
}
125134
}
126135
}

Flow.Launcher/App.xaml.cs

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ public partial class App : IDisposable, ISingleInstanceApp
4343
private static readonly string ClassName = nameof(App);
4444

4545
private static bool _disposed;
46+
private static Settings _settings;
4647
private static MainWindow _mainWindow;
4748
private readonly MainViewModel _mainVM;
48-
private readonly Settings _settings;
4949

5050
// To prevent two disposals running at the same time.
5151
private static readonly object _disposingLock = new();
@@ -57,18 +57,7 @@ public partial class App : IDisposable, ISingleInstanceApp
5757
public App()
5858
{
5959
// Initialize settings
60-
try
61-
{
62-
var storage = new FlowLauncherJsonStorage<Settings>();
63-
_settings = storage.Load();
64-
_settings.SetStorage(storage);
65-
_settings.WMPInstalled = WindowsMediaPlayerHelper.IsWindowsMediaPlayerInstalled();
66-
}
67-
catch (Exception e)
68-
{
69-
ShowErrorMsgBoxAndFailFast("Cannot load setting storage, please check local data directory", e);
70-
return;
71-
}
60+
_settings.WMPInstalled = WindowsMediaPlayerHelper.IsWindowsMediaPlayerInstalled();
7261

7362
// Check if the application is running as administrator
7463
if (_settings.AlwaysRunAsAdministrator && !Win32Helper.IsAdministrator())
@@ -132,16 +121,6 @@ public App()
132121
ShowErrorMsgBoxAndFailFast("Cannot initialize api and settings, please open new issue in Flow.Launcher", e);
133122
return;
134123
}
135-
136-
// Local function
137-
static void ShowErrorMsgBoxAndFailFast(string message, Exception e)
138-
{
139-
// Firstly show users the message
140-
MessageBox.Show(e.ToString(), message, MessageBoxButton.OK, MessageBoxImage.Error);
141-
142-
// Flow cannot construct its App instance, so ensure Flow crashes w/ the exception info.
143-
Environment.FailFast(message, e);
144-
}
145124
}
146125

147126
#endregion
@@ -151,6 +130,29 @@ static void ShowErrorMsgBoxAndFailFast(string message, Exception e)
151130
[STAThread]
152131
public static void Main()
153132
{
133+
// Initialize settings so that we can get language code
134+
try
135+
{
136+
var storage = new FlowLauncherJsonStorage<Settings>();
137+
_settings = storage.Load();
138+
_settings.SetStorage(storage);
139+
}
140+
catch (Exception e)
141+
{
142+
ShowErrorMsgBoxAndFailFast("Cannot load setting storage, please check local data directory", e);
143+
return;
144+
}
145+
146+
// Initialize system language before changing culture info
147+
Internationalization.InitSystemLanguageCode();
148+
149+
// Change culture info before application creation to localize WinForm windows
150+
if (_settings.Language != Constant.SystemLanguageCode)
151+
{
152+
Internationalization.ChangeCultureInfo(_settings.Language);
153+
}
154+
155+
// Start the application as a single instance
154156
if (SingleInstance<App>.InitializeAsFirstInstance())
155157
{
156158
using var application = new App();
@@ -161,6 +163,19 @@ public static void Main()
161163

162164
#endregion
163165

166+
#region Fail Fast
167+
168+
private static void ShowErrorMsgBoxAndFailFast(string message, Exception e)
169+
{
170+
// Firstly show users the message
171+
MessageBox.Show(e.ToString(), message, MessageBoxButton.OK, MessageBoxImage.Error);
172+
173+
// Flow cannot construct its App instance, so ensure Flow crashes w/ the exception info.
174+
Environment.FailFast(message, e);
175+
}
176+
177+
#endregion
178+
164179
#region App Events
165180

166181
#pragma warning disable VSTHRD100 // Avoid async void methods
Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
1-
using Microsoft.Win32;
1+
using System;
2+
using Microsoft.Win32;
23

34
namespace Flow.Launcher.Helper;
5+
46
internal static class WindowsMediaPlayerHelper
57
{
8+
private static readonly string ClassName = nameof(WindowsMediaPlayerHelper);
9+
610
internal static bool IsWindowsMediaPlayerInstalled()
711
{
8-
using var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\MediaPlayer");
9-
return key?.GetValue("Installation Directory") != null;
12+
try
13+
{
14+
using var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\MediaPlayer");
15+
return key?.GetValue("Installation Directory") != null;
16+
}
17+
catch (Exception e)
18+
{
19+
App.API.LogException(ClassName, "Failed to check if Windows Media Player is installed", e);
20+
return false;
21+
}
1022
}
1123
}

Plugins/Flow.Launcher.Plugin.Shell/Main.cs

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -194,10 +194,13 @@ private ProcessStartInfo PrepareProcessStartInfo(string command, bool runAsAdmin
194194
var workingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
195195
var runAsAdministratorArg = !runAsAdministrator && !_settings.RunAsAdministrator ? "" : "runas";
196196

197-
ProcessStartInfo info = new()
197+
var info = new ProcessStartInfo()
198198
{
199-
Verb = runAsAdministratorArg, WorkingDirectory = workingDirectory,
199+
Verb = runAsAdministratorArg,
200+
WorkingDirectory = workingDirectory,
200201
};
202+
var notifyStr = Context.API.GetTranslation("flowlauncher_plugin_cmd_press_any_key_to_close");
203+
var addedCharacter = _settings.UseWindowsTerminal ? "\\" : "";
201204
switch (_settings.Shell)
202205
{
203206
case Shell.Cmd:
@@ -211,16 +214,26 @@ private ProcessStartInfo PrepareProcessStartInfo(string command, bool runAsAdmin
211214
{
212215
info.FileName = "cmd.exe";
213216
}
214-
215-
info.ArgumentList.Add($"{(_settings.LeaveShellOpen ? "/k" : "/c")} {command} {(_settings.CloseShellAfterPress ? $"&& echo {Context.API.GetTranslation("flowlauncher_plugin_cmd_press_any_key_to_close")} && pause > nul /c" : "")}");
217+
if (_settings.LeaveShellOpen)
218+
{
219+
info.ArgumentList.Add("/k");
220+
}
221+
else
222+
{
223+
info.ArgumentList.Add("/c");
224+
}
225+
info.ArgumentList.Add(
226+
$"{command}" +
227+
$"{(_settings.CloseShellAfterPress ?
228+
$" && echo {notifyStr} && pause > nul /c" :
229+
"")}");
216230
break;
217231
}
218232

219233
case Shell.Powershell:
220234
{
221235
// Using just a ; doesn't work with wt, as it's used to create a new tab for the terminal window
222236
// \\ must be escaped for it to work properly, or breaking it into multiple arguments
223-
var addedCharacter = _settings.UseWindowsTerminal ? "\\" : "";
224237
if (_settings.UseWindowsTerminal)
225238
{
226239
info.FileName = "wt.exe";
@@ -238,7 +251,11 @@ private ProcessStartInfo PrepareProcessStartInfo(string command, bool runAsAdmin
238251
else
239252
{
240253
info.ArgumentList.Add("-Command");
241-
info.ArgumentList.Add($"{command}{addedCharacter}; {(_settings.CloseShellAfterPress ? $"Write-Host '{Context.API.GetTranslation("flowlauncher_plugin_cmd_press_any_key_to_close")}'{addedCharacter}; [System.Console]::ReadKey(){addedCharacter}; exit" : "")}");
254+
info.ArgumentList.Add(
255+
$"{command}{addedCharacter};" +
256+
$"{(_settings.CloseShellAfterPress ?
257+
$" Write-Host '{notifyStr}'{addedCharacter}; [System.Console]::ReadKey(){addedCharacter}; exit" :
258+
"")}");
242259
}
243260
break;
244261
}
@@ -247,7 +264,6 @@ private ProcessStartInfo PrepareProcessStartInfo(string command, bool runAsAdmin
247264
{
248265
// Using just a ; doesn't work with wt, as it's used to create a new tab for the terminal window
249266
// \\ must be escaped for it to work properly, or breaking it into multiple arguments
250-
var addedCharacter = _settings.UseWindowsTerminal ? "\\" : "";
251267
if (_settings.UseWindowsTerminal)
252268
{
253269
info.FileName = "wt.exe";
@@ -262,7 +278,11 @@ private ProcessStartInfo PrepareProcessStartInfo(string command, bool runAsAdmin
262278
info.ArgumentList.Add("-NoExit");
263279
}
264280
info.ArgumentList.Add("-Command");
265-
info.ArgumentList.Add($"{command}{addedCharacter}; {(_settings.CloseShellAfterPress ? $"Write-Host '{Context.API.GetTranslation("flowlauncher_plugin_cmd_press_any_key_to_close")}'{addedCharacter}; [System.Console]::ReadKey(){addedCharacter}; exit" : "")}");
281+
info.ArgumentList.Add(
282+
$"{command}{addedCharacter};" +
283+
$"{(_settings.CloseShellAfterPress ?
284+
$" Write-Host '{notifyStr}'{addedCharacter}; [System.Console]::ReadKey(){addedCharacter}; exit" :
285+
"")}");
266286
break;
267287
}
268288

0 commit comments

Comments
 (0)