Skip to content

Commit 284a771

Browse files
committed
feat: macOS hotkey fix, UI improvements, PKG packaging, test coverage
- Fix CGKeyboardEventKeycode constant (6→9) that prevented hotkey matching - Rename LiveLingo.App→LiveLingo.Desktop to avoid macOS .app bundle misidentification - Add macOS text injection with target window activation and proper timing - Beautify About dialog and permission check dialog with dark theme - Suppress llama.cpp native log output, reduce model log noise to Debug level - Add full-chain logging: hotkey trigger → overlay show → translation - Enable "Check Updates" tray menu item regardless of update URL config - Add PackMac Nuke target for .pkg installer generation - Fix Smoke tests by loading AppTheme.axaml in TestAppBuilder - Expand test coverage: all key mappings, parser edge cases, VM commands - 524 tests passing (235 Core + 289 Desktop) Made-with: Cursor
1 parent b927c4d commit 284a771

File tree

90 files changed

+2339
-765
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+2339
-765
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,3 +425,4 @@ coverage-report/
425425

426426
# Nuke temp
427427
.nuke/temp/
428+
.DS_Store

LiveLingo.slnx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<Solution>
22
<Folder Name="/src/">
3-
<Project Path="src/LiveLingo.App/LiveLingo.App.csproj" />
3+
<Project Path="src/LiveLingo.Desktop/LiveLingo.Desktop.csproj" />
44
<Project Path="src/LiveLingo.Core/LiveLingo.Core.csproj" />
55
</Folder>
66
<Folder Name="/tests/">
7-
<Project Path="tests/LiveLingo.App.Tests/LiveLingo.App.Tests.csproj" />
7+
<Project Path="tests/LiveLingo.Desktop.Tests/LiveLingo.Desktop.Tests.csproj" />
88
<Project Path="tests/LiveLingo.Core.Tests/LiveLingo.Core.Tests.csproj" />
99
</Folder>
1010
</Solution>

build/BuildTask.cs

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class BuildTask : NukeBuild
4343
AbsolutePath ReleasesDir => RootDirectory / "releases";
4444
AbsolutePath RunSettingsFile => RootDirectory / "test.runsettings";
4545

46-
AbsolutePath AppProject => SourceDir / "LiveLingo.App" / "LiveLingo.App.csproj";
46+
AbsolutePath AppProject => SourceDir / "LiveLingo.Desktop" / "LiveLingo.Desktop.csproj";
4747

