Add screenshot generator
This commit is contained in:
@@ -32,7 +32,12 @@ open class ApplicationDelegate: NSObject, NSApplicationDelegate, UNUserNotificat
|
||||
let launchedAsLogInItem =
|
||||
event?.eventID == kAEOpenApplication &&
|
||||
event?.paramDescriptor(forKeyword: keyAEPropData)?.enumCodeValue == keyAELaunchedAsLogInItem
|
||||
if SharedPreferences.inDebug || !launchedAsLogInItem || !SharedPreferences.showMenuBarExtra.getBlocking() || !SharedPreferences.menuBarExtraInBackground.getBlocking() {
|
||||
let shouldShowWindow = Variant.screenshotMode ||
|
||||
SharedPreferences.inDebug ||
|
||||
!launchedAsLogInItem ||
|
||||
!SharedPreferences.showMenuBarExtra.getBlocking() ||
|
||||
!SharedPreferences.menuBarExtraInBackground.getBlocking()
|
||||
if shouldShowWindow {
|
||||
NSApp.setActivationPolicy(.regular)
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
} else {
|
||||
|
||||
@@ -157,20 +157,6 @@ private class WindowState {
|
||||
}
|
||||
}
|
||||
|
||||
private struct WindowAccessor: NSViewRepresentable {
|
||||
let callback: (NSWindow?) -> Void
|
||||
|
||||
func makeNSView(context _: Context) -> NSView {
|
||||
let view = NSView()
|
||||
DispatchQueue.main.async {
|
||||
callback(view.window)
|
||||
}
|
||||
return view
|
||||
}
|
||||
|
||||
func updateNSView(_: NSView, context _: Context) {}
|
||||
}
|
||||
|
||||
private class WindowCloseDelegate: NSObject, NSWindowDelegate {
|
||||
var allowClose = false
|
||||
private let windowState: WindowState
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import AppKit
|
||||
import ApplicationLibrary
|
||||
import Foundation
|
||||
import Library
|
||||
import SwiftUI
|
||||
|
||||
@@ -6,17 +8,49 @@ import SwiftUI
|
||||
public struct MainView: View {
|
||||
@Environment(\.controlActiveState) private var controlActiveState
|
||||
@EnvironmentObject private var environments: ExtensionEnvironments
|
||||
@StateObject private var viewModel = MainViewModel()
|
||||
@StateObject private var viewModel: MainViewModel
|
||||
@State private var showCardManagement = false
|
||||
@State private var cardConfigurationVersion = 0
|
||||
@State private var settingsNavigationPath = NavigationPath()
|
||||
@State private var pendingSettingsPage: SettingsPage?
|
||||
@State private var didConfigureScreenshotWindow = false
|
||||
@State private var pendingScreenshotSelection: NavigationPage?
|
||||
|
||||
private let profileEditor: (Binding<String>, Bool) -> AnyView = { text, isEditable in
|
||||
AnyView(ProfileEditorWrapperView(text: text, isEditable: isEditable))
|
||||
}
|
||||
|
||||
public init() {}
|
||||
private let screenshotDefaultPixelHeight: CGFloat = 1000
|
||||
|
||||
public init() {
|
||||
let initialSelection: NavigationPage = .dashboard
|
||||
if Variant.screenshotMode,
|
||||
let pageValue = ProcessInfo.processInfo.environment["SCREENSHOT_PAGE"],
|
||||
let page = NavigationPage(snapshotValue: pageValue)
|
||||
{
|
||||
_pendingScreenshotSelection = State(initialValue: page)
|
||||
} else {
|
||||
_pendingScreenshotSelection = State(initialValue: nil)
|
||||
}
|
||||
_viewModel = StateObject(wrappedValue: MainViewModel(selection: initialSelection))
|
||||
}
|
||||
|
||||
private func screenshotTargetHeight(baseHeight _: CGFloat, window: NSWindow) -> CGFloat {
|
||||
let scale = max(window.backingScaleFactor, 1)
|
||||
if let pixelOverride = ProcessInfo.processInfo.environment["SCREENSHOT_WINDOW_PIXEL_HEIGHT"] {
|
||||
let trimmed = pixelOverride.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if let height = Double(trimmed), height > 0 {
|
||||
return CGFloat(height) / scale
|
||||
}
|
||||
}
|
||||
if let override = ProcessInfo.processInfo.environment["SCREENSHOT_WINDOW_HEIGHT"] {
|
||||
let trimmed = override.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if let height = Double(trimmed), height > 0 {
|
||||
return CGFloat(height)
|
||||
}
|
||||
}
|
||||
return screenshotDefaultPixelHeight / scale
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
NavigationSplitView {
|
||||
@@ -31,7 +65,27 @@ public struct MainView: View {
|
||||
.environment(\.settingsNavigationPath, $settingsNavigationPath)
|
||||
.navigationSplitViewColumnWidth(650)
|
||||
}
|
||||
.frame(minHeight: 500)
|
||||
.frame(minHeight: Variant.screenshotMode ? 0 : 500)
|
||||
.background(WindowAccessor { window in
|
||||
guard Variant.screenshotMode, !didConfigureScreenshotWindow, let window else { return }
|
||||
didConfigureScreenshotWindow = true
|
||||
DispatchQueue.main.async {
|
||||
window.hasShadow = true
|
||||
let baseSize = window.contentLayoutRect.size
|
||||
let targetHeight = screenshotTargetHeight(baseHeight: baseSize.height, window: window)
|
||||
let targetSize = NSSize(width: baseSize.width, height: targetHeight)
|
||||
guard targetSize.width > 0, targetSize.height > 0 else { return }
|
||||
window.contentMinSize = targetSize
|
||||
window.contentMaxSize = targetSize
|
||||
window.minSize = targetSize
|
||||
window.maxSize = targetSize
|
||||
window.setContentSize(targetSize)
|
||||
if let pending = pendingScreenshotSelection, pending != viewModel.selection {
|
||||
viewModel.selection = pending
|
||||
pendingScreenshotSelection = nil
|
||||
}
|
||||
}
|
||||
})
|
||||
.onAppear {
|
||||
viewModel.onAppear(environments: environments)
|
||||
}
|
||||
|
||||
@@ -6,10 +6,15 @@ import SwiftUI
|
||||
|
||||
@MainActor
|
||||
public class MainViewModel: BaseViewModel {
|
||||
@Published public var selection = NavigationPage.dashboard
|
||||
@Published public var selection: NavigationPage
|
||||
@Published public var importProfile: LibboxProfileContent?
|
||||
@Published public var importRemoteProfile: LibboxImportRemoteProfile?
|
||||
|
||||
public init(selection: NavigationPage = .dashboard) {
|
||||
self.selection = selection
|
||||
super.init()
|
||||
}
|
||||
|
||||
public func onAppear(environments: ExtensionEnvironments) {
|
||||
environments.postReload()
|
||||
#if !DEBUG
|
||||
|
||||
@@ -9,7 +9,7 @@ private struct SidebarContentView: View {
|
||||
var environments: ExtensionEnvironments
|
||||
|
||||
private var hasGroups: Bool {
|
||||
environments.commandClient.groups?.isEmpty == false
|
||||
Variant.screenshotMode || environments.commandClient.groups?.isEmpty == false
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
@@ -77,9 +77,7 @@ public struct SidebarView: View {
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
if ApplicationLibrary.inPreview {
|
||||
previewContent
|
||||
} else if environments.extensionProfileLoading {
|
||||
if environments.extensionProfileLoading {
|
||||
ProgressView()
|
||||
} else if let profile = environments.extensionProfile {
|
||||
SidebarContentView(
|
||||
@@ -93,24 +91,6 @@ public struct SidebarView: View {
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var previewContent: some View {
|
||||
List(selection: $localSelection) {
|
||||
Section(NavigationPage.dashboard.title) {
|
||||
Label("Overview", systemImage: "text.and.command.macwindow")
|
||||
.tint(.textColor)
|
||||
.tag(NavigationPage.dashboard)
|
||||
NavigationPage.groups.label.tag(NavigationPage.groups)
|
||||
NavigationPage.connections.label.tag(NavigationPage.connections)
|
||||
}
|
||||
ForEach(NavigationPage.macosDefaultPages, id: \.self) { it in
|
||||
it.label
|
||||
}
|
||||
}
|
||||
.listStyle(.sidebar)
|
||||
.scrollDisabled(true)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var disconnectedContent: some View {
|
||||
List(selection: $localSelection) {
|
||||
|
||||
@@ -203,7 +203,7 @@ public class StatusBarController: NSObject, NSMenuDelegate {
|
||||
|
||||
guard let groups else { return }
|
||||
|
||||
let selectableGroups = groups.filter { $0.selectable }
|
||||
let selectableGroups = groups.filter(\.selectable)
|
||||
if selectableGroups.isEmpty {
|
||||
groupsItem?.isHidden = true
|
||||
return
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import SwiftUI
|
||||
|
||||
struct WindowAccessor: NSViewRepresentable {
|
||||
final class WindowReportingView: NSView {
|
||||
var onWindowChange: ((NSWindow?) -> Void)?
|
||||
|
||||
override func viewDidMoveToWindow() {
|
||||
super.viewDidMoveToWindow()
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.onWindowChange?(self?.window)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let callback: (NSWindow?) -> Void
|
||||
|
||||
func makeNSView(context _: Context) -> WindowReportingView {
|
||||
let view = WindowReportingView()
|
||||
view.onWindowChange = callback
|
||||
return view
|
||||
}
|
||||
|
||||
func updateNSView(_ nsView: WindowReportingView, context _: Context) {
|
||||
nsView.onWindowChange = callback
|
||||
DispatchQueue.main.async {
|
||||
callback(nsView.window)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user