commit 8ffa8446b61cbc0382cc56e7db6cad0fc85fcaa1
parent fb1f99e7283b2e1cc302fb94cde8cb045e6ffbfe
Author: Swift <scoder1747@gmail.com>
Date: Wed, 18 Jan 2023 10:07:03 -0800
Image Pinch Zooming
Changelog-Added: Added pinch to zoom on images
Diffstat:
7 files changed, 256 insertions(+), 33 deletions(-)
diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj
@@ -148,6 +148,7 @@
4CEE2B02280B39E800AB5EEF /* EventActionBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */; };
4FE60CDD295E1C5E00105A1F /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE60CDC295E1C5E00105A1F /* Wallet.swift */; };
647D9A8D2968520300A295DE /* SideMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647D9A8C2968520300A295DE /* SideMenuView.swift */; };
+ 6439E014296790CF0020672B /* ProfileZoomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6439E013296790CF0020672B /* ProfileZoomView.swift */; };
64FBD06F296255C400D9D3B2 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64FBD06E296255C400D9D3B2 /* Theme.swift */; };
6C7DE41F2955169800E66263 /* Vault in Frameworks */ = {isa = PBXBuildFile; productRef = 6C7DE41E2955169800E66263 /* Vault */; };
7C45AE6D297352F90031D7BC /* SVGKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7C45AE6C297352F90031D7BC /* SVGKit */; };
@@ -356,6 +357,7 @@
4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventActionBar.swift; sourceTree = "<group>"; };
4FE60CDC295E1C5E00105A1F /* Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wallet.swift; sourceTree = "<group>"; };
647D9A8C2968520300A295DE /* SideMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideMenuView.swift; sourceTree = "<group>"; };
+ 6439E013296790CF0020672B /* ProfileZoomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileZoomView.swift; sourceTree = "<group>"; };
64FBD06E296255C400D9D3B2 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
7C45AE70297353390031D7BC /* KFImageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KFImageModel.swift; sourceTree = "<group>"; };
9609F057296E220800069BF3 /* BannerImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BannerImageView.swift; sourceTree = "<group>"; };
@@ -514,8 +516,8 @@
4C216F33286F5ACD00040376 /* DMView.swift */,
E990020E2955F837003BBC5A /* EditMetadataView.swift */,
3169CAE4294E699400EE4006 /* Empty Views */,
- 4CEE2AF0280B216B00AB5EEF /* EventDetailView.swift */,
4C75EFB82804A2740006080F /* EventView.swift */,
+ 4CEE2AF0280B216B00AB5EEF /* EventDetailView.swift */,
4C3AC79E2833115300E1F516 /* FollowButtonView.swift */,
4C3AC79C2833036D00E1F516 /* FollowingView.swift */,
4C90BD17283A9EE5008EE7EF /* LoginView.swift */,
@@ -547,6 +549,7 @@
647D9A8C2968520300A295DE /* SideMenuView.swift */,
9609F057296E220800069BF3 /* BannerImageView.swift */,
4CB8838E296F781C00DC99E7 /* ReactionsView.swift */,
+ 6439E013296790CF0020672B /* ProfileZoomView.swift */,
);
path = Views;
sourceTree = "<group>";
@@ -949,6 +952,7 @@
4C5F9114283D694D0052CD1C /* FollowTarget.swift in Sources */,
4CB8838629656C8B00DC99E7 /* NIP05.swift in Sources */,
4C5C7E6A284EDE2E00A22DF5 /* SearchResultsView.swift in Sources */,
+ 6439E014296790CF0020672B /* ProfileZoomView.swift in Sources */,
4CE6DF1627F8DEBF00C66700 /* RelayConnection.swift in Sources */,
4C3BEFD6281D995700B3DE84 /* ActionBarModel.swift in Sources */,
4C363AA428296DEE006E126D /* SearchModel.swift in Sources */,
diff --git a/damus/Components/ImageCarousel.swift b/damus/Components/ImageCarousel.swift
@@ -64,9 +64,50 @@ struct ImageContextMenuModifier: ViewModifier {
}
}
-struct ImageViewer: View {
+struct ImageView: View {
let urls: [URL]
+ @Environment(\.presentationMode) var presentationMode
+ //let pubkey: String
+ //let profiles: Profiles
+
+ @GestureState private var scaleState: CGFloat = 1
+ @GestureState private var offsetState = CGSize.zero
+
+ @State private var offset = CGSize.zero
+ @State private var scale: CGFloat = 1
+
+ func resetStatus(){
+ self.offset = CGSize.zero
+ self.scale = 1
+ }
+
+ var zoomGesture: some Gesture {
+ MagnificationGesture()
+ .updating($scaleState) { currentState, gestureState, _ in
+ gestureState = currentState
+ }
+ .onEnded { value in
+ scale *= value
+ }
+ }
+
+ var dragGesture: some Gesture {
+ DragGesture()
+ .updating($offsetState) { currentState, gestureState, _ in
+ gestureState = currentState.translation
+ }.onEnded { value in
+ offset.height += value.translation.height
+ offset.width += value.translation.width
+ }
+ }
+
+ var doubleTapGesture : some Gesture {
+ TapGesture(count: 2).onEnded { value in
+ resetStatus()
+ }
+ }
+
private struct ImageHandler: ImageModifier {
@Binding var handler: UIImage?
@@ -86,30 +127,61 @@ struct ImageViewer: View {
}
var body: some View {
- TabView {
- ForEach(urls, id: \.absoluteString) { url in
- VStack{
- Text(url.lastPathComponent)
-
- KFAnimatedImage(url)
- .configure { view in
- view.framePreloadCount = 3
- }
- .cacheOriginalImage()
- .imageModifier(ImageHandler(handler: $image))
- .loadDiskFileSynchronously()
- .scaleFactor(UIScreen.main.scale)
- .fade(duration: 0.1)
- .aspectRatio(contentMode: .fit)
- .tabItem {
- Text(url.absoluteString)
- }
- .id(url.absoluteString)
- .modifier(ImageContextMenuModifier(url: url, image: image, showShareSheet: $showShareSheet))
- .sheet(isPresented: $showShareSheet) {
- ShareSheet(activityItems: [url])
- }
-
+ ZStack(alignment: .topLeading) {
+ Color("DamusDarkGrey") // Or Color("DamusBlack")
+ .edgesIgnoringSafeArea(.all)
+
+ HStack() {
+ Button {
+ presentationMode.wrappedValue.dismiss()
+ } label: {
+ Image(systemName: "xmark")
+ .foregroundColor(.white)
+ .font(.largeTitle)
+ .frame(width: 40, height: 40)
+ .padding(20)
+ }
+ }
+ .zIndex(1)
+
+ VStack(alignment: .center) {
+ //Spacer()
+ //.frame(height: 120)
+
+ TabView {
+ ForEach(urls, id: \.absoluteString) { url in
+ VStack{
+ //Color("DamusDarkGrey")
+ Text(url.lastPathComponent)
+ .foregroundColor(Color("DamusWhite"))
+
+ KFAnimatedImage(url)
+ .configure { view in
+ view.framePreloadCount = 3
+ }
+ .cacheOriginalImage()
+ .imageModifier(ImageHandler(handler: $image))
+ .loadDiskFileSynchronously()
+ .scaleFactor(UIScreen.main.scale)
+ .fade(duration: 0.1)
+ .aspectRatio(contentMode: .fit)
+ .tabItem {
+ Text(url.absoluteString)
+ }
+ .id(url.absoluteString)
+ .modifier(ImageContextMenuModifier(url: url, image: image, showShareSheet: $showShareSheet))
+ .sheet(isPresented: $showShareSheet) {
+ ShareSheet(activityItems: [url])
+ }
+ //.padding(100)
+ .scaledToFit()
+ .scaleEffect(self.scale * scaleState)
+ .offset(x: offset.width + offsetState.width, y: offset.height + offsetState.height)
+ .gesture(SimultaneousGesture(zoomGesture, dragGesture))
+ .gesture(doubleTapGesture)
+
+ }.padding(.bottom, 50) // Ensure carousel appears beneath
+ }
}
}
}
@@ -151,8 +223,8 @@ struct ImageCarousel: View {
}
}
.cornerRadius(10)
- .sheet(isPresented: $open_sheet) {
- ImageViewer(urls: urls)
+ .fullScreenCover(isPresented: $open_sheet) {
+ ImageView(urls: urls)
}
.frame(height: 200)
.onTapGesture {
@@ -164,6 +236,6 @@ struct ImageCarousel: View {
struct ImageCarousel_Previews: PreviewProvider {
static var previews: some View {
- ImageCarousel(urls: [URL(string: "https://jb55.com/red-me.jpg")!])
+ ImageCarousel(urls: [URL(string: "https://jb55.com/red-me.jpg")!,URL(string: "https://jb55.com/red-me.jpg")!])
}
}
diff --git a/damus/Views/ImageView.swift b/damus/Views/ImageView.swift
@@ -0,0 +1,20 @@
+//
+// ImageView.swift
+// damus
+//
+// Created by user232838 on 1/5/23.
+//
+
+import SwiftUI
+
+struct ImageView: View {
+ var body: some View {
+ Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
+ }
+}
+
+struct ImageView_Previews: PreviewProvider {
+ static var previews: some View {
+ ImageView()
+ }
+}
diff --git a/damus/Views/MagnificationGestureView.swift b/damus/Views/MagnificationGestureView.swift
@@ -0,0 +1,33 @@
+//
+// MagnificationGestureView.swift
+// damus
+//
+// Created by user232838 on 1/5/23.
+//
+
+import SwiftUI
+
+struct MagnificationGestureView: View {
+
+ @GestureState var magnifyBy = 1.0
+
+ var magnification: some Gesture {
+ MagnificationGesture()
+ .updating($magnifyBy) { currentState, gestureState, transaction in
+ gestureState = currentState
+ }
+ }
+
+ var body: some View {
+ Circle()
+ .frame(width: 100, height: 100)
+ .scaleEffect(magnifyBy)
+ .gesture(magnification)
+ }
+}
+
+struct MagnificationGestureView_Previews: PreviewProvider {
+ static var previews: some View {
+ MagnificationGestureView()
+ }
+}
diff --git a/damus/Views/NoteContentView.swift b/damus/Views/NoteContentView.swift
@@ -53,7 +53,7 @@ func render_note_content(ev: NostrEvent, profiles: Profiles, privkey: String?) -
}
func is_image_url(_ url: URL) -> Bool {
- let str = url.lastPathComponent
+ let str = url.lastPathComponent.lowercased()
return str.hasSuffix("png") || str.hasSuffix("jpg") || str.hasSuffix("jpeg") || str.hasSuffix("gif")
}
diff --git a/damus/Views/ProfileView.swift b/damus/Views/ProfileView.swift
@@ -211,9 +211,8 @@ struct ProfileView: View {
.onTapGesture {
is_zoomed.toggle()
}
- .sheet(isPresented: $is_zoomed) {
- ProfilePicView(pubkey: profile.pubkey, size: zoom_size, highlight: .none, profiles: damus_state.profiles)
- }
+ .fullScreenCover(isPresented: $is_zoomed) {
+ ProfileZoomView(pubkey: profile.pubkey, profiles: damus_state.profiles) }
.offset(y: -(pfp_size/2.0)) // Increase if set a frame
Spacer()
diff --git a/damus/Views/ProfileZoomView.swift b/damus/Views/ProfileZoomView.swift
@@ -0,0 +1,95 @@
+//
+// ProfileZoomView.swift
+// damus
+//
+// Created by scoder1747 on 12/27/22.
+//
+import SwiftUI
+
+struct ProfileZoomView: View {
+
+ @Environment(\.presentationMode) var presentationMode
+ let pubkey: String
+ let profiles: Profiles
+
+ @GestureState private var scaleState: CGFloat = 1
+ @GestureState private var offsetState = CGSize.zero
+
+ @State private var offset = CGSize.zero
+ @State private var scale: CGFloat = 1
+
+ func resetStatus(){
+ self.offset = CGSize.zero
+ self.scale = 1
+ }
+
+ var zoomGesture: some Gesture {
+ MagnificationGesture()
+ .updating($scaleState) { currentState, gestureState, _ in
+ gestureState = currentState
+ }
+ .onEnded { value in
+ scale *= value
+ }
+ }
+
+ var dragGesture: some Gesture {
+ DragGesture()
+ .updating($offsetState) { currentState, gestureState, _ in
+ gestureState = currentState.translation
+ }.onEnded { value in
+ offset.height += value.translation.height
+ offset.width += value.translation.width
+ }
+ }
+
+ var doubleTapGesture : some Gesture {
+ TapGesture(count: 2).onEnded { value in
+ resetStatus()
+ }
+ }
+
+ var body: some View {
+ ZStack(alignment: .topLeading) {
+ Color("DamusDarkGrey") // Or Color("DamusBlack")
+ .edgesIgnoringSafeArea(.all)
+
+ HStack() {
+ Button {
+ presentationMode.wrappedValue.dismiss()
+ } label: {
+ Image(systemName: "xmark")
+ .foregroundColor(.white)
+ .font(.largeTitle)
+ .frame(width: 40, height: 40)
+ .padding(20)
+ }
+ }
+ .zIndex(1)
+
+ VStack(alignment: .center) {
+ Spacer()
+ .frame(height: 120)
+
+ ProfilePicView(pubkey: pubkey, size: 200.0, highlight: .none, profiles: profiles)
+ .padding(100)
+ .scaledToFit()
+ .scaleEffect(self.scale * scaleState)
+ .offset(x: offset.width + offsetState.width, y: offset.height + offsetState.height)
+ .gesture(SimultaneousGesture(zoomGesture, dragGesture))
+ .gesture(doubleTapGesture)
+
+ }
+ }
+ }
+}
+
+struct ProfileZoomView_Previews: PreviewProvider {
+ static let pubkey = "ca48854ac6555fed8e439ebb4fa2d928410e0eef13fa41164ec45aaaa132d846"
+
+ static var previews: some View {
+ ProfileZoomView(
+ pubkey: pubkey,
+ profiles: make_preview_profiles(pubkey))
+ }
+}