| CHANGELOG.md | ●●●●● patch | view | raw | blame | history | |
| TODO.md | ●●●●● patch | view | raw | blame | history | |
| VoiceSnapGo/app.go | ●●●●● patch | view | raw | blame | history | |
| VoiceSnapGo/build/config.yml | ●●●●● patch | view | raw | blame | history | |
| VoiceSnapGo/build/darwin/Info.plist | ●●●●● patch | view | raw | blame | history | |
| VoiceSnapGo/build/windows/wails.exe.manifest | ●●●●● patch | view | raw | blame | history | |
| VoiceSnapGo/frontend/package-lock.json | ●●●●● patch | view | raw | blame | history | |
| VoiceSnapGo/frontend/package.json | ●●●●● patch | view | raw | blame | history | |
| VoiceSnapGo/frontend/src/components/settings/AboutPage.svelte | ●●●●● patch | view | raw | blame | history | |
| VoiceSnapGo/internal/overlay/overlay_darwin.go | ●●●●● patch | view | raw | blame | history |
CHANGELOG.md
@@ -1,5 +1,17 @@ # Changelog ## v2.1.2 (2026-05-18) ### Bug 修复 - **全屏窗口下悬浮指示器不显示**:macOS 悬浮指示器从普通 `NSWindow` 调整为非激活 `NSPanel`,窗口层级提升到状态栏级别,并补充 `Transient` / `IgnoresCycle` / `FullScreenAuxiliary` / `CanJoinAllSpaces` 行为,确保任意 App 全屏 Space 下也能显示录音胶囊。 ### 构建 - build: `20260518.1623` --- ## v2.1.1 (2026-02-27) ### Bug 修复 TODO.md
@@ -21,6 +21,15 @@ ## Done - [2026-05-18] 修复全屏窗口下语音输入悬浮指示器不显示。 - 根因: macOS 全屏 Space 下普通 `NSWindow` + `NSFloatingWindowLevel` 不稳定,容易被全屏 App 压在下层。 - 修复: 悬浮指示器改为非激活 `NSPanel`,窗口层级提升到 `kCGStatusWindowLevelKey`,并补充 `Transient`、`IgnoresCycle`、`FullScreenAuxiliary`、`CanJoinAllSpaces` 行为。 - 版本: `2.1.2` - build: `20260518.1623` - 输出: `VoiceSnapGo/build/local/arm64/VoiceSnap.app` - 输出: `VoiceSnapGo/build/local/arm64/VoiceSnap-2.1.2-build20260518.1623-arm64-local.dmg` - 兼容输出: `VoiceSnapGo/build/local/arm64/VoiceSnap-2.1.2-arm64-local.dmg` - 已安装到 `/Applications/VoiceSnap.app`;签名验证为 `VoiceSnap Local Code Signing`。 - [2026-05-18] 将 macOS 后台活动/登录项纳入权限检查面板。 - 说明: 系统设置里的 “VoiceSnap Local” 是本地稳定签名证书的开发者名,下面挂着 VoiceSnap 的登录项/后台活动。 - 它不是右 Alt、录音、自动上屏的必需隐私权限,但会影响登录后是否自动在后台运行。 VoiceSnapGo/app.go
@@ -26,8 +26,8 @@ ) const ( appVersion = "2.1.1" appBuild = "20260518.1604" appVersion = "2.1.2" appBuild = "20260518.1623" appDisplayVersion = appVersion + " (build " + appBuild + ")" appName = "VoiceSnap" VoiceSnapGo/build/config.yml
@@ -7,7 +7,7 @@ description: "Offline voice to text tool" copyright: "(c) 2025, VoiceSnap" comments: "Press and hold hotkey to record, release to transcribe" version: "2.1.1" version: "2.1.2" dev_mode: root_path: . VoiceSnapGo/build/darwin/Info.plist
@@ -15,9 +15,9 @@ <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> <string>2.1.1</string> <string>2.1.2</string> <key>CFBundleVersion</key> <string>20260518.1604</string> <string>20260518.1623</string> <key>LSMinimumSystemVersion</key> <string>11.0</string> <key>NSMicrophoneUsageDescription</key> VoiceSnapGo/build/windows/wails.exe.manifest
@@ -3,7 +3,7 @@ <assemblyIdentity type="win32" name="VoiceSnap" version="2.1.1.0" version="2.1.2.0" processorArchitecture="*"/> <dependency> <dependentAssembly> VoiceSnapGo/frontend/package-lock.json
@@ -1,12 +1,12 @@ { "name": "voicesnap-frontend", "version": "2.1.1", "version": "2.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "voicesnap-frontend", "version": "2.1.1", "version": "2.1.2", "dependencies": { "@wailsio/runtime": "latest" }, VoiceSnapGo/frontend/package.json
@@ -1,7 +1,7 @@ { "name": "voicesnap-frontend", "private": true, "version": "2.1.1", "version": "2.1.2", "type": "module", "scripts": { "dev": "vite dev", VoiceSnapGo/frontend/src/components/settings/AboutPage.svelte
@@ -2,7 +2,7 @@ import { Call } from '@wailsio/runtime' import { t } from '../../lib/i18n' let version = $state('2.1.1') let version = $state('2.1.2') let updateStatus = $state('') let updateColor = $state('') let checking = $state(false) VoiceSnapGo/internal/overlay/overlay_darwin.go
@@ -4,8 +4,9 @@ /* #cgo CFLAGS: -x objective-c #cgo LDFLAGS: -framework Cocoa #cgo LDFLAGS: -framework Cocoa -framework ApplicationServices #import <Cocoa/Cocoa.h> #import <ApplicationServices/ApplicationServices.h> #include <dispatch/dispatch.h> #include <string.h> @@ -118,8 +119,8 @@ @end // ---- Custom NSWindow for drag tracking ---- @interface VoiceSnapOverlayWindow : NSWindow { // ---- Custom NSPanel for drag tracking ---- @interface VoiceSnapOverlayWindow : NSPanel { NSPoint _dragStartOrigin; } @end @@ -148,6 +149,7 @@ } - (BOOL)canBecomeKeyWindow { return NO; } - (BOOL)canBecomeMainWindow { return NO; } @end @@ -155,6 +157,21 @@ static NSWindow* g_window = nil; static VoiceSnapOverlayView* g_view = nil; static NSTimer* g_timer = nil; static void applyOverlayWindowPolicy(NSWindow* window) { if (!window) return; [window setLevel:CGWindowLevelForKey(kCGStatusWindowLevelKey)]; [window setCollectionBehavior: NSWindowCollectionBehaviorCanJoinAllSpaces | NSWindowCollectionBehaviorStationary | NSWindowCollectionBehaviorFullScreenAuxiliary | NSWindowCollectionBehaviorTransient | NSWindowCollectionBehaviorIgnoresCycle]; [window setCanHide:NO]; if ([window isKindOfClass:[NSPanel class]]) { [(NSPanel*)window setHidesOnDeactivate:NO]; } } static void animateBars(void) { g_state.animTime += 0.033f; @@ -230,6 +247,7 @@ } if (g_state.fadeTarget > 0 && ![g_window isVisible]) { applyOverlayWindowPolicy(g_window); [g_window orderFrontRegardless]; } @@ -259,17 +277,13 @@ VoiceSnapOverlayWindow* window = [[VoiceSnapOverlayWindow alloc] initWithContentRect:NSMakeRect(0, 0, CAP_W, CAP_H) styleMask:NSWindowStyleMaskBorderless styleMask:NSWindowStyleMaskBorderless | NSWindowStyleMaskNonactivatingPanel backing:NSBackingStoreBuffered defer:NO]; [window setOpaque:NO]; [window setBackgroundColor:[NSColor clearColor]]; [window setLevel:NSFloatingWindowLevel]; [window setCollectionBehavior: NSWindowCollectionBehaviorCanJoinAllSpaces | NSWindowCollectionBehaviorStationary | NSWindowCollectionBehaviorFullScreenAuxiliary]; applyOverlayWindowPolicy(window); [window setIgnoresMouseEvents:NO]; [window setMovableByWindowBackground:YES]; [window setHasShadow:NO]; @@ -307,11 +321,19 @@ g_state.hasPosition = 1; } static void doBringOverlayForward(void* ctx) { (void)ctx; if (!g_window) return; applyOverlayWindowPolicy(g_window); [g_window orderFrontRegardless]; } static void overlayShow(void) { g_state.fadeTarget = 1.0f; if (!g_state.hasPosition) { dispatch_async_f(dispatch_get_main_queue(), NULL, doAutoPosition); } dispatch_async_f(dispatch_get_main_queue(), NULL, doBringOverlayForward); } static void overlayHide(void) {