4848
Target Clean => _ => _
4949
.Before(Restore)
@@ -241,7 +241,7 @@ double RunMutationTesting()
241241
{
242242
DotNetToolRestore();
243243

244-
var mainExe = Runtime.StartsWith("win") ? "LiveLingo.App.exe" : "LiveLingo.App";
244+
var mainExe = Runtime.StartsWith("win") ? "LiveLingo.Desktop.exe" : "LiveLingo.Desktop";
245245

246246
var tempDir = RootDirectory / ".nuke" / "temp" / "vpk";
247247
tempDir.CreateDirectory();
@@ -262,4 +262,83 @@ double RunMutationTesting()
262262
$"--outputDir {ReleasesDir}",
263263
environmentVariables: vpkEnv);
264264
});
265+
266+
Target PackMac => _ => _
267+
.DependsOn(Publish)
268+
.Requires(() => Runtime.StartsWith("osx"))
269+
.Executes(() =>
270+
{
271+
var macosDir = RootDirectory / "build" / "macos";
272+
var appBundle = PublishDir / "LiveLingo.app";
273+
var contentsDir = appBundle / "Contents";
274+
var macOsDir = contentsDir / "MacOS";
275+
var resourcesDir = contentsDir / "Resources";
276+
277+
appBundle.DeleteDirectory();
278+
macOsDir.CreateDirectory();
279+
resourcesDir.CreateDirectory();
280+
281+
var infoPlist = File.ReadAllText(macosDir / "Info.plist");
282+
infoPlist = infoPlist.Replace("__VERSION__", Version);
283+
File.WriteAllText(contentsDir / "Info.plist", infoPlist);
284+
285+
File.Copy(macosDir / "entitlements.plist", contentsDir / "entitlements.plist", overwrite: true);
286+
287+
var publishedFiles = PublishDir / Runtime;
288+
foreach (var file in Directory.GetFiles(publishedFiles, "*", SearchOption.AllDirectories))
289+
{
290+
var relative = Path.GetRelativePath(publishedFiles, file);
291+
var dest = macOsDir / relative;
292+
Directory.CreateDirectory(Path.GetDirectoryName(dest)!);
293+
File.Copy(file, dest, overwrite: true);
294+
}
295+
296+
var mainExe = macOsDir / "LiveLingo.Desktop";
297+
if (File.Exists(mainExe))
298+
Chmod(mainExe, "755");
299+
300+
var svgIcon = RootDirectory / "src" / "LiveLingo.Desktop" / "Assets" / "app-icon.svg";
301+
if (File.Exists(svgIcon))
302+
File.Copy(svgIcon, resourcesDir / "app-icon.svg", overwrite: true);
303+
304+
ReleasesDir.CreateDirectory();
305+
306+
var componentPkg = PublishDir / "LiveLingo-component.pkg";
307+
RunProcess("pkgbuild",
308+
$"--root \"{appBundle}\" " +
309+
$"--identifier com.livelingo.app " +
310+
$"--version {Version} " +
311+
$"--install-location /Applications/LiveLingo.app " +
312+
$"\"{componentPkg}\"");
313+
314+
var finalPkg = ReleasesDir / $"LiveLingo-{Version}-{Runtime}.pkg";
315+
RunProcess("productbuild",
316+
$"--package \"{componentPkg}\" " +
317+
$"\"{finalPkg}\"");
318+
319+
componentPkg.DeleteFile();
320+
Log.Information("macOS PKG created: {Path}", finalPkg);
321+
});
322+
323+
static void Chmod(string path, string mode)
324+
{
325+
RunProcess("chmod", $"{mode} \"{path}\"");
326+
}
327+
328+
static void RunProcess(string tool, string arguments)
329+
{
330+
var psi = new System.Diagnostics.ProcessStartInfo(tool, arguments)
331+
{
332+
RedirectStandardOutput = true,
333+
RedirectStandardError = true,
334+
UseShellExecute = false
335+
};
336+
using var proc = System.Diagnostics.Process.Start(psi)!;
337+
proc.WaitForExit();
338+
if (proc.ExitCode != 0)
339+
{
340+
var stderr = proc.StandardError.ReadToEnd();
341+
throw new Exception($"{tool} failed (exit {proc.ExitCode}): {stderr}");
342+
}
343+
}
265344
}

build/macos/Info.plist

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>CFBundleName</key>
6+
<string>LiveLingo</string>
7+
<key>CFBundleDisplayName</key>
8+
<string>LiveLingo</string>
9+
<key>CFBundleIdentifier</key>
10+
<string>com.livelingo.app</string>
11+
<key>CFBundleVersion</key>
12+
<string>__VERSION__</string>
13+
<key>CFBundleShortVersionString</key>
14+
<string>__VERSION__</string>
15+
<key>CFBundlePackageType</key>
16+
<string>APPL</string>
17+
<key>CFBundleExecutable</key>
18+
<string>LiveLingo.Desktop</string>
19+
<key>LSMinimumSystemVersion</key>
20+
<string>12.0</string>
21+
<key>NSHighResolutionCapable</key>
22+
<true/>
23+
<key>LSUIElement</key>
24+
<true/>
25+
<key>NSPrincipalClass</key>
26+
<string>NSApplication</string>
27+
</dict>
28+
</plist>

build/macos/entitlements.plist

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>com.apple.security.automation.apple-events</key>
6+
<true/>
7+
<key>com.apple.security.device.audio-input</key>
8+
<false/>
9+
<key>com.apple.security.personal-information.addressbook</key>
10+
<false/>
11+
</dict>
12+
</plist>

src/LiveLingo.App/Controls/HotkeyRecorder.cs

Lines changed: 0 additions & 99 deletions
This file was deleted.

src/LiveLingo.App/Platform/macOS/AccessibilityPermission.cs

Lines changed: 0 additions & 19 deletions
This file was deleted.

src/LiveLingo.App/Platform/macOS/MacClipboardService.cs

Lines changed: 0 additions & 19 deletions
This file was deleted.

src/LiveLingo.App/Platform/macOS/MacHotkeyService.cs

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/LiveLingo.App/Platform/macOS/MacTextInjector.cs

Lines changed: 0 additions & 20 deletions
This file was deleted.

0 commit comments

Comments
 (0)