commit 2e34230119226e7b44882224372ee762f6aeed8f
parent cad89525b725c34f46f2096c44cb8c67fe8bab11
Author: William Casarin <jb55@jb55.com>
Date: Thu, 23 Mar 2023 08:54:25 -0600
Clean up image views
Diffstat:
10 files changed, 223 insertions(+), 156 deletions(-)
diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj
@@ -222,6 +222,9 @@
4CF0ABEE29844B5500D66079 /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABED29844B5500D66079 /* AnyEncodable.swift */; };
4CF0ABF029857E9200D66079 /* Bech32Object.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABEF29857E9200D66079 /* Bech32Object.swift */; };
4CF0ABF62985CD5500D66079 /* UserSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF0ABF52985CD5500D66079 /* UserSearch.swift */; };
+ 4CFF8F6329CC9AD7008DB934 /* ImageContextMenuModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF8F6229CC9AD7008DB934 /* ImageContextMenuModifier.swift */; };
+ 4CFF8F6729CC9E3A008DB934 /* ImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF8F6629CC9E3A008DB934 /* ImageView.swift */; };
+ 4CFF8F6929CC9ED1008DB934 /* ImageContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF8F6829CC9ED1008DB934 /* ImageContainerView.swift */; };
4FE60CDD295E1C5E00105A1F /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE60CDC295E1C5E00105A1F /* Wallet.swift */; };
50A50A8D29A09E1C00C01BE7 /* RequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50A50A8C29A09E1C00C01BE7 /* RequestTests.swift */; };
5C513FBA297F72980072348F /* CustomPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C513FB9297F72980072348F /* CustomPicker.swift */; };
@@ -595,6 +598,9 @@
4CF0ABED29844B5500D66079 /* AnyEncodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyEncodable.swift; sourceTree = "<group>"; };
4CF0ABEF29857E9200D66079 /* Bech32Object.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bech32Object.swift; sourceTree = "<group>"; };
4CF0ABF52985CD5500D66079 /* UserSearch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSearch.swift; sourceTree = "<group>"; };
+ 4CFF8F6229CC9AD7008DB934 /* ImageContextMenuModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageContextMenuModifier.swift; sourceTree = "<group>"; };
+ 4CFF8F6629CC9E3A008DB934 /* ImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageView.swift; sourceTree = "<group>"; };
+ 4CFF8F6829CC9ED1008DB934 /* ImageContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageContainerView.swift; sourceTree = "<group>"; };
4FE60CDC295E1C5E00105A1F /* Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wallet.swift; sourceTree = "<group>"; };
50A50A8C29A09E1C00C01BE7 /* RequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestTests.swift; sourceTree = "<group>"; };
5C513FB9297F72980072348F /* CustomPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomPicker.swift; sourceTree = "<group>"; };
@@ -797,6 +803,7 @@
4C75EFA227FA576C0006080F /* Views */ = {
isa = PBXGroup;
children = (
+ 4CFF8F6129CC9A80008DB934 /* Images */,
4CCEB7AC29B53D180078AA28 /* Search */,
4C30AC7029A5676F00E2BD5A /* Notifications */,
4CE0E2B029A3DF4700DB4CA2 /* Timeline */,
@@ -834,10 +841,6 @@
9CA876E129A00CE90003B9A3 /* AttachMediaUtility.swift */,
9C83F89229A937B900136C08 /* TextViewWrapper.swift */,
4CEE2AF8280B2EAC00AB5EEF /* PowView.swift */,
- 4CEE2AF6280B2DEA00AB5EEF /* ProfileName.swift */,
- 4C285C892838B985008A31F1 /* ProfilePictureSelector.swift */,
- 4CEE2AF2280B25C500AB5EEF /* ProfilePicView.swift */,
- 4C8682862814DE470026224F /* ProfileView.swift */,
4C3AC7A42836987600E1F516 /* MainTabView.swift */,
4C363A8B28236B92006E126D /* PubkeyView.swift */,
4CACA9D4280C31E100D9BBE8 /* ReplyView.swift */,
@@ -959,6 +962,10 @@
4CB9D4A52992D01900A9A7E4 /* Profile */ = {
isa = PBXGroup;
children = (
+ 4CEE2AF6280B2DEA00AB5EEF /* ProfileName.swift */,
+ 4C285C892838B985008A31F1 /* ProfilePictureSelector.swift */,
+ 4CEE2AF2280B25C500AB5EEF /* ProfilePicView.swift */,
+ 4C8682862814DE470026224F /* ProfileView.swift */,
4CB9D4A62992D02B00A9A7E4 /* ProfileNameView.swift */,
4CB9D4A82992D2F400A9A7E4 /* FollowsYou.swift */,
4C9F18E329ABDE6D008C55EC /* MaybeAnonPfpView.swift */,
@@ -1177,6 +1184,16 @@
path = Posting;
sourceTree = "<group>";
};
+ 4CFF8F6129CC9A80008DB934 /* Images */ = {
+ isa = PBXGroup;
+ children = (
+ 4CFF8F6229CC9AD7008DB934 /* ImageContextMenuModifier.swift */,
+ 4CFF8F6629CC9E3A008DB934 /* ImageView.swift */,
+ 4CFF8F6829CC9ED1008DB934 /* ImageContainerView.swift */,
+ );
+ path = Images;
+ sourceTree = "<group>";
+ };
7C0F392D29B57C8F0039859C /* Extensions */ = {
isa = PBXGroup;
children = (
@@ -1434,6 +1451,7 @@
4CE4F9E328528C5200C00DD9 /* AddRelayView.swift in Sources */,
4C363A9A28283854006E126D /* Reply.swift in Sources */,
BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */,
+ 4CFF8F6729CC9E3A008DB934 /* ImageView.swift in Sources */,
4C90BD18283A9EE5008EE7EF /* LoginView.swift in Sources */,
4CB8838B296F6E1E00DC99E7 /* NIP05Badge.swift in Sources */,
4C3EA66828FF5F9900C48A62 /* hex.c in Sources */,
@@ -1488,6 +1506,7 @@
4C363A94282704FA006E126D /* Post.swift in Sources */,
4C216F32286E388800040376 /* DMChatView.swift in Sources */,
4CAAD8AD298851D000060CEA /* AccountDeletion.swift in Sources */,
+ 4CFF8F6329CC9AD7008DB934 /* ImageContextMenuModifier.swift in Sources */,
4C54AA0A29A55429003E4487 /* EventGroup.swift in Sources */,
4C3EA67928FF7ABF00C48A62 /* list.c in Sources */,
4C64987E286D082C00EAE2B3 /* DirectMessagesModel.swift in Sources */,
@@ -1547,6 +1566,7 @@
4C3EA63D28FF52D600C48A62 /* bolt11.c in Sources */,
4C9BB83129C0ED4F00FC4E37 /* DisplayName.swift in Sources */,
7CFF6317299FEFE5005D382A /* SelectableText.swift in Sources */,
+ 4CFF8F6929CC9ED1008DB934 /* ImageContainerView.swift in Sources */,
4C54AA0729A540BA003E4487 /* NotificationsModel.swift in Sources */,
4CB55EF3295E5D59007FD187 /* RecommendedRelayView.swift in Sources */,
4CF0ABEC29844B4700D66079 /* AnyDecodable.swift in Sources */,
diff --git a/damus/Components/ImageCarousel.swift b/damus/Components/ImageCarousel.swift
@@ -31,158 +31,9 @@ struct ShareSheet: UIViewControllerRepresentable {
}
}
-struct ImageContextMenuModifier: ViewModifier {
- let url: URL?
- let image: UIImage?
- @Binding var showShareSheet: Bool
-
- func body(content: Content) -> some View {
- return content.contextMenu {
- Button {
- UIPasteboard.general.url = url
- } label: {
- Label(NSLocalizedString("Copy Image URL", comment: "Context menu option to copy the URL of an image into clipboard."), systemImage: "doc.on.doc")
- }
- if let someImage = image {
- Button {
- UIPasteboard.general.image = someImage
- } label: {
- Label(NSLocalizedString("Copy Image", comment: "Context menu option to copy an image into clipboard."), systemImage: "photo.on.rectangle")
- }
- Button {
- UIImageWriteToSavedPhotosAlbum(someImage, nil, nil, nil)
- } label: {
- Label(NSLocalizedString("Save Image", comment: "Context menu option to save an image."), systemImage: "square.and.arrow.down")
- }
- }
- Button {
- showShareSheet = true
- } label: {
- Label(NSLocalizedString("Share", comment: "Button to share an image."), systemImage: "square.and.arrow.up")
- }
- }
- }
-}
-private struct ImageContainerView: View {
-
- let url: URL?
-
- @State private var image: UIImage?
- @State private var showShareSheet = false
-
- private struct ImageHandler: ImageModifier {
- @Binding var handler: UIImage?
-
- func modify(_ image: UIImage) -> UIImage {
- handler = image
- return image
- }
- }
-
- var body: some View {
-
- KFAnimatedImage(url)
- .imageContext(.note)
- .configure { view in
- view.framePreloadCount = 3
- }
- .imageModifier(ImageHandler(handler: $image))
- .clipped()
- .modifier(ImageContextMenuModifier(url: url, image: image, showShareSheet: $showShareSheet))
- .sheet(isPresented: $showShareSheet) {
- ShareSheet(activityItems: [url])
- }
- }
-}
-struct ImageView: View {
-
- let urls: [URL?]
-
- @Environment(\.presentationMode) var presentationMode
-
- @State private var selectedIndex = 0
- @State var showMenu = true
-
- var navBarView: some View {
- VStack {
- HStack {
- /*
- Text(urls[selectedIndex]?.lastPathComponent ?? "")
- .bold()
- */
-
- Spacer()
-
- Button(action: {
- presentationMode.wrappedValue.dismiss()
- }, label: {
- Image(systemName: "xmark")
- })
- }
- .padding()
- }
- }
-
- var tabViewIndicator: some View {
- HStack(spacing: 10) {
- ForEach(urls.indices, id: \.self) { index in
- Capsule()
- .fill(index == selectedIndex ? Color(UIColor.label) : Color.secondary)
- .frame(width: 7, height: 7)
- }
- }
- .padding()
- .background(.regularMaterial)
- .clipShape(Capsule())
- }
-
- var body: some View {
- ZStack {
- Color(.systemBackground)
- .ignoresSafeArea()
-
- TabView(selection: $selectedIndex) {
- ForEach(urls.indices, id: \.self) { index in
- ZoomableScrollView {
- ImageContainerView(url: urls[index])
- .aspectRatio(contentMode: .fit)
- .padding(.top, Theme.safeAreaInsets?.top)
- .padding(.bottom, Theme.safeAreaInsets?.bottom)
- }
- .modifier(SwipeToDismissModifier(minDistance: 50, onDismiss: {
- presentationMode.wrappedValue.dismiss()
- }))
- .ignoresSafeArea()
- .tag(index)
- }
- }
- .ignoresSafeArea()
- .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
- .gesture(TapGesture(count: 2).onEnded {
- // Prevents menu from hiding on double tap
- })
- .gesture(TapGesture(count: 1).onEnded {
- showMenu.toggle()
- })
- .overlay(
- VStack {
- if showMenu {
- navBarView
- Spacer()
-
- if (urls.count > 1) {
- tabViewIndicator
- }
- }
- }
- .animation(.easeInOut, value: showMenu)
- .padding(.bottom, Theme.safeAreaInsets?.bottom)
- )
- }
- }
-}
+
struct ImageCarousel: View {
var urls: [URL]
diff --git a/damus/Views/Images/ImageContainerView.swift b/damus/Views/Images/ImageContainerView.swift
@@ -0,0 +1,51 @@
+//
+// CarouselImageContainerView.swift
+// damus
+//
+// Created by William Casarin on 2023-03-23.
+//
+
+import SwiftUI
+import Kingfisher
+
+
+// lots of overlap between this and ImageContainerView
+struct ImageContainerView: View {
+
+ let url: URL?
+
+ @State private var image: UIImage?
+ @State private var showShareSheet = false
+
+ private struct ImageHandler: ImageModifier {
+ @Binding var handler: UIImage?
+
+ func modify(_ image: UIImage) -> UIImage {
+ handler = image
+ return image
+ }
+ }
+
+ var body: some View {
+
+ KFAnimatedImage(url)
+ .imageContext(.note)
+ .configure { view in
+ view.framePreloadCount = 3
+ }
+ .imageModifier(ImageHandler(handler: $image))
+ .clipped()
+ .modifier(ImageContextMenuModifier(url: url, image: image, showShareSheet: $showShareSheet))
+ .sheet(isPresented: $showShareSheet) {
+ ShareSheet(activityItems: [url])
+ }
+ }
+}
+
+let test_image_url = URL(string: "https://jb55.com/red-me.jpg")!
+
+struct ImageContainerView_Previews: PreviewProvider {
+ static var previews: some View {
+ ImageContainerView(url: test_image_url)
+ }
+}
diff --git a/damus/Views/Images/ImageContextMenuModifier.swift b/damus/Views/Images/ImageContextMenuModifier.swift
@@ -0,0 +1,43 @@
+//
+// ImageContextMenuModifier.swift
+// damus
+//
+// Created by William Casarin on 2023-03-23.
+//
+
+import Foundation
+import SwiftUI
+import UIKit
+
+struct ImageContextMenuModifier: ViewModifier {
+ let url: URL?
+ let image: UIImage?
+ @Binding var showShareSheet: Bool
+
+ func body(content: Content) -> some View {
+ return content.contextMenu {
+ Button {
+ UIPasteboard.general.url = url
+ } label: {
+ Label(NSLocalizedString("Copy Image URL", comment: "Context menu option to copy the URL of an image into clipboard."), systemImage: "doc.on.doc")
+ }
+ if let someImage = image {
+ Button {
+ UIPasteboard.general.image = someImage
+ } label: {
+ Label(NSLocalizedString("Copy Image", comment: "Context menu option to copy an image into clipboard."), systemImage: "photo.on.rectangle")
+ }
+ Button {
+ UIImageWriteToSavedPhotosAlbum(someImage, nil, nil, nil)
+ } label: {
+ Label(NSLocalizedString("Save Image", comment: "Context menu option to save an image."), systemImage: "square.and.arrow.down")
+ }
+ }
+ Button {
+ showShareSheet = true
+ } label: {
+ Label(NSLocalizedString("Share", comment: "Button to share an image."), systemImage: "square.and.arrow.up")
+ }
+ }
+ }
+}
diff --git a/damus/Views/Images/ImageView.swift b/damus/Views/Images/ImageView.swift
@@ -0,0 +1,102 @@
+//
+// ImageView.swift
+// damus
+//
+// Created by William Casarin on 2023-03-23.
+//
+
+import SwiftUI
+
+struct ImageView: View {
+
+ let urls: [URL?]
+
+ @Environment(\.presentationMode) var presentationMode
+
+ @State private var selectedIndex = 0
+ @State var showMenu = true
+
+ var navBarView: some View {
+ VStack {
+ HStack {
+ /*
+ Text(urls[selectedIndex]?.lastPathComponent ?? "")
+ .bold()
+ */
+
+ Spacer()
+
+ Button(action: {
+ presentationMode.wrappedValue.dismiss()
+ }, label: {
+ Image(systemName: "xmark")
+ })
+ }
+ .padding()
+ }
+ }
+
+ var tabViewIndicator: some View {
+ HStack(spacing: 10) {
+ ForEach(urls.indices, id: \.self) { index in
+ Capsule()
+ .fill(index == selectedIndex ? Color(UIColor.label) : Color.secondary)
+ .frame(width: 7, height: 7)
+ }
+ }
+ .padding()
+ .background(.regularMaterial)
+ .clipShape(Capsule())
+ }
+
+ var body: some View {
+ ZStack {
+ Color(.systemBackground)
+ .ignoresSafeArea()
+
+ TabView(selection: $selectedIndex) {
+ ForEach(urls.indices, id: \.self) { index in
+ ZoomableScrollView {
+ ImageContainerView(url: urls[index])
+ .aspectRatio(contentMode: .fit)
+ .padding(.top, Theme.safeAreaInsets?.top)
+ .padding(.bottom, Theme.safeAreaInsets?.bottom)
+ }
+ .modifier(SwipeToDismissModifier(minDistance: 50, onDismiss: {
+ presentationMode.wrappedValue.dismiss()
+ }))
+ .ignoresSafeArea()
+ .tag(index)
+ }
+ }
+ .ignoresSafeArea()
+ .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
+ .gesture(TapGesture(count: 2).onEnded {
+ // Prevents menu from hiding on double tap
+ })
+ .gesture(TapGesture(count: 1).onEnded {
+ showMenu.toggle()
+ })
+ .overlay(
+ VStack {
+ if showMenu {
+ navBarView
+ Spacer()
+
+ if (urls.count > 1) {
+ tabViewIndicator
+ }
+ }
+ }
+ .animation(.easeInOut, value: showMenu)
+ .padding(.bottom, Theme.safeAreaInsets?.bottom)
+ )
+ }
+ }
+}
+
+struct ImageView_Previews: PreviewProvider {
+ static var previews: some View {
+ ImageView(urls: [URL(string: "https://jb55.com/red-me.jpg")])
+ }
+}
diff --git a/damus/Views/ProfileName.swift b/damus/Views/Profile/ProfileName.swift
diff --git a/damus/Views/ProfilePicView.swift b/damus/Views/Profile/ProfilePicView.swift
diff --git a/damus/Views/ProfilePictureSelector.swift b/damus/Views/Profile/ProfilePictureSelector.swift
diff --git a/damus/Views/ProfileView.swift b/damus/Views/Profile/ProfileView.swift
diff --git a/damus/Views/ProfileZoomView.swift b/damus/Views/ProfileZoomView.swift
@@ -7,7 +7,7 @@
import SwiftUI
import Kingfisher
-private struct ImageContainerView: View {
+struct ProfileImageContainerView: View {
let url: URL?
@@ -68,7 +68,7 @@ struct ProfileZoomView: View {
.ignoresSafeArea()
ZoomableScrollView {
- ImageContainerView(url: get_profile_url(picture: nil, pubkey: pubkey, profiles: profiles))
+ ProfileImageContainerView(url: get_profile_url(picture: nil, pubkey: pubkey, profiles: profiles))
.aspectRatio(contentMode: .fit)
.padding(.top, Theme.safeAreaInsets?.top)
.padding(.bottom, Theme.safeAreaInsets?.bottom)