Skip to content

Commit

Permalink
Merge pull request #21 from payan-app/image
Browse files Browse the repository at this point in the history
feat: add image viewer
  • Loading branch information
juandahurt authored Jun 29, 2022
2 parents fbc5ec8 + 4cdb103 commit dcda933
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 0 deletions.
4 changes: 4 additions & 0 deletions PuraceDemo/PuraceDemo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
2F5EFD3C284D23E3005D130A /* HorizontalGridExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F5EFD3B284D23E2005D130A /* HorizontalGridExample.swift */; };
2F6267AE2857B6960063A630 /* AccordionExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F6267AD2857B6960063A630 /* AccordionExample.swift */; };
2F77A234283C4AC700F143FB /* ImageExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F77A233283C4AC700F143FB /* ImageExample.swift */; };
2F7EC3C72867656200D5DDC6 /* ImageViewerExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F7EC3C62867656200D5DDC6 /* ImageViewerExample.swift */; };
2F9321B3282EE49E003DA929 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F9321B2282EE49E003DA929 /* AppDelegate.swift */; };
2F9321B5282EE49E003DA929 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F9321B4282EE49E003DA929 /* SceneDelegate.swift */; };
2F9321B7282EE49E003DA929 /* MenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F9321B6282EE49E003DA929 /* MenuView.swift */; };
Expand All @@ -38,6 +39,7 @@
2F5EFD3B284D23E2005D130A /* HorizontalGridExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HorizontalGridExample.swift; sourceTree = "<group>"; };
2F6267AD2857B6960063A630 /* AccordionExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccordionExample.swift; sourceTree = "<group>"; };
2F77A233283C4AC700F143FB /* ImageExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageExample.swift; sourceTree = "<group>"; };
2F7EC3C62867656200D5DDC6 /* ImageViewerExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageViewerExample.swift; sourceTree = "<group>"; };
2F9321AF282EE49E003DA929 /* PuraceDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PuraceDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
2F9321B2282EE49E003DA929 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
2F9321B4282EE49E003DA929 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -94,6 +96,7 @@
2FA9867A28373DD3000DB409 /* SnackbarExample.swift */,
2F27BC9C284814B600B5AC8D /* TabExample.swift */,
2F5EFD3B284D23E2005D130A /* HorizontalGridExample.swift */,
2F7EC3C62867656200D5DDC6 /* ImageViewerExample.swift */,
);
path = Complex;
sourceTree = "<group>";
Expand Down Expand Up @@ -217,6 +220,7 @@
2F1F7D7128317E0700AA30DB /* CollectionCardExample.swift in Sources */,
2F1F7D7328318D9900AA30DB /* TextExample.swift in Sources */,
2F9321B7282EE49E003DA929 /* MenuView.swift in Sources */,
2F7EC3C72867656200D5DDC6 /* ImageViewerExample.swift in Sources */,
2F9321B3282EE49E003DA929 /* AppDelegate.swift in Sources */,
2F6267AE2857B6960063A630 /* AccordionExample.swift in Sources */,
2F569939285FB93500F2D4D3 /* ModalExample.swift in Sources */,
Expand Down
26 changes: 26 additions & 0 deletions PuraceDemo/PuraceDemo/Examples/Complex/ImageViewerExample.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// ImageViewerExample.swift
// PuraceDemo
//
// Created by Juan Hurtado on 25/06/22.
//

import Foundation
import SwiftUI
import Purace

struct ImageViewerExample: View {
@State var isVisible = false

var body: some View {
VStack {
PuraceButtonView("Mostrar imagen") {
isVisible.toggle()
}
Spacer()
}.imageViewer(
url: URL(string: "https://payan-dev-images.s3.us-east-2.amazonaws.com/santo-domingo.jpg"),
isVisible: $isVisible
)
}
}
3 changes: 3 additions & 0 deletions PuraceDemo/PuraceDemo/MenuView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ struct MenuView: View {
NavigationLink("Tab") {
TabExample()
}
NavigationLink("Image Viewer") {
ImageViewerExample()
}
}
}
.navigationTitle("Purace")
Expand Down
5 changes: 5 additions & 0 deletions Sources/Purace/Styles/PuraceStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ public struct PuraceStyle {
public static let S7 = SwiftUI.Color(hex: "D4CAC6") ?? .orange
public static let S8 = SwiftUI.Color(hex: "C8D0CA") ?? .orange

public static let X1 = SwiftUI.Color(hex: "272627") ?? .gray
public static let X2 = SwiftUI.Color(hex: "3F402D") ?? .gray
public static let X3 = SwiftUI.Color(hex: "3B140E") ?? .gray
public static let X4 = SwiftUI.Color(hex: "17293E") ?? .gray

public static let allSkeletons: [SwiftUI.Color] = [Color.S1, Color.S2, Color.S3, Color.S4, Color.S5, Color.S6, Color.S7, Color.S8]
}

