Fix mobile marketing screenshots
This commit is contained in:
1 parent
f9e063ee11
commit
997fd79815
2 files changed
+136
-28
No files matched your search
@@ -65,10 +65,12 @@ run_capture() {
|
||||
|
||||
xcrun simctl boot "$device_id" 2>/dev/null || true
|
||||
xcrun simctl bootstatus "$device_id" -b
|
||||
if [[ "$name" == iPad* ]]; then
|
||||
set_simulator_orientation "$name" "Landscape Right"
|
||||
else
|
||||
set_simulator_orientation "$name" "Portrait"
|
||||
if pgrep -x Simulator >/dev/null; then
|
||||
if [[ "$name" == iPad* ]]; then
|
||||
set_simulator_orientation "$name" "Landscape Right"
|
||||
else
|
||||
set_simulator_orientation "$name" "Portrait"
|
||||
fi
|
||||
fi
|
||||
xcrun simctl status_bar "$device_id" override \
|
||||
--time '9:41' --batteryState charged --batteryLevel 100 --wifiBars 3 --cellularBars 4
|
||||
@@ -94,7 +96,18 @@ run_capture() {
|
||||
mkdir -p "${destination:h}"
|
||||
xcrun simctl io "$device_id" screenshot --type=png "$destination" >/dev/null
|
||||
if [[ "$device" == "ipad" ]]; then
|
||||
sips -r 90 "$destination" >/dev/null
|
||||
local width height
|
||||
width="$(sips -g pixelWidth "$destination" | awk '/pixelWidth/ { print $2 }')"
|
||||
height="$(sips -g pixelHeight "$destination" | awk '/pixelHeight/ { print $2 }')"
|
||||
if [[ "$width" == "2064" && "$height" == "2752" ]]; then
|
||||
sips -r 90 "$destination" >/dev/null
|
||||
elif [[ "$width" != "2752" || "$height" != "2064" ]]; then
|
||||
print -u2 "Unexpected iPad screenshot dimensions: ${width}x${height}"
|
||||
kill "$test_pid" 2>/dev/null || true
|
||||
wait "$test_pid" 2>/dev/null || true
|
||||
xcrun simctl status_bar "$device_id" clear
|
||||
exit 70
|
||||
fi
|
||||
fi
|
||||
touch "$app_container/Documents/marketing-capture-control/ack-$token"
|
||||
last_token="$token"
|
||||
|
||||
@@ -25,13 +25,7 @@ struct MobileMarketingScreenshotTests {
|
||||
let app = try makeApp(language: language)
|
||||
if includes("vault") {
|
||||
try await capture("vault", language: language) {
|
||||
NavigationStack {
|
||||
MobileVaultView(
|
||||
app: app, editingHost: .constant(nil), activateHost: { _ in },
|
||||
open: { _, _ in }
|
||||
)
|
||||
.toolbar { marketingSidebarButton(language: language) }
|
||||
}
|
||||
MarketingVaultScene(app: app)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +68,13 @@ struct MobileMarketingScreenshotTests {
|
||||
if includes("metrics") {
|
||||
let metrics = makeMetrics(language: language)
|
||||
try await capture("metrics", language: language) {
|
||||
NavigationStack { MarketingMetricsScene(servers: metrics, language: language) }
|
||||
if UIDevice.current.userInterfaceIdiom == .pad {
|
||||
NavigationStack { MarketingMetricsScene(servers: metrics, language: language) }
|
||||
} else {
|
||||
MarketingPhoneTabShell(selected: .vault) {
|
||||
MarketingPhoneMetricsNavigation(app: app, servers: metrics, language: language)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,9 +83,17 @@ struct MobileMarketingScreenshotTests {
|
||||
let conversation = ConversationModel.demo(language: try #require(AppLanguage(rawValue: language)))
|
||||
assistant.library.insertAndSelect(conversation)
|
||||
try await capture("assistant", language: language) {
|
||||
NavigationStack {
|
||||
MobileAssistantView(app: app, model: assistant, libraryRoute: .constant(nil))
|
||||
.toolbar { marketingBackButton(language: language) }
|
||||
if UIDevice.current.userInterfaceIdiom == .pad {
|
||||
NavigationStack {
|
||||
MobileAssistantView(app: app, model: assistant, libraryRoute: .constant(nil))
|
||||
.toolbar { marketingBackButton(language: language) }
|
||||
}
|
||||
} else {
|
||||
MarketingPhoneTabShell(selected: .assistant) {
|
||||
NavigationStack {
|
||||
MobileAssistantView(app: app, model: assistant, libraryRoute: .constant(nil))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,8 +172,12 @@ struct MobileMarketingScreenshotTests {
|
||||
_ name: String, language: String, @ViewBuilder view: () -> V
|
||||
) async throws {
|
||||
let scene = try #require(UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }.first)
|
||||
if UIDevice.current.userInterfaceIdiom == .pad, scene.interfaceOrientation.isPortrait {
|
||||
scene.requestGeometryUpdate(.iOS(interfaceOrientations: .landscapeLeft)) { error in
|
||||
let isPad = UIDevice.current.userInterfaceIdiom == .pad
|
||||
let targetOrientation: UIInterfaceOrientationMask = isPad ? .landscapeLeft : .portrait
|
||||
let hasTargetOrientation =
|
||||
isPad ? scene.interfaceOrientation == .landscapeLeft : scene.interfaceOrientation == .portrait
|
||||
if !hasTargetOrientation {
|
||||
scene.requestGeometryUpdate(.iOS(interfaceOrientations: targetOrientation)) { error in
|
||||
print("Unable to rotate the marketing scene: \(error.localizedDescription)")
|
||||
}
|
||||
try await Task.sleep(for: .milliseconds(800))
|
||||
@@ -247,14 +259,6 @@ struct MobileMarketingScreenshotTests {
|
||||
}
|
||||
}
|
||||
|
||||
@ToolbarContentBuilder
|
||||
private func marketingSidebarButton(language: String) -> some ToolbarContent {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
Button(text(language, "Sidebar", "侧边栏", "側邊欄"), systemImage: "sidebar.left") {}
|
||||
.labelStyle(.iconOnly)
|
||||
}
|
||||
}
|
||||
|
||||
private func text(_ language: String, _ english: String, _ simplified: String, _ traditional: String) -> String {
|
||||
switch language {
|
||||
case "zh-Hans": simplified
|
||||
@@ -268,6 +272,94 @@ private enum MarketingCaptureError: Error {
|
||||
case systemCaptureTimedOut(String)
|
||||
}
|
||||
|
||||
private struct MarketingVaultScene: View {
|
||||
let app: MobileAppModel
|
||||
private let features = MobileFeatureRegistry.standard()
|
||||
@State private var selectedDestination: MobileDestination? = .vault
|
||||
|
||||
var body: some View {
|
||||
if UIDevice.current.userInterfaceIdiom == .pad {
|
||||
NavigationSplitView(columnVisibility: .constant(.all)) {
|
||||
List(selection: $selectedDestination) {
|
||||
ForEach(features.registrations(on: .padSidebar)) { feature in
|
||||
NavigationLink(value: feature.id) {
|
||||
Label(feature.title, systemImage: feature.symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationSplitViewColumnWidth(min: 240, ideal: 280, max: 320)
|
||||
} detail: {
|
||||
NavigationStack {
|
||||
MobileVaultView(
|
||||
app: app, editingHost: .constant(nil), activateHost: { _ in },
|
||||
open: { _, _ in }, showsMetrics: false
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MarketingPhoneTabShell(selected: .vault) {
|
||||
NavigationStack {
|
||||
MobileVaultView(
|
||||
app: app, editingHost: .constant(nil), activateHost: { _ in },
|
||||
open: { _, _ in }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct MarketingPhoneTabShell<Content: View>: View {
|
||||
let selected: MobileDestination
|
||||
let content: Content
|
||||
private let features = MobileFeatureRegistry.standard()
|
||||
|
||||
init(selected: MobileDestination, @ViewBuilder content: () -> Content) {
|
||||
self.selected = selected
|
||||
self.content = content()
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
TabView(selection: .constant(selected)) {
|
||||
ForEach(features.registrations(on: .phoneTab)) { feature in
|
||||
Group {
|
||||
if feature.id == selected {
|
||||
content
|
||||
} else {
|
||||
NavigationStack { Color.clear }
|
||||
}
|
||||
}
|
||||
.tabItem { Label(feature.title, systemImage: feature.symbol) }
|
||||
.tag(feature.id)
|
||||
}
|
||||
}
|
||||
.toolbar(.visible, for: .tabBar)
|
||||
}
|
||||
}
|
||||
|
||||
private struct MarketingPhoneMetricsNavigation: View {
|
||||
private enum Route: Hashable {
|
||||
case metrics
|
||||
}
|
||||
|
||||
let app: MobileAppModel
|
||||
let servers: [ServerMetric]
|
||||
let language: String
|
||||
@State private var path: [Route] = [.metrics]
|
||||
|
||||
var body: some View {
|
||||
NavigationStack(path: $path) {
|
||||
MobileVaultView(
|
||||
app: app, editingHost: .constant(nil), activateHost: { _ in },
|
||||
open: { _, _ in }
|
||||
)
|
||||
.navigationDestination(for: Route.self) { _ in
|
||||
MarketingMetricsScene(servers: servers, language: language, showsSidebarButton: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct MarketingTerminalScene: View {
|
||||
@ObservedObject var terminal: TerminalViewState
|
||||
let language: String
|
||||
@@ -301,6 +393,7 @@ private struct MarketingTerminalScene: View {
|
||||
private struct MarketingMetricsScene: View {
|
||||
let servers: [ServerMetric]
|
||||
let language: String
|
||||
var showsSidebarButton = true
|
||||
|
||||
var body: some View {
|
||||
MobileCardPage {
|
||||
@@ -319,8 +412,10 @@ private struct MarketingMetricsScene: View {
|
||||
}
|
||||
.navigationTitle("Metrics")
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
Button("Sidebar", systemImage: "sidebar.left") {}.labelStyle(.iconOnly)
|
||||
if showsSidebarButton {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
Button("Sidebar", systemImage: "sidebar.left") {}.labelStyle(.iconOnly)
|
||||
}
|
||||
}
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
Button("Add Server", systemImage: "plus") {}.labelStyle(.iconOnly)
|
||||
|
||||
Reference in new issue
Block a user