@@ -4,20 +4,27 @@ import Kingfisher
44import SwiftUI
55import AVKit
66
7+ class ClosableWindow : NSWindow {
8+ override func cancelOperation( _ sender: Any ? ) {
9+ self . close ( )
10+ }
11+ }
12+
713@_cdecl ( " open_img_viewer " )
814public func open_img_viewer( urlCString: UnsafePointer < CChar > ? ) {
915 let urlStr = urlCString. flatMap { String ( cString: $0) } ?? " about:blank "
1016 let targetURL = URL ( string: urlStr) !
1117 DispatchQueue . main. async {
1218 if NSApp == nil { _ = NSApplication . shared }
1319
14- let win = NSWindow ( contentRect: NSRect ( x: 200 , y: 200 , width: 1000 , height: 700 ) ,
20+ let win = ClosableWindow ( contentRect: NSRect ( x: 200 , y: 200 , width: 1000 , height: 700 ) ,
1521 styleMask: [ . resizable, . titled, . closable, . miniaturizable, . fullSizeContentView] ,
1622 backing: . buffered, defer: false )
1723 win. titlebarAppearsTransparent = true
1824 win. titleVisibility = . hidden
1925 win. isMovableByWindowBackground = true
2026 win. appearance = . init( named: . darkAqua)
27+ win. setFrameOriginToPositionWindowInCenterOfScreen ( )
2128
2229 win. contentView = makeZoomingScrollView ( targetURL: targetURL)
2330 win. isReleasedWhenClosed = false
@@ -35,13 +42,14 @@ public func open_video_viewer(urlCString: UnsafePointer<CChar>?) {
3542 DispatchQueue . main. async {
3643 if NSApp == nil { _ = NSApplication . shared }
3744
38- let win = NSWindow ( contentRect: NSRect ( x: 200 , y: 200 , width: 1000 , height: 700 ) ,
45+ let win = ClosableWindow ( contentRect: NSRect ( x: 200 , y: 200 , width: 1000 , height: 700 ) ,
3946 styleMask: [ . resizable, . titled, . closable, . miniaturizable, . fullSizeContentView] ,
4047 backing: . buffered, defer: false )
4148 win. titlebarAppearsTransparent = true
4249 win. titleVisibility = . hidden
4350 win. isMovableByWindowBackground = true
4451 win. appearance = . init( named: . darkAqua)
52+ win. setFrameOriginToPositionWindowInCenterOfScreen ( )
4553 let playerView = AVPlayerView ( )
4654 let videoPlayer = AVPlayer ( url: targetURL)
4755 playerView. player = videoPlayer
@@ -56,53 +64,94 @@ public func open_video_viewer(urlCString: UnsafePointer<CChar>?) {
5664
5765
5866
59- //struct OpenStatusImageModel: Decodable {
60- // let index: Int
61- // let medias: [StatusMediaItem]
62- //}
63- //
64- //struct StatusMediaItem: Decodable {
65- // let url: String
66- // let type: String
67- // let placeholder: String?
68- //}
69- //
70- //@_cdecl("open_status_image_viewer")
71- //public func open_status_image_viewer(_ json: UnsafePointer<CChar>?) {
72- // guard let json = json else { return }
73- // let s = String(cString: json)
74- // if let data = s.data(using: .utf8),
75- // let model = try? JSONDecoder().decode(OpenStatusImageModel.self, from: data) {
76- // DispatchQueue.main.sync {
77- // if NSApp == nil { _ = NSApplication.shared }
78- // let win = NSWindow(contentRect: NSRect(x: 200, y: 200, width: 1000, height: 700),
79- // styleMask: [.resizable, .titled, .closable, .miniaturizable, .fullSizeContentView],
80- // backing: .buffered, defer: false)
81- //// let win = NSWindow(contentViewController: OpenStatusPagerViewController(model: model))
82- //// win.contentMinSize = .init(width: 100, height: 100)
83- //// win.styleMask = [.resizable, .titled, .closable, .miniaturizable, .fullSizeContentView]
84- // win.titlebarAppearsTransparent = true
85- // win.titleVisibility = .hidden
86- // win.isMovableByWindowBackground = true
87- // win.appearance = .init(named: .darkAqua)
88- //
89- //// let pagerVC = OpenStatusPagerViewController(model: model)
90- //// win.contentViewController = pagerVC
91- // win.contentView = NSHostingView(rootView: MediaPagerView(model: model))
92- // win.isReleasedWhenClosed = false
93- // win.delegate = windowDelegate
94- // openedWindows.insert(win)
95- // swiftLog(2, "Window opened. Total windows: \(openedWindows.count)") // 调试日志
96- //
97- // win.makeKeyAndOrderFront(nil)
98- // NSApp.activate(ignoringOtherApps: true)
99- // swiftLog(2, "8. Window should be visible. Window count: \(openedWindows.count)")
100- // swiftLog(2, "9. Window is visible: \(win.isVisible), is key: \(win.isKeyWindow)")
101- //
102- // }
103- // }
104- //}
67+ struct OpenStatusImageModel : Decodable {
68+ let index : Int
69+ let medias : [ StatusMediaItem ]
70+ }
71+
72+ struct StatusMediaItem : Decodable {
73+ let url : String
74+ let type : String
75+ let placeholder : String ?
76+ }
77+
78+ @_cdecl ( " open_status_image_viewer " )
79+ public func open_status_image_viewer( _ json: UnsafePointer < CChar > ? ) {
80+ guard let json = json else { return }
81+ let s = String ( cString: json)
82+ if let data = s. data ( using: . utf8) ,
83+ let model = try ? JSONDecoder ( ) . decode ( OpenStatusImageModel . self, from: data) {
84+ DispatchQueue . main. sync {
85+ if NSApp == nil { _ = NSApplication . shared }
86+ let win = ClosableWindow ( contentRect: NSRect ( x: 200 , y: 200 , width: 1000 , height: 700 ) ,
87+ styleMask: [ . resizable, . titled, . closable, . miniaturizable, . fullSizeContentView] ,
88+ backing: . buffered, defer: false )
89+ win. titlebarAppearsTransparent = true
90+ win. titleVisibility = . hidden
91+ win. isMovableByWindowBackground = true
92+ win. appearance = . init( named: . darkAqua)
93+ win. setFrameOriginToPositionWindowInCenterOfScreen ( )
94+
95+ win. contentView = NSHostingView ( rootView: StatusMediaView ( medias: model. medias, page: model. index) )
96+ win. isReleasedWhenClosed = false
97+
98+ win. makeKeyAndOrderFront ( nil )
99+ NSApp . activate ( ignoringOtherApps: true )
100+
101+ }
102+ }
103+ }
104+
105105
106+ struct StatusMediaView : View {
107+ let medias : [ StatusMediaItem ]
108+ @State var page : Int ? = 0
109+ var body : some View {
110+ ScrollView ( . horizontal) {
111+ HStack ( spacing: 0 ) {
112+ ForEach ( 0 ..< medias. count, id: \. self) { i in
113+ let media = medias [ i]
114+ ZStack {
115+ if ( media. type == " gif " || media. type == " image " ) {
116+ KFImage ( . init( string: media. url) !)
117+ . placeholder ( {
118+ if let placeholder = media. placeholder {
119+ KFImage
120+ . url ( . init( string: placeholder) !)
121+ . resizable ( )
122+ . scaledToFit ( )
123+ } else {
124+ ProgressView ( )
125+ }
126+ } )
127+ . resizable ( )
128+ . scaledToFit ( )
129+ } else if ( media. type == " video " ) {
130+ if ( page == i) {
131+ let player = AVPlayer ( url: . init( string: media. url) !)
132+ VideoPlayer ( player: player)
133+ . onAppear {
134+ player. play ( )
135+ }
136+ } else if let placeholder = media. placeholder {
137+ KFImage ( . init( string: placeholder) !)
138+ } else {
139+ EmptyView ( )
140+ }
141+ }
142+ }
143+ . containerRelativeFrame ( . horizontal, count: 1 , spacing: 0 )
144+ . id ( i)
145+ }
146+ }
147+ . scrollTargetLayout ( )
148+ }
149+ . scrollIndicators ( . hidden)
150+ . scrollTargetBehavior ( . paging)
151+ . scrollPosition ( id: $page)
152+ . ignoresSafeArea ( )
153+ }
154+ }
106155
107156
108157
@@ -165,3 +214,11 @@ final class CenteringClipView: NSClipView {
165214 return rect
166215 }
167216}
217+
218+ extension NSWindow {
219+ public func setFrameOriginToPositionWindowInCenterOfScreen( ) {
220+ if let screenSize = screen? . frame. size {
221+ self . setFrameOrigin ( NSPoint ( x: ( screenSize. width- frame. size. width) / 2 , y: ( screenSize. height- frame. size. height) / 2 ) )
222+ }
223+ }
224+ }
0 commit comments