Expand Down
127 changes: 127 additions & 0 deletions Sources/Purace/Views/Complex/Image Viewer/PuraceImageViewer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
//
// PuraceImageViewer.swift
//
//
// Created by Juan Hurtado on 25/06/22.
//

import Foundation
import SwiftUI
import Kingfisher

public struct PuraceImageViewer: View {
@Binding var isVisible: Bool
let backgroundColor: Color
let url: URL?
@State var opacity: Double = 0
@State var dragOffset: CGSize = .zero
@State var backgroundOpacity: Double = 1
@State var hasDraggedTheImage = false
@State var dragInitialTime: Date?

@GestureState var scale: CGFloat = 1

private let maximumImageHeight = UIScreen.main.bounds.height * 0.65

public init(url: URL?, isVisible: Binding<Bool>) {
let colors: [Color] = [
PuraceStyle.Color.X1,
PuraceStyle.Color.X2,
PuraceStyle.Color.X3,
PuraceStyle.Color.X4
]
backgroundColor = colors.randomElement()!
self.url = url
self._isVisible = isVisible
}

private func differenceBeetwenInitialDragTime(and date: Date) -> Double {
guard let dragInitialTime = dragInitialTime else {
return .zero
}
return date.timeIntervalSince(dragInitialTime) * 1000
}

var draggableArea: some View {
Color.black
.animation(.none)
.opacity(0.001)
.gesture(
DragGesture()
.onChanged { value in
hasDraggedTheImage = true
if scale == 1 {
if dragInitialTime == nil {
dragInitialTime = Date()
}
let translation = value.translation.height
dragOffset.height = translation
backgroundOpacity = 1 - abs(translation) * 0.001
}
}
.onEnded { value in
if scale == 1 {
let diff = differenceBeetwenInitialDragTime(and: Date())
if diff <= 150 || abs(dragOffset.height) >= UIScreen.main.bounds.height * 0.4 {
hideView()
} else {
withAnimation {
backgroundOpacity = 1
}
dragOffset = .zero
}
dragInitialTime = nil
}
}
)
.simultaneousGesture(
MagnificationGesture()
.updating($scale, body: { value, state, _ in
guard value > 0.7 else { return }
state = value
})
)
}

var image: some View {
PuraceImageView(url: url)
.scaledToFit()
.offset(x: dragOffset.width, y: dragOffset.height)
.animation(hasDraggedTheImage ? .easeOut(duration: 0.35) : .none)
.scaleEffect(scale)
.frame(maxHeight: maximumImageHeight)
}

public var body: some View {
ZStack {
backgroundColor
.opacity(backgroundOpacity)
image
draggableArea
}
.edgesIgnoringSafeArea(.all)
.transition(.opacity.animation(.linear))
}
}

extension PuraceImageViewer {
private func hideImage() {
withAnimation {
if dragOffset.height > 0 {
dragOffset.height = UIScreen.main.bounds.height
} else {
dragOffset.height = -UIScreen.main.bounds.height
}
}
}

private func hideView() {
hideImage()
withAnimation {
backgroundOpacity = 0
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
isVisible = false
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// PuraceImageViewerModifier.swift
//
//
// Created by Juan Hurtado on 26/06/22.
//

import Foundation
import SwiftUI

public struct PuraceImageViewerModifier: ViewModifier {
let url: URL?
@Binding var isVisible: Bool

public init(url: URL?, isVisible: Binding<Bool>) {
self.url = url
self._isVisible = isVisible
}

public func body(content: Content) -> some View {
ZStack {
content
if isVisible {
PuraceImageViewer(url: url, isVisible: $isVisible)
}
}
}
}

public extension View {
func imageViewer(url: URL?, isVisible: Binding<Bool>) -> some View {
modifier(PuraceImageViewerModifier(url: url, isVisible: isVisible))
}
}

0 comments on commit dcda933

Please sign in to comment.