You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
169 lines
8.0 KiB
169 lines
8.0 KiB
//
|
|
// Created by Marco Schmickler on 22.06.22.
|
|
// Copyright (c) 2022 Marco Schmickler. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import SwiftUI
|
|
|
|
struct KAnimate: ViewModifier {
|
|
var dragOffset: CGSize
|
|
var spring: Bool
|
|
var off: Bool
|
|
|
|
init(dragOffset: CGSize, spring: Bool, off: Bool = false) {
|
|
self.dragOffset = dragOffset
|
|
self.spring = spring
|
|
self.off = off
|
|
}
|
|
|
|
func body(content: Content) -> some View {
|
|
if (off) {
|
|
content
|
|
} else if (spring) {
|
|
content.animation(.spring(response: 10, dampingFraction: 0.05), value: dragOffset)
|
|
} else {
|
|
content.animation(.easeOut(duration: 3), value: dragOffset)
|
|
}
|
|
}
|
|
}
|
|
|
|
struct SPhotoView: View {
|
|
@ObservedObject
|
|
var model: SPhotoModel
|
|
|
|
@State var lastScale: CGFloat = 2
|
|
@State var lastScaleValue: CGFloat = 1.0
|
|
@State var lastDragOffset: CGSize = CGSize.zero
|
|
@State var lastDrag: CGSize = CGSize.zero
|
|
@State var skip = false
|
|
@State var zooming = false
|
|
@State var startindex = -1
|
|
@State var animateX = 0
|
|
@State var dampen = 0.05
|
|
@State var jump = LocalManager.sharedInstance.settings.jump
|
|
|
|
init(model: SPhotoModel) {
|
|
self.model = model
|
|
}
|
|
|
|
var body: some View {
|
|
|
|
GeometryReader { geo in
|
|
// AsyncImage(item: model.selectedItem, thumb: false, placeholder: { Text("Loading ...") }, image: { Image(uiImage: $0).resizable() })
|
|
ZStack {
|
|
Image(uiImage: model.image)
|
|
.resizable().scaledToFit()
|
|
// SwiftUI.AsyncImage(url: URL(string: model.allItems[model.index].imageUrlAbsolute)) { image in
|
|
// image.resizable().scaledToFit()
|
|
// }
|
|
// placeholder: {
|
|
// if let i = model.selectedItem.thumbImage {
|
|
// Image(uiImage: i).resizable().scaledToFit()
|
|
// } else {
|
|
// Text("...")
|
|
// }
|
|
// }
|
|
.frame(height: geo.size.height).frame(width: geo.size.width, alignment: .leading)
|
|
.scaleEffect(model.scale).offset(model.dragOffset).modifier(KAnimate(dragOffset: model.dragOffset, spring: model.spring, off: zooming))
|
|
}
|
|
.onTapGesture(count: 2) {
|
|
let h1 = geo.size.height
|
|
let h2 = model.image.size.height
|
|
model.maxScale = h2 / h1
|
|
print("3 tapped!")
|
|
if model.scale == 1 {
|
|
model.scale = lastScale
|
|
} else {
|
|
lastScale = model.scale
|
|
model.scale = 1
|
|
model.dragOffset = CGSize.zero
|
|
}
|
|
}
|
|
.gesture(
|
|
DragGesture()
|
|
.onChanged { gesture in
|
|
let dragged = gesture.translation
|
|
let multi = (model.spring) ? 2.0 : 3.0
|
|
|
|
if startindex < 0 {
|
|
startindex = model.index
|
|
}
|
|
// print("\(startindex) \(dragged.width)")
|
|
if model.scale == 1 { //&& gesture.startLocation.x < 400 {
|
|
if (jump && dragged.height > 120) {
|
|
print("next")
|
|
model.next()
|
|
return
|
|
}
|
|
|
|
if (jump && dragged.height < -120) {
|
|
print("back")
|
|
model.back()
|
|
return
|
|
}
|
|
|
|
var i = startindex + Int(dragged.width / 15.0)
|
|
|
|
if i >= model.allItems.count {
|
|
i = model.allItems.count - 1
|
|
}
|
|
if i < 0 {
|
|
i = 0
|
|
}
|
|
|
|
if (i != model.index) {
|
|
ImageLoader.shared.backgroundQueue.cancelAllOperations()
|
|
model.index = i
|
|
model.selectedItem = model.allItems[model.index]
|
|
model.loadImage()
|
|
}
|
|
} else {
|
|
if (dragged.height * multi) + lastDragOffset.height > -500 * model.scale {
|
|
model.dragOffset = CGSize(width: (dragged.width * multi) + lastDragOffset.width, height: (dragged.height * multi) + lastDragOffset.height)
|
|
}
|
|
}
|
|
dampen = 0.05
|
|
lastDrag = dragged
|
|
print("scale \(model.scale) h \(model.dragOffset.height) w \(model.dragOffset.width)")
|
|
}
|
|
.onEnded { gesture in
|
|
startindex = -1
|
|
lastDragOffset = model.dragOffset
|
|
dampen = 0.05
|
|
skip = false
|
|
}
|
|
)
|
|
.gesture(MagnificationGesture()
|
|
.onChanged { val in
|
|
if !zooming {
|
|
zooming = true
|
|
lastDragOffset = model.dragOffset
|
|
}
|
|
|
|
let delta = val / self.lastScaleValue
|
|
self.lastScaleValue = val
|
|
model.scale = model.scale * delta
|
|
|
|
let h1 = geo.size.height
|
|
let h2 = model.image.size.height
|
|
model.maxScale = h2 / h1
|
|
|
|
let width = geo.size.width / 2;
|
|
model.dragOffset.width = lastDragOffset.width + (width - (width / model.scale))
|
|
|
|
let height = geo.size.height / 2;
|
|
model.dragOffset.height = lastDragOffset.height + (height - (height / model.scale))
|
|
print("scale \(model.scale) h \(model.dragOffset.height) w \(model.dragOffset.width) lh \(lastDragOffset.height) lw \(lastDragOffset.width)")
|
|
// print("scale \(model.scale) frame \(h1) image \(h2) \(h2/h1)")
|
|
}
|
|
.onEnded { val in
|
|
zooming = false
|
|
// without this the next gesture will be broken
|
|
self.lastScaleValue = 1.0
|
|
})
|
|
|
|
}
|
|
.contentShape(Rectangle()).clipped();
|
|
}
|
|
}
|