damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

commit a4d40dbfa675144a09f865982403bca36b944b8e
parent 05d332eac3d2736b4959e229ffa89ee0e9c02150
Author: William Casarin <jb55@jb55.com>
Date:   Sat, 15 Apr 2023 12:43:44 -0700

Revert "Changelog-Added: Banner Image Upload"

I didn't mean to commit this yet

This reverts commit 95041600dcd1801df481c468a3bf890bb0468a26.

Diffstat:
Mdamus.xcodeproj/project.pbxproj | 8++++----
Mdamus/Util/AnyCodable/AnyEncodable.swift | 4++--
Mdamus/Views/BannerImageView.swift | 27---------------------------
Mdamus/Views/CreateAccountView.swift | 8++++----
Mdamus/Views/EditMetadataView.swift | 14++++----------
Mdamus/Views/ImagePicker.swift | 19++-----------------
Ddamus/Views/Profile/EditPictureControl.swift | 114-------------------------------------------------------------------------------
Adamus/Views/Profile/EditProfilePictureControl.swift | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdamus/Views/Profile/ProfilePicView.swift | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdamus/Views/Profile/ProfilePictureSelector.swift | 67+++++++++++++++++--------------------------------------------------
10 files changed, 174 insertions(+), 228 deletions(-)

diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj @@ -276,7 +276,7 @@ F75BA12F29A18EF500E10810 /* BookmarksView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F75BA12E29A18EF500E10810 /* BookmarksView.swift */; }; F7908E92298B0F0700AB113A /* RelayDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7908E91298B0F0700AB113A /* RelayDetailView.swift */; }; F7908E97298B1FDF00AB113A /* NIPURLBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7908E96298B1FDF00AB113A /* NIPURLBuilder.swift */; }; - F79C7FAD29D5E9620000F946 /* EditPictureControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = F79C7FAC29D5E9620000F946 /* EditPictureControl.swift */; }; + F79C7FAD29D5E9620000F946 /* EditProfilePictureControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = F79C7FAC29D5E9620000F946 /* EditProfilePictureControl.swift */; }; F7F0BA25297892BD009531F3 /* SwipeToDismiss.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F0BA24297892BD009531F3 /* SwipeToDismiss.swift */; }; F7F0BA272978E54D009531F3 /* ParicipantsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F0BA262978E54D009531F3 /* ParicipantsView.swift */; }; /* End PBXBuildFile section */ @@ -686,7 +686,7 @@ F75BA12E29A18EF500E10810 /* BookmarksView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksView.swift; sourceTree = "<group>"; }; F7908E91298B0F0700AB113A /* RelayDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayDetailView.swift; sourceTree = "<group>"; }; F7908E96298B1FDF00AB113A /* NIPURLBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NIPURLBuilder.swift; sourceTree = "<group>"; }; - F79C7FAC29D5E9620000F946 /* EditPictureControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditPictureControl.swift; sourceTree = "<group>"; }; + F79C7FAC29D5E9620000F946 /* EditProfilePictureControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditProfilePictureControl.swift; sourceTree = "<group>"; }; F7F0BA24297892BD009531F3 /* SwipeToDismiss.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeToDismiss.swift; sourceTree = "<group>"; }; F7F0BA262978E54D009531F3 /* ParicipantsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParicipantsView.swift; sourceTree = "<group>"; }; /* End PBXFileReference section */ @@ -1052,7 +1052,7 @@ children = ( 4CEE2AF6280B2DEA00AB5EEF /* ProfileName.swift */, 4C285C892838B985008A31F1 /* ProfilePictureSelector.swift */, - F79C7FAC29D5E9620000F946 /* EditPictureControl.swift */, + F79C7FAC29D5E9620000F946 /* EditProfilePictureControl.swift */, 4CEE2AF2280B25C500AB5EEF /* ProfilePicView.swift */, 4C8682862814DE470026224F /* ProfileView.swift */, 4CB9D4A62992D02B00A9A7E4 /* ProfileNameView.swift */, @@ -1622,7 +1622,7 @@ 4CE0E2B629A3ED5500DB4CA2 /* InnerTimelineView.swift in Sources */, 4C363A8828236948006E126D /* BlocksView.swift in Sources */, 4C06670628FCB08600038D2A /* ImageCarousel.swift in Sources */, - F79C7FAD29D5E9620000F946 /* EditPictureControl.swift in Sources */, + F79C7FAD29D5E9620000F946 /* EditProfilePictureControl.swift in Sources */, 4C9F18E229AA9B6C008C55EC /* CustomizeZapView.swift in Sources */, 4C75EFAF28049D350006080F /* NostrFilter.swift in Sources */, 4C3EA64C28FF59AC00C48A62 /* bech32_util.c in Sources */, diff --git a/damus/Util/AnyCodable/AnyEncodable.swift b/damus/Util/AnyCodable/AnyEncodable.swift @@ -91,8 +91,8 @@ extension _AnyEncodable { try encode(nsnumber: number, into: &container) case let date as Date: try container.encode(date) - case let profile_url as URL: - try container.encode(profile_url) + case let url as URL: + try container.encode(url) #endif case let array as [Any?]: try container.encode(array.map { AnyEncodable($0) }) diff --git a/damus/Views/BannerImageView.swift b/damus/Views/BannerImageView.swift @@ -8,33 +8,6 @@ import SwiftUI import Kingfisher -struct EditBannerImageView: View { - - var damus_state: DamusState - @ObservedObject var viewModel: ImageUploadingObserver - let callback: (URL?) -> Void - let defaultImage = UIImage(named: "profile-banner") ?? UIImage() - - @State var banner_image: URL? = nil - - var body: some View { - ZStack { - Color(uiColor: .systemBackground) - KFAnimatedImage(get_banner_url(banner: banner_image?.absoluteString, pubkey: damus_state.pubkey, profiles: damus_state.profiles)) - .imageContext(.banner) - .configure { view in - view.framePreloadCount = 3 - } - .placeholder { _ in - Color(uiColor: .secondarySystemBackground) - } - .onFailureImage(defaultImage) - - EditPictureControl(pubkey: damus_state.pubkey, image_url: $banner_image, uploadObserver: viewModel, callback: callback) - } - } -} - struct InnerBannerImageView: View { let url: URL? diff --git a/damus/Views/CreateAccountView.swift b/damus/Views/CreateAccountView.swift @@ -9,7 +9,7 @@ import SwiftUI struct CreateAccountView: View { @StateObject var account: CreateAccountModel = CreateAccountModel() - @StateObject var profileUploadObserver = ImageUploadingObserver() + @StateObject var profileUploadViewModel = ProfileUploadingViewModel() @State var is_light: Bool = false @State var is_done: Bool = false @@ -35,7 +35,7 @@ struct CreateAccountView: View { .font(.title.bold()) .foregroundColor(.white) - EditProfilePictureView(pubkey: account.pubkey, uploadObserver: profileUploadObserver, callback: uploadedProfilePicture(image_url:)) + ProfilePictureSelector(pubkey: account.pubkey, viewModel: profileUploadViewModel, callback: uploadedProfilePicture(image_url:)) HStack(alignment: .top) { VStack { @@ -84,8 +84,8 @@ struct CreateAccountView: View { self.is_done = true } .padding() - .disabled(profileUploadObserver.isLoading) - .opacity(profileUploadObserver.isLoading ? 0.5 : 1) + .disabled(profileUploadViewModel.isLoading) + .opacity(profileUploadViewModel.isLoading ? 0.5 : 1) } .padding(.leading, 14.0) .padding(.trailing, 20.0) diff --git a/damus/Views/EditMetadataView.swift b/damus/Views/EditMetadataView.swift @@ -68,9 +68,7 @@ struct EditMetadataView: View { @Environment(\.colorScheme) var colorScheme @State var confirm_ln_address: Bool = false - - @StateObject var profileUploadObserver = ImageUploadingObserver() - @StateObject var bannerUploadObserver = ImageUploadingObserver() + @StateObject var profileUploadViewModel = ProfileUploadingViewModel() init (damus_state: DamusState) { self.damus_state = damus_state @@ -121,7 +119,7 @@ struct EditMetadataView: View { var TopSection: some View { ZStack(alignment: .top) { GeometryReader { geo in - EditBannerImageView(damus_state: damus_state, viewModel: bannerUploadObserver, callback: uploadedBanner(image_url:)) + BannerImageView(pubkey: damus_state.pubkey, profiles: damus_state.profiles) .aspectRatio(contentMode: .fill) .frame(width: geo.size.width, height: BANNER_HEIGHT) .clipped() @@ -130,7 +128,7 @@ struct EditMetadataView: View { let pfp_size: CGFloat = 90.0 HStack(alignment: .center) { - EditProfilePictureView(pubkey: damus_state.pubkey, damus_state: damus_state, size: pfp_size, uploadObserver: profileUploadObserver, callback: uploadedProfilePicture(image_url:)) + ProfilePictureSelector(pubkey: damus_state.pubkey, damus_state: damus_state, viewModel: profileUploadViewModel, callback: uploadedProfilePicture(image_url:)) .offset(y: -(pfp_size/2.0)) // Increase if set a frame Spacer() @@ -223,7 +221,7 @@ struct EditMetadataView: View { dismiss() } } - .disabled(profileUploadObserver.isLoading || bannerUploadObserver.isLoading) + .disabled(profileUploadViewModel.isLoading) .alert(NSLocalizedString("Invalid Tip Address", comment: "Title of alerting as invalid tip address."), isPresented: $confirm_ln_address) { Button(NSLocalizedString("Ok", comment: "Button to dismiss the alert.")) { } @@ -239,10 +237,6 @@ struct EditMetadataView: View { func uploadedProfilePicture(image_url: URL?) { picture = image_url?.absoluteString ?? "" } - - func uploadedBanner(image_url: URL?) { - banner = image_url?.absoluteString ?? "" - } } struct EditMetadataView_Previews: PreviewProvider { diff --git a/damus/Views/ImagePicker.swift b/damus/Views/ImagePicker.swift @@ -47,13 +47,11 @@ struct ImagePicker: UIViewControllerRepresentable { // Handle the selected image onImagePicked(imageURL) } else if let cameraImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage { - let orientedImage = cameraImage.fixOrientation() - if let imageURL = saveImageToTemporaryFolder(image: orientedImage, imageType: "jpeg") { + if let imageURL = saveImageToTemporaryFolder(image: cameraImage, imageType: "jpeg") { onImagePicked(imageURL) } } else if let editedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage { - let orientedImage = editedImage.fixOrientation() - if let editedImageURL = saveImageToTemporaryFolder(image: orientedImage, imageType: "jpeg") { + if let editedImageURL = saveImageToTemporaryFolder(image: editedImage) { onImagePicked(editedImageURL) } } @@ -124,16 +122,3 @@ struct ImagePicker: UIViewControllerRepresentable { } } - -extension UIImage { - func fixOrientation() -> UIImage { - guard imageOrientation != .up else { return self } - - UIGraphicsBeginImageContextWithOptions(size, false, scale) - draw(in: CGRect(origin: .zero, size: size)) - let normalizedImage = UIGraphicsGetImageFromCurrentImageContext() - UIGraphicsEndImageContext() - - return normalizedImage ?? self - } -} diff --git a/damus/Views/Profile/EditPictureControl.swift b/damus/Views/Profile/EditPictureControl.swift @@ -1,114 +0,0 @@ -// -// EditPictureControl.swift -// damus -// -// Created by Joel Klabo on 3/30/23. -// - -import SwiftUI - -class ImageUploadingObserver: ObservableObject { - @Published var isLoading: Bool = false -} - -struct EditPictureControl: View { - - let pubkey: String - @Binding var image_url: URL? - @ObservedObject var uploadObserver: ImageUploadingObserver - let callback: (URL?) -> Void - - @StateObject var image_upload: ImageUploadModel = ImageUploadModel() - - @State private var show_camera = false - @State private var show_library = false - @State var image_upload_confirm: Bool = false - - var body: some View { - Menu { - Button(action: { - self.show_library = true - }) { - Text("Choose from Library", comment: "Option to select photo from library") - } - - Button(action: { - self.show_camera = true - }) { - Text("Take Photo", comment: "Option to take a photo with the camera") - } - } label: { - if uploadObserver.isLoading { - ProgressView() - .progressViewStyle(CircularProgressViewStyle(tint: DamusColors.purple)) - .padding(10) - .background(DamusColors.white.opacity(0.7)) - .clipShape(Circle()) - .shadow(color: DamusColors.purple, radius: 15, x: 0, y: 0) - } else { - Image(systemName: "camera") - .resizable() - .scaledToFit() - .frame(width: 25, height: 25) - .foregroundColor(DamusColors.purple) - .padding(10) - .background(DamusColors.white.opacity(0.7)) - .clipShape(Circle()) - .shadow(color: DamusColors.purple, radius: 15, x: 0, y: 0) - } - } - .sheet(isPresented: $show_camera) { - // The alert may not be required for the profile pic upload case. Not showing the confirm check alert for this scenario - ImagePicker(sourceType: .camera, pubkey: pubkey, image_upload_confirm: $image_upload_confirm, imagesOnly: true) { img in - handle_upload(media: .image(img)) - } onVideoPicked: { url in - print("Cannot upload videos as profile image") - } - } - .sheet(isPresented: $show_library) { - // The alert may not be required for the profile pic upload case. Not showing the confirm check alert for this scenario - ImagePicker(sourceType: .photoLibrary, pubkey: pubkey, image_upload_confirm: $image_upload_confirm, imagesOnly: true) { img in - handle_upload(media: .image(img)) - } onVideoPicked: { url in - print("Cannot upload videos as profile image") - } - } - } - - private func handle_upload(media: MediaUpload) { - uploadObserver.isLoading = true - let uploader = get_media_uploader(pubkey) - Task { - let res = await image_upload.start(media: media, uploader: uploader) - - switch res { - case .success(let urlString): - let url = URL(string: urlString) - image_url = url - callback(url) - case .failed(let error): - if let error { - print("Error uploading profile image \(error.localizedDescription)") - } else { - print("Error uploading image :(") - } - callback(nil) - } - uploadObserver.isLoading = false - } - } -} - -struct EditPictureControl_Previews: PreviewProvider { - static var previews: some View { - let pubkey = "123" - let url = Binding<URL?>.constant(URL(string: "https://damus.io")!) - let observer = ImageUploadingObserver() - ZStack { - Color.gray - EditPictureControl(pubkey: pubkey, image_url: url, uploadObserver: observer) { _ in - // - } - } - } -} diff --git a/damus/Views/Profile/EditProfilePictureControl.swift b/damus/Views/Profile/EditProfilePictureControl.swift @@ -0,0 +1,87 @@ +// +// ProfilePictureEditView.swift +// damus +// +// Created by Joel Klabo on 3/30/23. +// + +import SwiftUI + +struct EditProfilePictureControl: View { + + let pubkey: String + @Binding var profile_image: URL? + @ObservedObject var viewModel: ProfileUploadingViewModel + let callback: (URL?) -> Void + + @StateObject var image_upload: ImageUploadModel = ImageUploadModel() + + @State private var show_camera = false + @State private var show_library = false + @State var image_upload_confirm: Bool = false + + var body: some View { + Menu { + Button(action: { + self.show_library = true + }) { + Text("Choose from Library", comment: "Option to select photo from library") + } + + Button(action: { + self.show_camera = true + }) { + Text("Take Photo", comment: "Option to take a photo with the camera") + } + } label: { + if viewModel.isLoading { + ProgressView() + } else { + Image(systemName: "camera") + .resizable() + .scaledToFit() + .frame(width: 25, height: 25) + .foregroundColor(DamusColors.white) + } + } + .sheet(isPresented: $show_camera) { + // The alert may not be required for the profile pic upload case. Not showing the confirm check alert for this scenario + ImagePicker(sourceType: .camera, pubkey: pubkey, image_upload_confirm: $image_upload_confirm, imagesOnly: true) { img in + handle_upload(media: .image(img)) + } onVideoPicked: { url in + print("Cannot upload videos as profile image") + } + } + .sheet(isPresented: $show_library) { + // The alert may not be required for the profile pic upload case. Not showing the confirm check alert for this scenario + ImagePicker(sourceType: .photoLibrary, pubkey: pubkey, image_upload_confirm: $image_upload_confirm, imagesOnly: true) { img in + handle_upload(media: .image(img)) + } onVideoPicked: { url in + print("Cannot upload videos as profile image") + } + } + } + + private func handle_upload(media: MediaUpload) { + viewModel.isLoading = true + let uploader = get_media_uploader(pubkey) + Task { + let res = await image_upload.start(media: media, uploader: uploader) + + switch res { + case .success(let urlString): + let url = URL(string: urlString) + profile_image = url + callback(url) + case .failed(let error): + if let error { + print("Error uploading profile image \(error.localizedDescription)") + } else { + print("Error uploading image :(") + } + callback(nil) + } + viewModel.isLoading = false + } + } +} diff --git a/damus/Views/Profile/ProfilePicView.swift b/damus/Views/Profile/ProfilePicView.swift @@ -32,6 +32,60 @@ func pfp_line_width(_ h: Highlight) -> CGFloat { } } +struct EditProfilePictureView: View { + + @Binding var url: URL? + + let pubkey: String + let size: CGFloat + let highlight: Highlight + + var damus_state: DamusState? + + var PlaceholderColor: Color { + return id_to_color(pubkey) + } + + var Placeholder: some View { + PlaceholderColor + .frame(width: size, height: size) + .clipShape(Circle()) + .overlay(Circle().stroke(highlight_color(highlight), lineWidth: pfp_line_width(highlight))) + .padding(2) + } + + var body: some View { + ZStack { + Color(uiColor: .systemBackground) + + KFAnimatedImage(get_profile_url()) + .imageContext(.pfp) + .cancelOnDisappear(true) + .configure { view in + view.framePreloadCount = 3 + } + .placeholder { _ in + Placeholder + } + .scaledToFill() + .opacity(0.5) + } + .frame(width: size, height: size) + .clipShape(Circle()) + .overlay(Circle().stroke(highlight_color(highlight), lineWidth: pfp_line_width(highlight))) + } + + private func get_profile_url() -> URL? { + if let url { + return url + } else if let state = damus_state, let picture = state.profiles.lookup(id: pubkey)?.picture { + return URL(string: picture) + } else { + return url ?? URL(string: robohash(pubkey)) + } + } +} + struct InnerProfilePicView: View { let url: URL? diff --git a/damus/Views/Profile/ProfilePictureSelector.swift b/damus/Views/Profile/ProfilePictureSelector.swift @@ -1,66 +1,33 @@ // -// EditProfilePictureView.swift +// ProfilePictureSelector.swift // damus // // Created by William Casarin on 2022-05-20. // import SwiftUI -import Kingfisher + import Combine -struct EditProfilePictureView: View { - - @State var profile_url: URL? - +class ProfileUploadingViewModel: ObservableObject { + @Published var isLoading: Bool = false +} + +struct ProfilePictureSelector: View { + let pubkey: String - var damus_state: DamusState? var size: CGFloat = 80.0 - let highlight: Highlight = .custom(Color.white, 2.0) - @ObservedObject var uploadObserver: ImageUploadingObserver + var damus_state: DamusState? + @ObservedObject var viewModel: ProfileUploadingViewModel let callback: (URL?) -> Void - - var PlaceholderColor: Color { - return id_to_color(pubkey) - } - - var Placeholder: some View { - PlaceholderColor - .frame(width: size, height: size) - .clipShape(Circle()) - .overlay(Circle().stroke(highlight_color(highlight), lineWidth: pfp_line_width(highlight))) - .padding(2) - } - - var body: some View { - ZStack { - Color(uiColor: .systemBackground) - KFAnimatedImage(get_profile_url()) - .imageContext(.pfp) - .cancelOnDisappear(true) - .configure { view in - view.framePreloadCount = 3 - } - .placeholder { _ in - Placeholder - } - .scaledToFill() + @State var profile_image: URL? = nil - EditPictureControl(pubkey: pubkey, image_url: $profile_url, uploadObserver: uploadObserver, callback: callback) - } - .frame(width: size, height: size) - .clipShape(Circle()) - .overlay(Circle().stroke(highlight_color(highlight), lineWidth: pfp_line_width(highlight))) - } - - private func get_profile_url() -> URL? { - if let profile_url { - return profile_url - } else if let state = damus_state, let picture = state.profiles.lookup(id: pubkey)?.picture { - return URL(string: picture) - } else { - return profile_url ?? URL(string: robohash(pubkey)) + var body: some View { + let highlight: Highlight = .custom(Color.white, 2.0) + ZStack { + EditProfilePictureView(url: $profile_image, pubkey: pubkey, size: size, highlight: highlight, damus_state: damus_state) + EditProfilePictureControl(pubkey: pubkey, profile_image: $profile_image, viewModel: viewModel, callback: callback) } } } @@ -68,7 +35,7 @@ struct EditProfilePictureView: View { struct ProfilePictureSelector_Previews: PreviewProvider { static var previews: some View { let test_pubkey = "ff48854ac6555fed8e439ebb4fa2d928410e0eef13fa41164ec45aaaa132d846" - EditProfilePictureView(pubkey: test_pubkey, uploadObserver: ImageUploadingObserver()) { _ in + ProfilePictureSelector(pubkey: test_pubkey, viewModel: ProfileUploadingViewModel()) { _ in // } }