Skip to content

Commit

Permalink
Merge branch 'trunk' into andrewdmontgomery/localize-more-strings
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewdmontgomery authored Sep 18, 2024
2 parents 6ff9d95 + 0f51ba2 commit 42f66e8
Show file tree
Hide file tree
Showing 6 changed files with 481 additions and 1 deletion.
123 changes: 123 additions & 0 deletions Demo/Demo/Gravatar-UIKit-Demo/DemoImageCropperViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#if DEBUG

import UIKit
@testable import GravatarUI
import PhotosUI

class DemoImageCropperViewController: UIViewController {

lazy var selectImageButton: UIButton = {
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Select Image", for: .normal)
button.addTarget(self, action: #selector(selectImage), for: .touchUpInside)
return button
}()

lazy var croppedImageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFit
imageView.widthAnchor.constraint(equalToConstant: 300).isActive = true
imageView.heightAnchor.constraint(equalToConstant: 300).isActive = true
imageView.backgroundColor = UIColor.secondarySystemBackground
return imageView
}()

lazy var sizeLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = UIColor.label
label.numberOfLines = 0
return label
}()

lazy var rootStackView: UIStackView = {
let stack = UIStackView(arrangedSubviews: [selectImageButton, croppedImageView, sizeLabel])
stack.translatesAutoresizingMaskIntoConstraints = false
stack.axis = .vertical
stack.spacing = 12
stack.distribution = .fill
stack.alignment = .center
return stack
}()

override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.systemBackground
view.addSubview(rootStackView)
NSLayoutConstraint.activate([
rootStackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
rootStackView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
rootStackView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
}

@objc private func selectImage() {
var configuration = PHPickerConfiguration()
configuration.filter = .images // Only show images in picker
configuration.selectionLimit = 1 // Limit selection to one image

let picker = PHPickerViewController(configuration: configuration)
picker.delegate = self
present(picker, animated: true, completion: nil)
}
}

extension DemoImageCropperViewController: PHPickerViewControllerDelegate {

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
dismiss(animated: true, completion: nil)

// Ensure the user selected an image and that it can be loaded as a UIImage
guard let result = results.first else { return }

// Load the selected image
if result.itemProvider.canLoadObject(ofClass: UIImage.self) {
result.itemProvider.loadObject(ofClass: UIImage.self) { [weak self] (object, error) in
if let image = object as? UIImage {
DispatchQueue.main.async {
self?.showCropper(with: image)
}
}
}
}
}

// Show the cropper with the selected image
func showCropper(with image: UIImage) {
let cropperVC = ImageCropperViewController.wrappedInNavigationViewController(image: image) { image, _ in
self.croppedImageView.image = image
self.sizeLabel.text = "\(image.size.width) x \(image.size.height) - scale: \(image.scale) - \(image.calculateSizeInMB())MB"
self.dismiss(animated: true)
} onCancel: {
self.dismiss(animated: true)
}

present(cropperVC, animated: true, completion: nil)
}
}

private extension UIImage {
// Function to calculate and print the size of the UIImage in megabytes
func calculateSizeInMB() -> Double {
guard let cgImage = self.cgImage else { return 0.0 }

// Get the width and height of the image
let width = cgImage.width
let height = cgImage.height

// Assume 4 bytes per pixel for RGBA (32-bit color depth)
let bytesPerPixel = 4

// Calculate the total number of bytes
let totalBytes = width * height * bytesPerPixel

// Convert bytes to megabytes
let totalMB = Double(totalBytes) / (1024.0 * 1024.0)

return Double(round(100 * totalMB) / 100)
}
}

#endif
7 changes: 6 additions & 1 deletion Demo/Demo/Gravatar-UIKit-Demo/MainTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ class MainTableViewController: UITableViewController {
case profileViewController
#if DEBUG
case displayRemoteSVG
case imageCropper
#endif
}

private static let reuseID = "DefaultCell"

