mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2025-06-28 12:19:54 +00:00
155 lines
5.5 KiB
Swift
155 lines
5.5 KiB
Swift
//
|
|
// FullScreenImageView.swift
|
|
// SimpleX (iOS)
|
|
//
|
|
// Created by Evgeny on 08/10/2022.
|
|
// Copyright © 2022 SimpleX Chat. All rights reserved.
|
|
//
|
|
|
|
import SwiftUI
|
|
import SimpleXChat
|
|
import SwiftyGif
|
|
import AVKit
|
|
|
|
struct FullScreenMediaView: View {
|
|
@EnvironmentObject var m: ChatModel
|
|
@State var chatItem: ChatItem
|
|
var scrollToItem: ((ChatItem.ID) -> Void)?
|
|
@State var image: UIImage?
|
|
@State var player: AVPlayer? = nil
|
|
@State var url: URL? = nil
|
|
@Binding var showView: Bool
|
|
@State private var showNext = false
|
|
@State private var nextImage: UIImage?
|
|
@State private var nextPlayer: AVPlayer?
|
|
@State private var nextURL: URL?
|
|
@State private var scrolling = false
|
|
@State private var offset: CGFloat = 0
|
|
@State private var nextOffset: CGFloat = 0
|
|
|
|
var body: some View {
|
|
GeometryReader(content: mediaScrollView)
|
|
}
|
|
|
|
func mediaScrollView(_ g: GeometryProxy) -> some View {
|
|
ZStack {
|
|
Color.black.edgesIgnoringSafeArea(.all)
|
|
if showNext, let nextImage = nextImage {
|
|
if let image = image {
|
|
imageView(image).offset(x: offset)
|
|
} else if let player = player, let url = url {
|
|
videoView(player, url).offset(x: offset)
|
|
}
|
|
imageView(nextImage).offset(x: offset + nextOffset)
|
|
} else if showNext, let nextPlayer = nextPlayer, let nextURL = nextURL {
|
|
if let image = image {
|
|
imageView(image).offset(x: offset)
|
|
} else if let player = player, let url = url {
|
|
videoView(player, url).offset(x: offset)
|
|
}
|
|
videoView(nextPlayer, nextURL).offset(x: offset + nextOffset)
|
|
} else {
|
|
ZoomableScrollView {
|
|
if let image = image {
|
|
imageView(image)
|
|
} else if let player = player, let url = url {
|
|
videoView(player, url)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.onAppear {
|
|
startPlayerAndNotify()
|
|
}
|
|
.onDisappear {
|
|
player?.pause()
|
|
}
|
|
.gesture(
|
|
DragGesture(minimumDistance: 80)
|
|
.onChanged { gesture in
|
|
let t = gesture.translation
|
|
let w = abs(t.width)
|
|
if t.height > 60 && t.height > w * 2 {
|
|
showView = false
|
|
scrollToItem?(chatItem.id)
|
|
} else if w > 60 && w > abs(t.height) * 2 && !scrolling {
|
|
let previous = t.width > 0
|
|
scrolling = true
|
|
if let item = m.nextChatItemData(chatItem.id, previous: previous, map: chatItemImage) {
|
|
var img: UIImage?
|
|
var url: URL?
|
|
(chatItem, img, url) = item
|
|
nextImage = img
|
|
nextPlayer?.pause()
|
|
if let url = url {
|
|
nextPlayer = VideoPlayerView.getOrCreatePlayer(url, true)
|
|
} else {
|
|
nextPlayer = nil
|
|
}
|
|
nextURL = url
|
|
let s = g.size.width
|
|
var toOffset: CGFloat
|
|
(toOffset, nextOffset) = previous ? (s, -s) : (-s, s)
|
|
showNext = true
|
|
withAnimation(.easeIn(duration: 0.2)) {
|
|
offset = toOffset
|
|
}
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
|
|
image = img
|
|
player?.pause()
|
|
self.url = url
|
|
if let url = url {
|
|
player = VideoPlayerView.getOrCreatePlayer(url, true)
|
|
startPlayerAndNotify()
|
|
} else {
|
|
player = nil
|
|
}
|
|
showNext = false
|
|
offset = 0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.onEnded { _ in scrolling = false }
|
|
)
|
|
}
|
|
|
|
private func imageView(_ img: UIImage) -> some View {
|
|
ZStack {
|
|
Color.black
|
|
if img.imageData == nil {
|
|
Image(uiImage: img)
|
|
.resizable()
|
|
.scaledToFit()
|
|
} else {
|
|
SwiftyGif(image: img)
|
|
.scaledToFit()
|
|
}
|
|
}
|
|
.onTapGesture { showView = false } // this is used in full screen view, onTapGesture works
|
|
}
|
|
|
|
private func videoView( _ player: AVPlayer, _ url: URL) -> some View {
|
|
VideoPlayerView(player: player, url: url, showControls: true)
|
|
}
|
|
|
|
private func chatItemImage(_ ci: ChatItem) -> (ChatItem, UIImage?, URL?)? {
|
|
if case .image = ci.content.msgContent,
|
|
let img = getLoadedImage(ci.file) {
|
|
return (ci, img, nil)
|
|
}
|
|
// Currently, video support in gallery is not enabled
|
|
/*else if case .video = ci.content.msgContent,
|
|
let url = getLoadedVideo(ci.file) {
|
|
return (ci, nil, url)
|
|
}*/
|
|
return nil
|
|
}
|
|
|
|
private func startPlayerAndNotify() {
|
|
if let player = player {
|
|
m.stopPreviousRecPlay = url
|
|
player.play()
|
|
}
|
|
}
|
|
}
|