From c249d6796b368458fa80f763b692f40eb015fff5 Mon Sep 17 00:00:00 2001 From: Kaede Akino Date: Sat, 19 Sep 2026 00:31:35 +0800 Subject: [PATCH] New screenshots --- Memory/MARKETING.md | 94 ++++++++++++-- Scripts/run-mac-marketing-screenshots.sh | 116 ++++++++++++------ Scripts/run-mobile-marketing-screenshots.sh | 63 +++++----- TFITests/MobileMarketingScreenshotTests.swift | 7 +- TFMTests/MacMarketingScreenshotTests.swift | 69 ++++------- Termind.xcodeproj/project.pbxproj | 8 +- 6 files changed, 227 insertions(+), 130 deletions(-) diff --git a/Memory/MARKETING.md b/Memory/MARKETING.md index e6b51f69..35ead629 100644 --- a/Memory/MARKETING.md +++ b/Memory/MARKETING.md @@ -46,7 +46,7 @@ include `workspace`, `ssh`, `sftp`, `metrics`, `assistant`, `vault`, and Raw captures have no `-framed` suffix. Framing scripts may replace a framed file, but must never replace its raw input. The Mac capture script backs up previous raw -Workspace files under `.build/screenshot-backups//` before replacement. +files by feature under `.build/screenshot-backups//` before replacement. ## iPhone and iPad source captures @@ -73,6 +73,12 @@ runtime cannot silently change the marketing UI or select another same-name device. Set `TERMIND_MARKETING_RUNTIME` to a full CoreSimulator runtime identifier only when intentionally updating the runtime used for a capture set. +Each locale launches a separate test process with matching Apple language, region, +and locale arguments. `TERMIND_MARKETING_LOCALE` selects that process's fixture +language, so Foundation-localized strings (including Vault's last-connection label) +match SwiftUI labels. The iPhone fixture requests portrait orientation through its +window scene; the runner does not depend on Simulator menu automation. + For a targeted recapture, set both filters. This example refreshes only the three localized iPad Assistant sources: @@ -122,12 +128,14 @@ Whenever SFTP, Metrics, Assistant navigation, or system chrome changes, recaptur the affected device and every locale. A marketing fixture may be updated to expose the current UI, but it must not add production behavior. -## Mac Workspace source captures +## Mac source captures -The source is `TFMTests/MacMarketingScreenshotTests.swift`. It constructs the real -`RootView` and `ScreenshotDemoConfiguration` inside a native `NSWindow`. Before it +The source is `TFMTests/MacMarketingScreenshotTests.swift`. It captures the existing +production WindowGroup launched with `ScreenshotDemoConfiguration`; it never +mounts a second RootView or duplicates a terminal/transcript surface. Before it publishes the ready marker, it requires both `NSApp.isActive` and -`window.isKeyWindow`. +`window.isKeyWindow`, allows the focused appearance to render, and requires native +2× backing scale. Focus is checked again when the capture is acknowledged. Generate all three localized Workspace sources: @@ -135,6 +143,20 @@ Generate all three localized Workspace sources: Scripts/run-mac-marketing-screenshots.sh ``` +The default remains Workspace. Use `TERMIND_MAC_MARKETING_SCENES` to select a +comma-separated subset of `hosts`, `workspace`, `agent`, `command`, and `metrics`. +Use `TERMIND_MAC_MARKETING_LOCALES` for `en`, `zh-Hans`, and `zh-Hant` (all three by +default). The filename mappings are Vault `mac`, Workspace `mac`, Assistant `mac`, +Command Generator `mac`, and Metrics `mac-overview`, respectively. Metrics detail +remains available as a development demo, but has no marketing source or export. + +```sh +TERMIND_MAC_MARKETING_SCENES=hosts,metrics,command \ + Scripts/run-mac-marketing-screenshots.sh +TERMIND_MAC_MARKETING_SCENES=agent TERMIND_MAC_MARKETING_LOCALES=zh-Hant \ + Scripts/run-mac-marketing-screenshots.sh +``` + The runner: 1. builds the TFM test host from the pinned package resolution; @@ -142,7 +164,8 @@ The runner: 3. waits for an active/key window marker; 4. captures the system window by window number; 5. removes only the two-pixel transparent capture edge when present; -6. verifies a final `2360x1480` sRGB source. +6. verifies the test's focus acknowledgement and final dimensions before replacing + the source: `2360x1480`, or `2044x1280` for Command Generator. The current Workspace contains focused English terminal panes and the current SFTP browser. SFTP filenames, types, dates, and app chrome localize; terminal transcripts @@ -330,6 +353,9 @@ Use Figwright `save_screenshots` with `format: "JPG"` and `scale: 1` for final exports. `get_screenshot` is for visual review and caps its output size; it is not the delivery export path. Keep temporary node-ID filenames outside `Marketing/AppStore` and copy the verified full-size results to the established locale/platform names. +If a Figma JPG export has no embedded color profile, add the sRGB ICC profile as +JPEG metadata without re-encoding its image data. Verify that decoded RGB pixels +are identical to the original export before copying it into the delivery tree. ## Verification checklist @@ -356,8 +382,8 @@ Also confirm manually: - iOS status/navigation chrome is real and complete; - SFTP reflects the current production UI on every platform; - iPad Assistant is the latest capture; -- Mac traffic lights are colored, one pane has the active blue outline, and the - MacBook render contains no Dock or copyrighted wallpaper; +- Mac traffic lights are colored, Workspace's active pane has the blue outline, + and the MacBook render contains no Dock or copyrighted wallpaper; - Chinese glyphs use the intended PingFang family; - Traditional Chinese uses `伺服器` and other Taiwan-standard terms; - the store export directory contains exactly 54 final JPG files. @@ -381,3 +407,55 @@ copy, fonts, layout, geometry and FIT mode. SHA-256 comparison against the compl iPhone baseline found exactly 27 changed iPad images and 108 unchanged marketing files, including iPhone, Mac, SSH/SFTP and the first boards. All 54 App Store JPGs remain opaque three-channel sRGB. + +The 2026-09-19 Port Forwarding navigation refresh generated 16 raw captures: +Mac Vault, Metrics overview and Command Generator in all three languages, +Traditional Chinese Mac Assistant, and iPhone/iPad Vault in all three languages. +The two English/Simplified Chinese Mac Metrics detail sources were removed; +the product detail view and development demo remain available. Existing Workspace +sources and English/Simplified Chinese Mac Assistant sources stayed unchanged. +All 15 retained Mac source images and boards 02–06 were checked for colored +traffic lights. The ten new Mac captures also passed active/key checks before +capture and after acknowledgement. Traditional Chinese Assistant now contains a +Traditional Chinese interface and conversation, with English terminal output. + +Only the six mobile Vault MockUPhone frames were regenerated. The Figwright +development plugin was reconnected to the verified `Termind` file +(`udtCX9xVEeoHsTGTwIBgBw`). Mac boards 03, 05 and 06 in all languages, Traditional +Chinese Mac board 04, and mobile board 06 in all languages were replaced and +exported as JPG at 1×. All 16 Figma image fills match their local PNG source bytes; +readback confirmed unchanged text, fonts, geometry, shadows and FIT mode. The +final JPGs have embedded sRGB profiles, opaque RGB pixels and the original +platform dimensions. App Store delivery remains 54 JPGs, six per platform/locale. + +The pre-capture backup and SHA-256 manifests are under +`.build/marketing-forwarding-refresh/`. The exact-path audit found 35 modified, +three added, two deleted and 94 unchanged images: the final tree has 45 raw +captures, 33 device frames and 54 App Store exports. English, Simplified Chinese +and Traditional Chinese homepages were checked with the rebuilt Vault frames; +`/zh/` redirects to `/zh-hans/`. The production website build, Chinese localization +check, full Swift format lint and screenshot script syntax checks passed. + +Swift verification for this refresh is not fully green. The opt-in capture runs, +`ScreenshotDemoTests` and `AppLanguageTests` passed. The full TFI run completed +307 app tests with seven issues and passed all 316 shared-framework tests. The +full TFM run reported UI/runtime issues and was interrupted after its upload +cancellation test remained blocked in the fixture's socket read. Serial reruns +(`-parallel-testing-enabled NO`) passed the previously failing cancellation, +input, mobile editor, mobile forwarding and saved-name checks; the isolated +`MCPUploadTests` (23 tests) and `MobileUploadBatchTests` (nine tests) also passed. +The following failures persisted in unchanged tests: + +- `PortForwardingRenderingTests.saveClosesTheEditorOnlyAfterPersistenceSucceeds`: + the native Save accessibility element is missing in both parameter cases. +- `PortForwardingRenderingTests.closingJourneyRetainsItsExitViewButDisablesAuthentication`: + a secure text field remains when Reduce Motion is off. +- `MetricsDetailToolbarTests.legacyCompactSearchOpensTheNativeFieldAndKeepsItsQueryWhenWidened`: + the native search field is missing. +- `SpeechWaveformViewTests.waveformRespondsToLevelsAndReduceMotionMakesItStable`: + the Reduce Motion bitmap equality check fails on Mac, including an isolated rerun. +- `MobileProviderDefaultsTests.modelNamesAreMaterializedAfterMergingTheProviderDraft`: + the expected validation error is not thrown. + +Logs and `.xcresult` bundles remain in `.build/marketing-forwarding-refresh/`. +No production behavior or unrelated tests were changed to address these failures. diff --git a/Scripts/run-mac-marketing-screenshots.sh b/Scripts/run-mac-marketing-screenshots.sh index 7415063b..59087e29 100755 --- a/Scripts/run-mac-marketing-screenshots.sh +++ b/Scripts/run-mac-marketing-screenshots.sh @@ -8,8 +8,33 @@ repository_directory="${script_directory:h}" derived_data="$repository_directory/.build/mac-marketing-tests" products="$derived_data/Build/Products" backup_directory="$repository_directory/.build/screenshot-backups/$(date +%Y%m%d-%H%M%S)" -output_directory="$repository_directory/Marketing/Screenshots/Captures/workspace" +output_directory="$repository_directory/Marketing/Screenshots/Captures" +marketing_scenes="${TERMIND_MAC_MARKETING_SCENES:-workspace}" +marketing_locales="${TERMIND_MAC_MARKETING_LOCALES:-en,zh-Hans,zh-Hant}" +local_test_pid="" +cleanup() { + if [[ -n "$local_test_pid" ]]; then + kill "$local_test_pid" 2>/dev/null || true + wait "$local_test_pid" 2>/dev/null || true + fi +} +trap cleanup EXIT INT TERM + +for scene in ${(s:,:)marketing_scenes}; do + case "$scene" in + hosts|workspace|agent|command|metrics) ;; + *) print -u2 "Unsupported marketing scene: $scene"; exit 64 ;; + esac +done +for language in ${(s:,:)marketing_locales}; do + case "$language" in + en|zh-Hans|zh-Hant) ;; + *) print -u2 "Unsupported marketing locale: $language"; exit 64 ;; + esac +done + +mkdir -p "$derived_data" xcodebuild \ -project "$repository_directory/Termind.xcodeproj" \ -scheme TFM \ @@ -26,21 +51,34 @@ if [[ -z "$source_xctestrun" ]]; then fi capture() { - local language="$1" - local region="$2" - local asset_locale="$3" - local apple_locale="$4" - local xctestrun="$products/Marketing-TFM-$asset_locale.xctestrun" - local test_log="$derived_data/workspace-$asset_locale-capture.log" - local destination="$output_directory/mac-$asset_locale.png" + local scene="$1" + local language="$2" + local region asset_locale apple_locale feature prefix + local width=2360 height=1480 + case "$language" in + en) region=US; asset_locale=en; apple_locale=en_US ;; + zh-Hans) region=CN; asset_locale=zh-hans; apple_locale=zh_CN ;; + zh-Hant) region=TW; asset_locale=zh-hant; apple_locale=zh_TW ;; + esac + prefix=mac + case "$scene" in + hosts) feature=vault ;; + workspace) feature=workspace ;; + agent) feature=assistant ;; + command) feature=command-generator; width=2044; height=1280 ;; + metrics) feature=metrics; prefix=mac-overview ;; + esac + local xctestrun="$products/Marketing-TFM-$scene-$asset_locale.xctestrun" + local test_log="$derived_data/$scene-$asset_locale-capture.log" + local destination="$output_directory/$feature/$prefix-$asset_locale.png" + local captured="$derived_data/$scene-$asset_locale.png" cp "$source_xctestrun" "$xctestrun" /usr/libexec/PlistBuddy \ -c 'Add :TFMTests:EnvironmentVariables:TERMIND_MAC_MARKETING_SCREENSHOTS string 1' \ - -c "Add :TFMTests:EnvironmentVariables:TERMIND_MAC_MARKETING_LOCALE string $language" \ -c "Set :TFMTests:TestLanguage $language" \ -c "Set :TFMTests:TestRegion $region" \ - -c "Add :TFMTests:CommandLineArguments:0 string --termind-demo=workspace:$language" \ + -c "Add :TFMTests:CommandLineArguments:0 string --termind-demo=$scene:$language" \ -c 'Add :TFMTests:CommandLineArguments:1 string -AppleLanguages' \ -c "Add :TFMTests:CommandLineArguments:2 string ($language)" \ -c 'Add :TFMTests:CommandLineArguments:3 string -AppleLocale' \ @@ -53,10 +91,10 @@ capture() { -destination 'platform=macOS,arch=arm64' \ -only-testing:TFMTests/MacMarketingScreenshotTests \ test-without-building > "$test_log" 2>&1 & - local test_pid=$! + local_test_pid=$! local ready_path="" - for _ in {1..300}; do + for _ in {1..600}; do ready_path="$( rg -o 'TERMIND_MAC_MARKETING_READY .*' "$test_log" \ | tail -n 1 \ @@ -64,47 +102,53 @@ capture() { || true )" [[ -n "$ready_path" && -f "$ready_path" ]] && break - if ! kill -0 "$test_pid" 2>/dev/null; then + if ! kill -0 "$local_test_pid" 2>/dev/null; then tail -n 100 "$test_log" >&2 exit 70 fi sleep 0.1 done if [[ -z "$ready_path" || ! -f "$ready_path" ]]; then - kill "$test_pid" 2>/dev/null || true tail -n 100 "$test_log" >&2 exit 70 fi - local feature captured_language window_id token active key - IFS=$'\t' read -r feature captured_language window_id token active key < "$ready_path" - if [[ "$feature" != workspace || "$captured_language" != "$language" || "$active" != active || "$key" != key ]]; then + local captured_scene captured_language window_id token active key + IFS=$'\t' read -r captured_scene captured_language window_id token active key < "$ready_path" + if [[ "$captured_scene" != "$scene" || "$captured_language" != "$language" || "$active" != active || "$key" != key ]]; then print -u2 "Capture window was not ready and focused: $(<"$ready_path")" exit 70 fi - mkdir -p "$output_directory" "$backup_directory" - if [[ -f "$destination" ]]; then - cp "$destination" "$backup_directory/${destination:t}" - fi - screencapture -l "$window_id" -o "$destination" + screencapture -l "$window_id" -o "$captured" touch "${ready_path:h}/ack-$token" - wait "$test_pid" - - local dimensions="$(identify -format '%wx%h' "$destination")" - if [[ "$dimensions" == 2364x1484 ]]; then - sips -c 1480 2360 "$destination" >/dev/null - dimensions="$(identify -format '%wx%h' "$destination")" - fi - if [[ "$dimensions" != 2360x1480 ]]; then - print -u2 "Unexpected Workspace dimensions for $asset_locale: $dimensions" + if ! wait "$local_test_pid"; then + tail -n 100 "$test_log" >&2 exit 70 fi - print "Captured focused Workspace -> ${destination#$repository_directory/}" + local_test_pid="" + + local dimensions="$(identify -format '%wx%h' "$captured")" + if [[ "$dimensions" == "$((width + 4))x$((height + 4))" ]]; then + sips -c "$height" "$width" "$captured" >/dev/null + dimensions="$(identify -format '%wx%h' "$captured")" + fi + if [[ "$dimensions" != "${width}x${height}" ]]; then + print -u2 "Unexpected $scene dimensions for $asset_locale: $dimensions" + exit 70 + fi + mkdir -p "${destination:h}" "$backup_directory/$feature" + if [[ -f "$destination" ]]; then + cp "$destination" "$backup_directory/$feature/${destination:t}" + fi + cp "$captured" "$destination" + print "Captured focused $scene -> ${destination#$repository_directory/}" } -capture en US en en_US -capture zh-Hans CN zh-hans zh_CN -capture zh-Hant TW zh-hant zh_TW +for scene in ${(s:,:)marketing_scenes}; do + for language in ${(s:,:)marketing_locales}; do + capture "$scene" "$language" + done +done -print "Previous raw Workspace captures backed up in ${backup_directory#$repository_directory/}" +print "Previous captures backed up in ${backup_directory#$repository_directory/}" diff --git a/Scripts/run-mobile-marketing-screenshots.sh b/Scripts/run-mobile-marketing-screenshots.sh index 8cf0f14f..4fa08f61 100755 --- a/Scripts/run-mobile-marketing-screenshots.sh +++ b/Scripts/run-mobile-marketing-screenshots.sh @@ -14,13 +14,13 @@ marketing_runtime="${TERMIND_MARKETING_RUNTIME:-com.apple.CoreSimulator.SimRunti expected_capture_count() { if [[ -z "$marketing_scenes" ]]; then - print 15 + print 5 return fi local -a scenes scenes=("${(@s:,:)marketing_scenes}") local scene_count="${#scenes}" - print "$((scene_count * 3))" + print "$scene_count" } find_device() { @@ -31,33 +31,9 @@ find_device() { | head -n 1 } -set_simulator_orientation() { - local name="$1" - local orientation="$2" - osascript - "$name" "$orientation" <<'APPLESCRIPT' -on run arguments - set deviceName to item 1 of arguments - set targetOrientation to item 2 of arguments - tell application "Simulator" to activate - tell application "System Events" - tell process "Simulator" - repeat with candidate in menu items of menu 1 of menu bar item "Window" of menu bar 1 - if name of candidate starts with deviceName then - click candidate - exit repeat - end if - end repeat - delay 0.4 - click menu item targetOrientation of menu 1 of menu item "Orientation" of menu 1 of menu bar item "Device" of menu bar 1 - end tell - end tell -end run -APPLESCRIPT - sleep 1 -} - run_capture() { local name="$1" + local language="$2" local device_id device_id="$(find_device "$name")" if [[ -z "$device_id" ]]; then @@ -69,14 +45,29 @@ run_capture() { xcrun simctl bootstatus "$device_id" -b if [[ "$name" == iPad* ]]; then xcrun devicectl device orientation set --device "$device_id" landscapeLeft >/dev/null - elif pgrep -x Simulator >/dev/null; then - set_simulator_orientation "$name" "Portrait" fi xcrun simctl status_bar "$device_id" override \ --time '9:41' --batteryState charged --batteryLevel 100 --wifiBars 3 --cellularBars 4 - local test_log="$derived_data/${device_id}-capture.log" + local region apple_locale + case "$language" in + en) region=US; apple_locale=en_US ;; + zh-Hans) region=CN; apple_locale=zh_CN ;; + zh-Hant) region=TW; apple_locale=zh_TW ;; + esac + local localized_xctestrun="$derived_data/Build/Products/Marketing-TFI-$language.xctestrun" + cp "$marketing_xctestrun" "$localized_xctestrun" + /usr/libexec/PlistBuddy \ + -c "Add :TFITests:EnvironmentVariables:TERMIND_MARKETING_LOCALE string $language" \ + -c "Set :TFITests:TestLanguage $language" \ + -c "Set :TFITests:TestRegion $region" \ + -c 'Add :TFITests:CommandLineArguments:0 string -AppleLanguages' \ + -c "Add :TFITests:CommandLineArguments:1 string ($language)" \ + -c 'Add :TFITests:CommandLineArguments:2 string -AppleLocale' \ + -c "Add :TFITests:CommandLineArguments:3 string $apple_locale" \ + "$localized_xctestrun" + local test_log="$derived_data/${device_id}-$language-capture.log" xcodebuild \ - -xctestrun "$marketing_xctestrun" \ + -xctestrun "$localized_xctestrun" \ -destination "id=$device_id" \ -only-testing:TFITests/MobileMarketingScreenshotTests \ test-without-building > "$test_log" 2>&1 & @@ -129,7 +120,7 @@ run_capture() { local expected expected="$(expected_capture_count)" if [[ "$captures" -ne "$expected" ]]; then - print -u2 "Expected $expected captures for $name, received $captures. See $test_log" + print -u2 "Expected $expected captures for $name ($language), received $captures. See $test_log" exit 70 fi } @@ -168,10 +159,14 @@ if [[ -n "$marketing_scenes" ]]; then fi if [[ ",$marketing_devices," == *,iphone,* ]]; then - run_capture "iPhone 17 Pro Max" + for language in en zh-Hans zh-Hant; do + run_capture "iPhone 17 Pro Max" "$language" + done fi if [[ ",$marketing_devices," == *,ipad,* ]]; then - run_capture "iPad Pro 13-inch (M5)" + for language in en zh-Hans zh-Hant; do + run_capture "iPad Pro 13-inch (M5)" "$language" + done fi print "Marketing screenshots written to $output_directory" diff --git a/TFITests/MobileMarketingScreenshotTests.swift b/TFITests/MobileMarketingScreenshotTests.swift index 1da6d8d3..fa99f3f1 100644 --- a/TFITests/MobileMarketingScreenshotTests.swift +++ b/TFITests/MobileMarketingScreenshotTests.swift @@ -12,7 +12,12 @@ import UIKit /// Opt-in marketing captures. Fixtures are entirely in memory and never open a network connection. @Suite(.serialized) @MainActor struct MobileMarketingScreenshotTests { - private let languages = ["en", "zh-Hans", "zh-Hant"] + private var languages: [String] { + if let language = ProcessInfo.processInfo.environment["TERMIND_MARKETING_LOCALE"] { + return [language] + } + return ["en", "zh-Hans", "zh-Hant"] + } @Test func renderMarketingScenes() async throws { guard ProcessInfo.processInfo.environment["TERMIND_MARKETING_SCREENSHOTS"] == "1" else { return } diff --git a/TFMTests/MacMarketingScreenshotTests.swift b/TFMTests/MacMarketingScreenshotTests.swift index 8148853a..4e2fa72c 100644 --- a/TFMTests/MacMarketingScreenshotTests.swift +++ b/TFMTests/MacMarketingScreenshotTests.swift @@ -1,8 +1,4 @@ import AppKit -import SwiftData -import SwiftUI -import TermindApplication -import TermindPersistence import Testing @testable import Termind @@ -12,57 +8,25 @@ import Testing @MainActor struct MacMarketingScreenshotTests { @Test - func captureWorkspaceInSystemWindow() async throws { + func captureDemoInFocusedSystemWindow() async throws { let environment = ProcessInfo.processInfo.environment guard environment["TERMIND_MAC_MARKETING_SCREENSHOTS"] == "1" else { return } - let argument = environment["TERMIND_MAC_MARKETING_LOCALE"] ?? "en" - let language: AppLanguage - switch argument { - case "zh-Hans": language = .simplifiedChinese - case "zh-Hant": language = .traditionalChinese - default: language = .english + let configuration = try #require(ScreenshotDemoConfiguration.active) + // Capture the production WindowGroup. A second RootView would mount + // persistent terminal and transcript surfaces in two hierarchies. + for _ in 0..<100 { + if NSApp.windows.contains(where: { $0.isVisible && $0.canBecomeKey }) { break } + try await Task.sleep(for: .milliseconds(50)) } - - let configuration = ScreenshotDemoConfiguration(scene: .workspace, language: language) - let hosts = HostLibraryModel.demo(language: language) - let app = AppModel( - hosts: hosts, - ai: .demo(), - proAccess: .unrestrictedForTesting(), - onboarding: OnboardingController(automaticPresentationEnabled: false), - serverMetrics: configuration.makeMetricsModel(hosts: hosts) - ) - let container = try TermindPersistence.makeContainer(inMemory: true) - let root = RootView(window: configuration.makeWindow(hosts: hosts)) - .environment(app) - .environment(\.locale, language.locale) - .modelContainer(container) - let controller = NSHostingController(rootView: root) - let window = NSWindow( - contentRect: NSRect(origin: .zero, size: configuration.windowSize), - styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], - backing: .buffered, - defer: false - ) - window.isReleasedWhenClosed = false - window.isRestorable = false + let window = try #require(NSApp.windows.first(where: { $0.isVisible && $0.canBecomeKey })) window.contentMinSize = .zero - window.titlebarAppearsTransparent = true - window.titlebarSeparatorStyle = .none window.appearance = NSAppearance(named: .aqua) - window.contentViewController = controller window.setFrame(NSRect(origin: .zero, size: configuration.windowSize), display: true) window.center() - defer { - window.orderOut(nil) - window.contentViewController = nil - app.shutdownForTermination() - } - - controller.view.layoutSubtreeIfNeeded() + window.contentView?.layoutSubtreeIfNeeded() try await Task.sleep(for: .seconds(1)) - controller.view.layoutSubtreeIfNeeded() + window.contentView?.layoutSubtreeIfNeeded() for _ in 0..<100 { NSRunningApplication.current.activate(options: [.activateAllWindows]) @@ -77,12 +41,22 @@ import Testing Issue.record("Marketing window could not become the focused key window") return } + if configuration.scene == .hosts { + window.initialFirstResponder = nil + window.makeFirstResponder(nil) + } + // Allow the active appearance to render before the external capture. + try await Task.sleep(for: .milliseconds(300)) + try #require(NSApp.isActive && window.isKeyWindow) + try #require(window.backingScaleFactor == 2) let control = FileManager.default.temporaryDirectory.appending(path: "marketing-capture-control") try FileManager.default.createDirectory(at: control, withIntermediateDirectories: true) let token = UUID().uuidString let ready = control.appending(path: "ready") - try "workspace\t\(argument)\t\(window.windowNumber)\t\(token)\tactive\tkey\n".write( + let scene = configuration.scene.rawValue + let language = configuration.language.rawValue + try "\(scene)\t\(language)\t\(window.windowNumber)\t\(token)\tactive\tkey\n".write( to: ready, atomically: true, encoding: .utf8) FileHandle.standardOutput.write( Data("TERMIND_MAC_MARKETING_READY \(ready.path)\n".utf8) @@ -91,6 +65,7 @@ import Testing let acknowledgement = control.appending(path: "ack-\(token)") for _ in 0..<600 { if FileManager.default.fileExists(atPath: acknowledgement.path) { + #expect(NSApp.isActive && window.isKeyWindow, "Capture window lost focus before acknowledgement") try? FileManager.default.removeItem(at: acknowledgement) try? FileManager.default.removeItem(at: ready) return diff --git a/Termind.xcodeproj/project.pbxproj b/Termind.xcodeproj/project.pbxproj index 46d0b693..d99e7a04 100644 --- a/Termind.xcodeproj/project.pbxproj +++ b/Termind.xcodeproj/project.pbxproj @@ -1770,7 +1770,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = TFI/TFI.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 22; + CURRENT_PROJECT_VERSION = 23; GENERATE_INFOPLIST_FILE = YES; ICLOUD_CONTAINER_ENVIRONMENT = Development; INFOPLIST_FILE = TFI/Info.plist; @@ -2043,7 +2043,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = TFI/TFI.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 22; + CURRENT_PROJECT_VERSION = 23; GENERATE_INFOPLIST_FILE = YES; ICLOUD_CONTAINER_ENVIRONMENT = Production; INFOPLIST_FILE = TFI/Info.plist; @@ -2282,7 +2282,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 29; + CURRENT_PROJECT_VERSION = 30; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = ""; ENABLE_APP_SANDBOX = YES; @@ -2319,7 +2319,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 29; + CURRENT_PROJECT_VERSION = 30; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = ""; ENABLE_APP_SANDBOX = YES;