Skip to content

Commit

Permalink
#1164: first pass at new image viewer
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuatbrown committed Aug 14, 2024
1 parent 8bf33de commit 9465df8
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 14 deletions.
14 changes: 13 additions & 1 deletion Nos.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
03B4E6AC2C125D13006E5F59 /* FileStorageUploadResponseJSONTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B4E6AB2C125D13006E5F59 /* FileStorageUploadResponseJSONTests.swift */; };
03B4E6AE2C125D61006E5F59 /* FileStorageUploadResponseJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B4E6AD2C125D61006E5F59 /* FileStorageUploadResponseJSON.swift */; };
03B4E6AF2C125D61006E5F59 /* FileStorageUploadResponseJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B4E6AD2C125D61006E5F59 /* FileStorageUploadResponseJSON.swift */; };
03C8B4962C6D065900A07CCD /* ImageViewer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03C8B4952C6D065900A07CCD /* ImageViewer.swift */; };
03D1B4282C3C1A5D001778CD /* NostrIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03D1B4272C3C1A5D001778CD /* NostrIdentifier.swift */; };
03D1B4292C3C1AC9001778CD /* NostrIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03D1B4272C3C1A5D001778CD /* NostrIdentifier.swift */; };
03D1B42C2C3C1B0D001778CD /* TLVElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03D1B42B2C3C1B0D001778CD /* TLVElement.swift */; };
Expand Down Expand Up @@ -564,6 +565,7 @@
03B4E6A12C125CA1006E5F59 /* nostr_build_nip96_upload_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = nostr_build_nip96_upload_response.json; sourceTree = "<group>"; };
03B4E6AB2C125D13006E5F59 /* FileStorageUploadResponseJSONTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileStorageUploadResponseJSONTests.swift; sourceTree = "<group>"; };
03B4E6AD2C125D61006E5F59 /* FileStorageUploadResponseJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileStorageUploadResponseJSON.swift; sourceTree = "<group>"; };
03C8B4952C6D065900A07CCD /* ImageViewer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageViewer.swift; sourceTree = "<group>"; };
03D1B4272C3C1A5D001778CD /* NostrIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NostrIdentifier.swift; sourceTree = "<group>"; };
03D1B42B2C3C1B0D001778CD /* TLVElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TLVElement.swift; sourceTree = "<group>"; };
03ED93462C46C48400C8D443 /* JSONEventTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONEventTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1059,6 +1061,15 @@
path = Generated;
sourceTree = "<group>";
};
03C8B4902C6D061900A07CCD /* Images */ = {
isa = PBXGroup;
children = (
03C8B4952C6D065900A07CCD /* ImageViewer.swift */,
C92DF80729C25FA900400561 /* SquareImage.swift */,
);
path = Images;
sourceTree = "<group>";
};
03D1B42A2C3C1AE7001778CD /* NostrIdentifier */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1124,6 +1135,7 @@
5B79F6402BA11618002DA9BE /* Components */ = {
isa = PBXGroup;
children = (
03C8B4902C6D061900A07CCD /* Images */,
5B79F6122B98B145002DA9BE /* WizardNavigationStack.swift */,
5B79F6452BA11725002DA9BE /* WizardSheetVStack.swift */,
5B79F64B2BA119AE002DA9BE /* WizardSheetTitleText.swift */,
Expand Down Expand Up @@ -1623,7 +1635,6 @@
CD09A74329A50F1D0063464F /* SideMenu.swift */,
C9A0DAD929C685E500466635 /* SideMenuButton.swift */,
CD09A74529A50F750063464F /* SideMenuContent.swift */,
C92DF80729C25FA900400561 /* SquareImage.swift */,
3FFB1D9B29A7DF9D002A755D /* StackedAvatarsView.swift */,
2D06BB9C2AE249D70085F509 /* ThreadRootView.swift */,
3F60F42829B27D3E000D62C4 /* ThreadView.swift */,
Expand Down Expand Up @@ -1989,6 +2000,7 @@
5B79F6532BA11B08002DA9BE /* WizardSheetDescriptionText.swift in Sources */,
5B6EB48E29EDBE0E006E750C /* NoteParser.swift in Sources */,
C9F84C23298DC7B900C6714D /* SettingsView.swift in Sources */,
03C8B4962C6D065900A07CCD /* ImageViewer.swift in Sources */,
5B79F6092B98AC33002DA9BE /* ClaimYourUniqueIdentitySheet.swift in Sources */,
C973AB652A323167002AED16 /* EventReference+CoreDataProperties.swift in Sources */,
C973AB632A323167002AED16 /* Relay+CoreDataProperties.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x24",
"green" : "0x0E",
"red" : "0x16"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xC6",
"green" : "0x81",
"red" : "0x9A"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
20 changes: 20 additions & 0 deletions Nos/Assets/Colors.xcassets/image-background.colorset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x16",
"green" : "0x07",
"red" : "0x0D"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
1 change: 1 addition & 0 deletions Nos/Views/CompactNoteView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ struct CompactNoteView_Previews: PreviewProvider {
CompactNoteView(note: previewData.linkNote, allowUserInteraction: false)
CompactNoteView(note: previewData.shortNote)
CompactNoteView(note: previewData.longNote)
CompactNoteView(note: previewData.imageNote)
CompactNoteView(note: previewData.doubleImageNote)
CompactNoteView(note: previewData.doubleImageNote, showLinkPreviews: false)
}
Expand Down
116 changes: 116 additions & 0 deletions Nos/Views/Components/Images/ImageViewer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import SDWebImageSwiftUI
import SwiftUI

/// A viewer for images. Supports full-screen zoom and panning.
struct ImageViewer: View {
/// The URL of the image to display.
let url: URL

@Environment(\.dismiss) var dismiss

@State private var scale: CGFloat = 1.0
@State private var lastScale: CGFloat = 1.0
@State private var offset: CGSize = .zero
@State private var lastOffset: CGSize = .zero
@State private var imageSize: CGSize = .zero

private let maxScale: CGFloat = 10.0
private let minScale: CGFloat = 1.0

var body: some View {
ZStack {
Color.imageBackground

GeometryReader { geometry in
WebImage(url: url)
.onSuccess { image, _, _ in
imageSize = image.size
}
.resizable()
.aspectRatio(contentMode: .fit)
.scaleEffect(scale)
.offset(x: offset.width, y: offset.height)
.gesture(
MagnificationGesture()
.onChanged { value in
withAnimation {
scale = lastScale * value
}
}
.onEnded { value in
withAnimation {
let newScale = lastScale * value
if newScale > maxScale {
scale = maxScale
} else if newScale < minScale {
scale = minScale
}

lastScale = scale
}
}
)
.gesture(
DragGesture()
.onChanged { value in
offset = CGSize(
width: lastOffset.width + value.translation.width,
height: lastOffset.height + value.translation.height
)
}
.onEnded { _ in
lastOffset = offset
}
)
.frame(width: geometry.size.width, height: geometry.size.height)
.clipped()
.onTapGesture(count: 2) {
withAnimation {
if scale == minScale {
scale = 4.0
} else {
scale = minScale
}
lastScale = scale
}
}
}
.ignoresSafeArea()

ZStack(alignment: .topLeading) {
Color.clear

Button(
action: {
dismiss()
},
label: {
Image(systemName: "xmark")
.symbolVariant(.fill.circle)
.symbolRenderingMode(.palette)
.foregroundStyle(Color.buttonCloseForeground, Color.buttonCloseBackground)
.font(.title)
}
)
.padding()
}
}
.ignoresSafeArea()
}
}

#Preview {
ImageViewer(
url: URL(
string: "https://image.nostr.build/9640e78f03afc4927d80a15fd1c4bd1404dc654a8663efb92cc9ee1b8b0719a3.jpg"
)!
)
}

#Preview {
ImageViewer(
url: URL(
string: "https://images.unsplash.com/photo-1716783841007-7de314270444"
)!
)
}
File renamed without changes.
32 changes: 20 additions & 12 deletions Nos/Views/LinkPreview.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Dependencies
import SwiftUI
import LinkPresentation
import SDWebImageSwiftUI
Expand Down Expand Up @@ -28,20 +29,27 @@ struct ImageLinkButton: View {
}

struct HeroImageButton: View {

let url: URL


@State private var isPresented: Bool = false

var body: some View {

Button(action: {
UIApplication.shared.open(url)
}, label: {
WebImage(url: url)
.resizable()
.indicator(.activity)
.aspectRatio(contentMode: .fit)
.frame(maxWidth: .infinity, maxHeight: .infinity)
})
Button(
action: {
isPresented = true
},
label: {
WebImage(url: url)
.resizable()
.indicator(.activity)
.aspectRatio(contentMode: .fill)
.clipped()
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
)
.fullScreenCover(isPresented: $isPresented) {
ImageViewer(url: url)
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion Nos/Views/NoteCard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Logger
import CoreData
import Dependencies

/// This view displays the information we have for an message suitable for being used in a list or grid.
/// This view displays the information we have for a message suitable for being used in a list or grid.
///
/// Use this view inside MessageButton to have nice borders.
struct NoteCard: View {
Expand Down

0 comments on commit 9465df8

Please sign in to comment.