override func viewDidLoad() {
Expand Down Expand Up @@ -57,6 +58,8 @@ class MainTableViewController: UITableViewController {
#if DEBUG
case .displayRemoteSVG:
content.text = "Display remote SVG"
case .imageCropper:
content.text = "Image Cropper"
#endif
}
cell.contentConfiguration = content
Expand Down Expand Up @@ -87,6 +90,8 @@ class MainTableViewController: UITableViewController {
#if DEBUG
case .displayRemoteSVG:
navigationController?.pushViewController(DemoRemoteSVGViewController(), animated: true)
case .imageCropper:
navigationController?.pushViewController(DemoImageCropperViewController(), animated: true)
#endif
}
}
Expand Down
4 changes: 4 additions & 0 deletions Demo/Gravatar-Demo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
49C5D6122B5B33E20067C2A8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 49C5D6112B5B33E20067C2A8 /* Assets.xcassets */; };
49C5D6152B5B33E20067C2A8 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 49C5D6142B5B33E20067C2A8 /* Preview Assets.xcassets */; };
49EFFB542C51A47C0086589A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 495775EA2B5B34980082812A /* Assets.xcassets */; };
9133058E2C91F8D1009F5C0B /* DemoImageCropperViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9133058D2C91F2C8009F5C0B /* DemoImageCropperViewController.swift */; };
9146A7AE2C3BD8F000E07C63 /* DemoAvatarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9146A7AD2C3BD8F000E07C63 /* DemoAvatarView.swift */; };
914AC0192BD7FF08005DA4A5 /* DemoBaseProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 914AC0172BD7FF08005DA4A5 /* DemoBaseProfileViewController.swift */; };
914AC01A2BD7FF08005DA4A5 /* DemoProfilePresentationStylesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 914AC0182BD7FF08005DA4A5 /* DemoProfilePresentationStylesViewController.swift */; };
Expand Down Expand Up @@ -115,6 +116,7 @@
49C5D6142B5B33E20067C2A8 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
49EFFB552C51AA280086589A /* Gravatar-UIKit-Demo.Base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Gravatar-UIKit-Demo.Base.xcconfig"; sourceTree = "<group>"; };
49EFFB572C51AA3E0086589A /* Gravatar-SwiftUI-Demo.Base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Gravatar-SwiftUI-Demo.Base.xcconfig"; sourceTree = "<group>"; };
9133058D2C91F2C8009F5C0B /* DemoImageCropperViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoImageCropperViewController.swift; sourceTree = "<group>"; };
9146A7AD2C3BD8F000E07C63 /* DemoAvatarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoAvatarView.swift; sourceTree = "<group>"; };
914AC0172BD7FF08005DA4A5 /* DemoBaseProfileViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DemoBaseProfileViewController.swift; sourceTree = "<group>"; };
914AC0182BD7FF08005DA4A5 /* DemoProfilePresentationStylesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DemoProfilePresentationStylesViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -192,6 +194,7 @@
91956A532B67943A00BF3CF0 /* DemoUIImageViewExtensionViewController.swift */,
914AC01F2BDAAC3C005DA4A5 /* DemoRemoteSVGViewController.swift */,
91F0B3DB2B62815F0025C4F8 /* MainTableViewController.swift */,
9133058D2C91F2C8009F5C0B /* DemoImageCropperViewController.swift */,
495775EA2B5B34980082812A /* Assets.xcassets */,
495775EC2B5B34980082812A /* LaunchScreen.storyboard */,
495775EF2B5B34980082812A /* Info.plist */,
Expand Down Expand Up @@ -446,6 +449,7 @@
495775E42B5B34970082812A /* SceneDelegate.swift in Sources */,
1ECAB5072BC984440043A331 /* DemoProfileConfigurationViewController.swift in Sources */,
91E2FB042BC0276E00265E8E /* DemoProfileViewsViewController.swift in Sources */,
9133058E2C91F8D1009F5C0B /* DemoImageCropperViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
25 changes: 25 additions & 0 deletions Sources/GravatarUI/ImageCropper/CropFrameOverlayView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import UIKit

class CropFrameOverlayView: UIView {
var scrollViewFrame: CGRect = .zero {
didSet {
setNeedsDisplay()
}
}

override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else { return }

// Fill the entire view with a semi black color
context.setFillColor(UIColor.black.withAlphaComponent(0.5).cgColor)
context.fill(rect)

// Clear the scrollView's area to make it transparent
context.clear(scrollViewFrame)

// Draw a border around the crop frame
context.setStrokeColor(UIColor.white.cgColor)
context.setLineWidth(1)
context.stroke(scrollViewFrame)
}
}
Loading

0 comments on commit 42f66e8

Please sign in to comment.