@@ -11,117 +11,117 @@ import Kingfisher
11
11
12
12
public struct PuraceImageViewer : View {
13
13
@Binding var isVisible : Bool
14
- let backgroundColor : Color
15
- let url : URL ?
16
- @State var opacity : Double = 0
17
- @State var dragOffset : CGSize = . zero
18
- @State var backgroundOpacity : Double = 1
19
- @State var hasDraggedTheImage = false
20
- @State var dragInitialTime : Date ?
21
-
14
+ let urls : [ URL ? ]
15
+ @State var currentIndex : Int
22
16
@GestureState var scale : CGFloat = 1
17
+ @State var dragOffset : CGFloat = . zero
18
+ @State var backgroundOpacity = 1.0
19
+
20
+ private let numberOfImages : Int
23
21
24
22
private let maximumImageHeight = UIScreen . main. bounds. height * 0.65
25
23
26
- public init ( url: URL ? , isVisible: Binding < Bool > ) {
27
- let colors : [ Color ] = [
28
- PuraceStyle . Color. X1,
29
- PuraceStyle . Color. X2,
30
- PuraceStyle . Color. X3,
31
- PuraceStyle . Color. X4
32
- ]
33
- backgroundColor = colors. randomElement ( ) !
34
- self . url = url
24
+ public init ( urls: [ URL ? ] , isVisible: Binding < Bool > , index: Int = 0 ) {
25
+ self . urls = urls
35
26
self . _isVisible = isVisible
27
+ self . _currentIndex = . init( initialValue: index)
28
+ self . numberOfImages = urls. count
36
29
}
37
30
38
- private func differenceBeetwenInitialDragTime( and date: Date ) -> Double {
39
- guard let dragInitialTime = dragInitialTime else {
40
- return . zero
31
+ var indicator : some View {
32
+ HStack {
33
+ if numberOfImages > 1 {
34
+ PuraceTextView ( " \( currentIndex + 1 ) / \( numberOfImages) " , fontSize: 14 , textColor: . white, weight: . medium)
35
+ . padding ( . trailing)
36
+ }
41
37
}
42
- return date. timeIntervalSince ( dragInitialTime) * 1000
43
38
}
44
39
45
- var draggableArea : some View {
46
- Color . black
47
- . animation ( . none)
48
- . opacity ( 0.001 )
49
- . gesture (
40
+ var backButton : some View {
41
+ Image ( systemName: " chevron.left " )
42
+ . foregroundColor ( . white)
43
+ . scaleEffect ( 1.2 )
44
+ . padding ( )
45
+ . highPriorityGesture (
46
+ TapGesture ( )
47
+ . onEnded {
48
+ withAnimation {
49
+ isVisible = false
50
+ }
51
+ }
52
+ )
53
+ }
54
+
55
+ var topBar : some View {
56
+ VStack {
57
+ HStack ( alignment: . center) {
58
+ backButton
59
+
60
+ Spacer ( )
61
+
62
+ indicator
63
+ } . frame ( height: 60 )
64
+ . opacity ( ( abs ( dragOffset) >= . zero && abs ( dragOffset) <= 5 ) ? 1 : 0.0002 )
65
+ }
66
+ }
67
+
68
+ var viewer : some View {
69
+ VStack ( spacing: 0 ) {
70
+ topBar
71
+
72
+ TabView ( selection: $currentIndex) {
73
+ ForEach ( 0 ..< numberOfImages) { index in
74
+ PuraceImageView ( url: urls [ index] )
75
+ . scaledToFit ( )
76
+ . tag ( index)
77
+ . scaleEffect ( scale)
78
+ . offset ( y: dragOffset)
79
+ . gesture (
80
+ MagnificationGesture ( )
81
+ . updating ( $scale) { value, scale, _ in
82
+ if value >= 0.9 {
83
+ scale = value
84
+ }
85
+ }
86
+ )
87
+ }
88
+ }
89
+ . tabViewStyle ( PageTabViewStyle ( indexDisplayMode: . never) )
90
+ . simultaneousGesture (
50
91
DragGesture ( )
51
92
. onChanged { value in
52
- hasDraggedTheImage = true
53
- if scale == 1 {
54
- if dragInitialTime == nil {
55
- dragInitialTime = Date ( )
56
- }
57
- let translation = value. translation. height
58
- dragOffset. height = translation
59
- backgroundOpacity = 1 - abs( translation) * 0.001
93
+ dragOffset = value. translation. height
94
+ let screenHeight = UIScreen . main. bounds. height
95
+ let progress = abs ( dragOffset) / screenHeight / 2
96
+ withAnimation {
97
+ backgroundOpacity = 1 - progress
60
98
}
61
99
}
62
- . onEnded { value in
63
- if scale == 1 {
64
- let diff = differenceBeetwenInitialDragTime ( and: Date ( ) )
65
- if diff <= 150 || abs ( dragOffset. height) >= UIScreen . main. bounds. height * 0.4 {
66
- hideView ( )
67
- } else {
68
- withAnimation {
69
- backgroundOpacity = 1
70
- }
71
- dragOffset = . zero
100
+ . onEnded { _ in
101
+ if abs ( dragOffset) < 200 {
102
+ withAnimation {
103
+ dragOffset = 0
104
+ backgroundOpacity = 1
105
+ }
106
+ } else {
107
+ withAnimation {
108
+ isVisible = false
72
109
}
73
- dragInitialTime = nil
74
110
}
75
111
}
76
112
)
77
- . simultaneousGesture (
78
- MagnificationGesture ( )
79
- . updating ( $scale, body: { value, state, _ in
80
- guard value > 0.7 else { return }
81
- state = value
82
- } )
83
- )
84
- }
85
-
86
- var image : some View {
87
- PuraceImageView ( url: url)
88
- . scaledToFit ( )
89
- . offset ( x: dragOffset. width, y: dragOffset. height)
90
- . animation ( hasDraggedTheImage ? . easeOut( duration: 0.35 ) : . none)
91
- . scaleEffect ( scale)
92
- . frame ( maxHeight: maximumImageHeight)
93
- }
94
-
95
- public var body : some View {
96
- ZStack {
97
- backgroundColor
113
+ . onChange ( of: currentIndex) { _ in
114
+ dragOffset = . zero
115
+ }
116
+
117
+ } . background (
118
+ PuraceStyle . Color. X1
119
+ . edgesIgnoringSafeArea ( . all)
98
120
. opacity ( backgroundOpacity)
99
- image
100
- draggableArea
101
- }
102
- . edgesIgnoringSafeArea ( . all)
103
- . transition ( . opacity. animation ( . linear) )
104
- }
105
- }
106
-
107
- extension PuraceImageViewer {
108
- private func hideImage( ) {
109
- withAnimation {
110
- if dragOffset. height > 0 {
111
- dragOffset. height = UIScreen . main. bounds. height
112
- } else {
113
- dragOffset. height = - UIScreen. main. bounds. height
114
- }
115
- }
121
+ )
116
122
}
117
123
118
- private func hideView( ) {
119
- hideImage ( )
120
- withAnimation {
121
- backgroundOpacity = 0
122
- }
123
- DispatchQueue . main. asyncAfter ( deadline: . now( ) + 0.25 ) {
124
- isVisible = false
125
- }
124
+ public var body : some View {
125
+ viewer
126
126
}
127
127
}
0 commit comments