Files
damus/damus/Views/Profile/ProfilePictureSelector.swift
T
Daniel D’Aquino bb0ad18913 Implement profile image cropping and optimization
This commit implements profile image cropping and optimization, as well
as a major refactor on EditPictureControl.

It now employs the following techniques:
- Users can now crop their profile pictures to fit a square aspect
  ratio nicely and avoid issues with automatic resizing/cropping
- Profile images are resized to a 400px by 400px image before sending it
  over the wire for better bandwidth usage
- Profile pictures are now tagged as such to the media uploaders, to
  enable media optimization or special care on their end.

Integrating the cropping step was very difficult with the previous
structures, so `EditPictureControl` was heavily refactored to have
improved state handling and better testability:

1. Enums with associated values are being used to capture all of the
   state in the picture selection process, as that helps ensure the
   needed info in each step is there and more clearly delianeate
   different steps — all at compile-time
2. The view was split into a view-model architecture, with almost all of
   the view logic ported to the new view-model class, making the view
   and the logic more clear to read as concerns are separated. This also
   enables better testabilty

Several automated tests were added to cover EditPictureControl logic and
looks.

Closes: https://github.com/damus-io/damus/issues/2643
Changelog-Added: Profile image cropping tools
Changelog-Changed: Improved profile image bandwidth optimization
Changelog-Changed: Improved reliability of picture selector
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2025-01-06 15:45:57 +09:00

70 lines
2.1 KiB
Swift

//
// EditProfilePictureView.swift
// damus
//
// Created by William Casarin on 2022-05-20.
//
import SwiftUI
import Kingfisher
import Combine
struct EditProfilePictureView: View {
@State var profile_url: URL?
let pubkey: Pubkey
var damus_state: DamusState?
var size: CGFloat = 80.0
let highlight: Highlight = .custom(Color.white, 2.0)
@ObservedObject var uploadObserver: ImageUploadingObserver
let callback: (URL?) -> Void
var body: some View {
ZStack {
Color(uiColor: .systemBackground)
KFAnimatedImage(get_profile_url())
.imageContext(.pfp, disable_animation: damus_state?.settings.disable_animation == true)
.cancelOnDisappear(true)
.configure { view in
view.framePreloadCount = 3
}
.scaledToFill()
.kfClickable()
EditPictureControl(
uploader: damus_state?.settings.default_media_uploader ?? .nostrBuild,
context: .profile_picture,
keypair: damus_state?.keypair,
pubkey: pubkey,
current_image_url: $profile_url,
upload_observer: 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)?.map({ pr in pr?.picture }).value {
return URL(string: picture)
} else {
return profile_url ?? URL(string: robohash(pubkey))
}
}
}
struct ProfilePictureSelector_Previews: PreviewProvider {
static var previews: some View {
EditProfilePictureView(pubkey: test_pubkey, uploadObserver: ImageUploadingObserver()) { _ in
//
}
}
}