191 lines
5.8 KiB
Swift
191 lines
5.8 KiB
Swift
//
|
|
// meetingnotesApp.swift
|
|
// meetingnotes
|
|
//
|
|
// Created by Owen Gretzinger on 2025-07-10.
|
|
//
|
|
|
|
import SwiftUI
|
|
import AppKit
|
|
import Sparkle
|
|
import PostHog
|
|
|
|
@main
|
|
struct MeetingnotesApp: App {
|
|
private let updaterController: SPUStandardUpdaterController
|
|
@StateObject private var recordingSessionManager = RecordingSessionManager.shared
|
|
|
|
init() {
|
|
updaterController = SPUStandardUpdaterController(updaterDelegate: nil, userDriverDelegate: nil)
|
|
// Setup PostHog analytics for anonymous tracking
|
|
let posthogAPIKey = "phc_Wt8sWUzUF7YPF50aQ0B1qbfA5SJWWR341zmXCaIaIRJ"
|
|
let posthogHost = "https://us.i.posthog.com"
|
|
let config = PostHogConfig(apiKey: posthogAPIKey, host: posthogHost)
|
|
// Only capture anonymous events
|
|
config.personProfiles = .never
|
|
// Enable lifecycle and screen view autocapture
|
|
config.captureApplicationLifecycleEvents = true
|
|
config.captureScreenViews = true
|
|
PostHogSDK.shared.setup(config)
|
|
// Register environment as a super property
|
|
#if DEBUG
|
|
PostHogSDK.shared.register(["environment": "dev"] )
|
|
#else
|
|
PostHogSDK.shared.register(["environment": "prod"] )
|
|
#endif
|
|
}
|
|
|
|
var body: some Scene {
|
|
WindowGroup("Meetingnotes", id: "main") {
|
|
ContentView()
|
|
.frame(minWidth: 700, minHeight: 400)
|
|
.background(MainWindowConfigurator())
|
|
}
|
|
.windowResizability(.automatic)
|
|
.defaultSize(width: 1000, height: 600)
|
|
.commands {
|
|
CommandGroup(after: .appInfo) {
|
|
CheckForUpdatesView(updater: updaterController.updater)
|
|
Divider()
|
|
Button("Show Audio Folder") {
|
|
LocalStorageManager.shared.showAudioFolderInFinder()
|
|
}
|
|
}
|
|
}
|
|
|
|
MenuBarExtra {
|
|
MeetingnotesMenu(
|
|
recordingSessionManager: recordingSessionManager,
|
|
updater: updaterController.updater
|
|
)
|
|
} label: {
|
|
Image(systemName: recordingSessionManager.isRecording ? "record.circle.fill" : "waveform")
|
|
.accessibilityLabel(recordingSessionManager.isRecording ? "Meetingnotes recording" : "Meetingnotes")
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct MeetingnotesMenu: View {
|
|
@ObservedObject var recordingSessionManager: RecordingSessionManager
|
|
let updater: SPUUpdater
|
|
@Environment(\.openWindow) private var openWindow
|
|
|
|
var body: some View {
|
|
if recordingSessionManager.isRecording {
|
|
Label("Recording", systemImage: "record.circle.fill")
|
|
} else if recordingSessionManager.isProcessing {
|
|
Label("Processing audio", systemImage: "hourglass")
|
|
}
|
|
|
|
Button {
|
|
MainWindowController.shared.show(using: openWindow)
|
|
} label: {
|
|
Label("Open Meetingnotes", systemImage: "macwindow")
|
|
}
|
|
|
|
Button {
|
|
LocalStorageManager.shared.showAudioFolderInFinder()
|
|
} label: {
|
|
Label("Show Audio Folder", systemImage: "folder")
|
|
}
|
|
|
|
Divider()
|
|
|
|
Button {
|
|
updater.checkForUpdates()
|
|
} label: {
|
|
Label("Check for Updates...", systemImage: "arrow.triangle.2.circlepath")
|
|
}
|
|
.keyboardShortcut("u")
|
|
|
|
Button {
|
|
NSApplication.shared.terminate(nil)
|
|
} label: {
|
|
Label("Quit Meetingnotes", systemImage: "power")
|
|
}
|
|
.keyboardShortcut("q")
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
private final class MainWindowController: NSObject {
|
|
static let shared = MainWindowController()
|
|
|
|
private weak var window: NSWindow?
|
|
|
|
func configure(_ window: NSWindow) {
|
|
if self.window !== window {
|
|
if let previousWindow = self.window {
|
|
NotificationCenter.default.removeObserver(
|
|
self,
|
|
name: NSWindow.willMiniaturizeNotification,
|
|
object: previousWindow
|
|
)
|
|
}
|
|
self.window = window
|
|
NotificationCenter.default.addObserver(
|
|
self,
|
|
selector: #selector(windowWillMiniaturize(_:)),
|
|
name: NSWindow.willMiniaturizeNotification,
|
|
object: window
|
|
)
|
|
}
|
|
|
|
if let minimizeButton = window.standardWindowButton(.miniaturizeButton) {
|
|
minimizeButton.target = self
|
|
minimizeButton.action = #selector(hideWindow(_:))
|
|
}
|
|
}
|
|
|
|
func show(using openWindow: OpenWindowAction) {
|
|
if let window {
|
|
window.makeKeyAndOrderFront(nil)
|
|
} else {
|
|
openWindow(id: "main")
|
|
}
|
|
NSApplication.shared.activate(ignoringOtherApps: true)
|
|
}
|
|
|
|
@objc private func hideWindow(_ sender: NSButton) {
|
|
sender.window?.orderOut(nil)
|
|
}
|
|
|
|
@objc private func windowWillMiniaturize(_ notification: Notification) {
|
|
guard let window = notification.object as? NSWindow else { return }
|
|
DispatchQueue.main.async {
|
|
window.deminiaturize(nil)
|
|
window.orderOut(nil)
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct MainWindowConfigurator: NSViewRepresentable {
|
|
func makeNSView(context: Context) -> NSView {
|
|
let view = NSView()
|
|
configureWindow(for: view)
|
|
return view
|
|
}
|
|
|
|
func updateNSView(_ nsView: NSView, context: Context) {
|
|
configureWindow(for: nsView)
|
|
}
|
|
|
|
private func configureWindow(for view: NSView) {
|
|
DispatchQueue.main.async {
|
|
guard let window = view.window else { return }
|
|
MainWindowController.shared.configure(window)
|
|
}
|
|
}
|
|
}
|
|
|
|
struct CheckForUpdatesView: View {
|
|
let updater: SPUUpdater
|
|
|
|
var body: some View {
|
|
Button("Check for Updates...") {
|
|
updater.checkForUpdates()
|
|
}
|
|
.keyboardShortcut("u", modifiers: .command)
|
|
}
|
|
}
|