Add an iPhone client sharing the macOS app's SwiftUI code
This commit is contained in:
+47
-14
@@ -1,4 +1,3 @@
|
||||
import AppKit
|
||||
import ByreAPI
|
||||
import SwiftUI
|
||||
|
||||
@@ -175,12 +174,21 @@ final class ChatModel {
|
||||
self?.builder.appendDelta(ev)
|
||||
}
|
||||
})
|
||||
#if os(macOS)
|
||||
activeObserver = NotificationCenter.default.addObserver(of: NSApplication.self, for: .didBecomeActive) { [weak self] _ in
|
||||
self?.markShown()
|
||||
}
|
||||
keyObserver = NotificationCenter.default.addObserver(of: NSWindow.self, for: .didBecomeKey) { [weak self] _ in
|
||||
self?.markShown()
|
||||
}
|
||||
#else
|
||||
activeObserver = NotificationCenter.default.addObserver(of: UIApplication.self, for: .didBecomeActive) { [weak self] _ in
|
||||
self?.markShown()
|
||||
}
|
||||
offs.append(store.paneFocus.shown.add { [weak self] _ in
|
||||
self?.markShown()
|
||||
})
|
||||
#endif
|
||||
}
|
||||
|
||||
func stop() {
|
||||
@@ -225,7 +233,7 @@ final class ChatModel {
|
||||
}
|
||||
|
||||
private func markShown() {
|
||||
guard let taskId, store.paneFocus.windowKey else {
|
||||
guard let taskId, store.paneFocus.taskVisible else {
|
||||
return
|
||||
}
|
||||
for seq in visibleSummaries {
|
||||
@@ -460,7 +468,7 @@ final class ChatModel {
|
||||
var imgs: [PendingImage] = []
|
||||
for id in p.imageIds {
|
||||
let data = try await ImageCache.fetch(.blob(id), store.api)
|
||||
guard let image = NSImage(data: data) else {
|
||||
guard let image = PlatformImage(data: data) else {
|
||||
throw ApiError(status: 0, message: "not an image")
|
||||
}
|
||||
imgs.append(PendingImage(data: data, image: image))
|
||||
@@ -903,34 +911,59 @@ struct StatusButton: View {
|
||||
}
|
||||
}
|
||||
|
||||
private struct Scanner: NSViewRepresentable {
|
||||
@MainActor
|
||||
private struct Scanner {
|
||||
let color: Color
|
||||
|
||||
func update(_ v: ScannerView, _ environment: EnvironmentValues) {
|
||||
let c = color.resolve(in: environment).cgColor
|
||||
let clear = c.copy(alpha: 0)!
|
||||
CATransaction.begin()
|
||||
CATransaction.setDisableActions(true)
|
||||
v.glow.colors = [clear, c, clear]
|
||||
CATransaction.commit()
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
extension Scanner: NSViewRepresentable {
|
||||
func makeNSView(context: Context) -> ScannerView {
|
||||
ScannerView()
|
||||
}
|
||||
|
||||
func updateNSView(_ v: ScannerView, context: Context) {
|
||||
let c = NSColor(color)
|
||||
CATransaction.begin()
|
||||
CATransaction.setDisableActions(true)
|
||||
v.glow.colors = [c.withAlphaComponent(0).cgColor, c.cgColor, c.withAlphaComponent(0).cgColor]
|
||||
CATransaction.commit()
|
||||
update(v, context.environment)
|
||||
}
|
||||
}
|
||||
#else
|
||||
extension Scanner: UIViewRepresentable {
|
||||
func makeUIView(context: Context) -> ScannerView {
|
||||
ScannerView()
|
||||
}
|
||||
|
||||
private final class ScannerView: NSView {
|
||||
func updateUIView(_ v: ScannerView, context: Context) {
|
||||
update(v, context.environment)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private final class ScannerView: PlatformView {
|
||||
let glow = CAGradientLayer()
|
||||
|
||||
override init(frame: NSRect) {
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
#if os(macOS)
|
||||
wantsLayer = true
|
||||
let host = layer!
|
||||
#else
|
||||
let host = layer
|
||||
#endif
|
||||
let dots = CALayer()
|
||||
dots.frame = CGRect(x: 0, y: 0, width: 84, height: 2)
|
||||
for x in stride(from: 0.0, through: 80, by: 5) {
|
||||
let dot = CALayer()
|
||||
dot.frame = CGRect(x: x, y: 0, width: 2, height: 2)
|
||||
dot.backgroundColor = NSColor.black.cgColor
|
||||
dot.backgroundColor = CGColor(gray: 0, alpha: 1)
|
||||
dots.addSublayer(dot)
|
||||
}
|
||||
glow.bounds = CGRect(x: 0, y: 0, width: 30, height: 2)
|
||||
@@ -941,7 +974,7 @@ private final class ScannerView: NSView {
|
||||
strip.frame = dots.frame
|
||||
strip.mask = dots
|
||||
strip.addSublayer(glow)
|
||||
layer?.addSublayer(strip)
|
||||
host.addSublayer(strip)
|
||||
let sweep = CABasicAnimation(keyPath: "position.x")
|
||||
sweep.fromValue = 15
|
||||
sweep.toValue = 69
|
||||
@@ -987,7 +1020,7 @@ private struct PendingView: View {
|
||||
if !pending.images.isEmpty {
|
||||
FlowLayout(spacing: 6) {
|
||||
ForEach(pending.images) { img in
|
||||
Image(nsImage: img.image)
|
||||
Image(platformImage: img.image)
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(maxWidth: 240, maxHeight: 180)
|
||||
|
||||
Reference in New Issue
Block a user