-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support video in the picker #44
Changes from 5 commits
b225632
d17c0a8
d78c367
8d010d0
97d1b62
9906e51
362075d
7f7eeb0
7924ab7
c4ee19a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"info" : { | ||
"version" : 1, | ||
"author" : "xcode" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"images" : [ | ||
{ | ||
"idiom" : "universal", | ||
"filename" : "video-icon.pdf" | ||
} | ||
], | ||
"info" : { | ||
"version" : 1, | ||
"author" : "xcode" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,8 @@ internal final class PhotoGalleryCell: UICollectionViewCell { | |
return imageView | ||
}() | ||
|
||
private let videoPropertyView = VideoPropertyView() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wondering if we should have a different type of cell for video:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. was thinking of that too, but the only diff is this VideoPropertyView. shall we subclass PhotoGalleryCell?
|
||
|
||
private let overlayView = UIView() | ||
private let tagLabel = PhotoGalleryTagLabel() | ||
|
||
|
@@ -41,9 +43,11 @@ internal final class PhotoGalleryCell: UICollectionViewCell { | |
overlayView.isHidden = false | ||
tagLabel.text = text | ||
accessibilityIdentifier = text | ||
videoPropertyView.setSelected(true) | ||
} else { | ||
overlayView.isHidden = true | ||
accessibilityIdentifier = nil | ||
videoPropertyView.setSelected(false) | ||
} | ||
} | ||
} | ||
|
@@ -58,6 +62,7 @@ internal final class PhotoGalleryCell: UICollectionViewCell { | |
imageRequestID = nil | ||
taggedText = nil | ||
imageView.image = nil | ||
videoPropertyView.isHidden = true | ||
} | ||
|
||
// MARK: - | ||
|
@@ -83,6 +88,9 @@ internal final class PhotoGalleryCell: UICollectionViewCell { | |
} | ||
} | ||
|
||
videoPropertyView.isHidden = asset.mediaType != .video | ||
videoPropertyView.configure(duration: asset.duration) | ||
|
||
if let color = configuration?.selectedImageOverlayColor { | ||
overlayView.backgroundColor = color | ||
} | ||
|
@@ -113,6 +121,13 @@ internal final class PhotoGalleryCell: UICollectionViewCell { | |
tagLabel.widthAnchor.constraint(equalTo: tagLabel.heightAnchor).isActive = true | ||
tagLabel.topAnchor.constraint(equalTo: overlayView.topAnchor, constant: 10).isActive = true | ||
tagLabel.trailingAnchor.constraint(equalTo: overlayView.trailingAnchor, constant: -10).isActive = true | ||
|
||
contentView.addSubview(videoPropertyView) | ||
videoPropertyView.translatesAutoresizingMaskIntoConstraints = false | ||
videoPropertyView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true | ||
videoPropertyView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true | ||
videoPropertyView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true | ||
videoPropertyView.heightAnchor.constraint(equalToConstant: 24).isActive = true | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -81,7 +81,23 @@ internal final class PhotoGalleryViewController: UIViewController, | |
internal private(set) lazy var fetchResult: PHFetchResult<PHAsset> = { | ||
let options = PHFetchOptions() | ||
options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)] | ||
options.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.image.rawValue) | ||
|
||
guard let configuration = configuration, | ||
let mediaType = configuration.mediaType | ||
else { | ||
options.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.image.rawValue) | ||
return PHAsset.fetchAssets(in: self.album, options: options) | ||
} | ||
|
||
switch mediaType { | ||
case .image: | ||
options.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.image.rawValue) | ||
case .video: | ||
options.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.video.rawValue) | ||
default: | ||
break | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I dont quite understand this. Shouldn't the fetch results contain both type of assets? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if we don't pass in the predicate, then yes it will fetch both type of assets There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It probably can be simplified as one switch: switch configuration?.mediaType {
case .image?:
// ...
case .video?:
// ...
case nil:
// ...
} |
||
} | ||
|
||
return PHAsset.fetchAssets(in: self.album, options: options) | ||
}() | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ internal extension UIColor { | |
static let gray = UIColor(hex: 0x8F939C) | ||
static let darkGray = UIColor(hex: 0x8F939C) | ||
static let magnesium = UIColor(hex: 0xB2B2B2) | ||
static let darkGrey = UIColor(hex: 0x4B4D52) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's already a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just noticed that |
||
} | ||
|
||
internal convenience init(hex: Int) { | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,73 @@ | ||||||
// | ||||||
// This source file is part of the carousell/pickle open source project | ||||||
// | ||||||
// Copyright © 2017 Carousell and the project authors | ||||||
// Licensed under Apache License v2.0 | ||||||
// | ||||||
// See https://github.com/carousell/pickle/blob/master/LICENSE for license information | ||||||
// See https://github.com/carousell/pickle/graphs/contributors for the list of project authors | ||||||
// | ||||||
|
||||||
internal final class VideoPropertyView: UIView { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's generally a good practice to specify explicit access control levels in a library. It implies that a method should only be made public in the future with careful consideration. The |
||||||
|
||||||
private let videoIcon: UIImageView = { | ||||||
let icon = UIImageView() | ||||||
icon.tintColor = .white | ||||||
icon.image = UIImage(named: "video-icon")?.withRenderingMode(.alwaysTemplate) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You might need to specify the framework bundle that contains the image. init?(named name: String, in bundle: Bundle?, compatibleWith traitCollection: UITraitCollection?) |
||||||
return icon | ||||||
}() | ||||||
|
||||||
private let durationLabel: UILabel = { | ||||||
let label = UILabel() | ||||||
label.font = UIFont.boldSystemFont(ofSize: 12) | ||||||
label.textAlignment = .right | ||||||
label.textColor = .white | ||||||
return label | ||||||
}() | ||||||
|
||||||
func configure(duration: TimeInterval) { | ||||||
let formatter = DateComponentsFormatter() | ||||||
formatter.zeroFormattingBehavior = .pad | ||||||
|
||||||
if duration >= 3600 { | ||||||
formatter.allowedUnits = [.hour, .minute, .second] | ||||||
} else { | ||||||
formatter.allowedUnits = [.minute, .second] | ||||||
} | ||||||
|
||||||
durationLabel.text = formatter.string(from: duration) | ||||||
} | ||||||
|
||||||
func setSelected(_ value: Bool) { | ||||||
if value { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
backgroundColor = UIColor.Palette.blue | ||||||
} else { | ||||||
backgroundColor = UIColor.Palette.darkGray.withAlphaComponent(0.2) | ||||||
} | ||||||
} | ||||||
|
||||||
override init(frame: CGRect) { | ||||||
super.init(frame: frame) | ||||||
setupViews() | ||||||
} | ||||||
|
||||||
required init?(coder aDecoder: NSCoder) { | ||||||
fatalError("init(coder:) has not been implemented") | ||||||
} | ||||||
|
||||||
private func setupViews() { | ||||||
backgroundColor = UIColor.Palette.darkGray.withAlphaComponent(0.2) | ||||||
|
||||||
addSubview(videoIcon) | ||||||
videoIcon.translatesAutoresizingMaskIntoConstraints = false | ||||||
videoIcon.heightAnchor.constraint(equalToConstant: 16).isActive = true | ||||||
videoIcon.widthAnchor.constraint(equalToConstant: 16).isActive = true | ||||||
videoIcon.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 4).isActive = true | ||||||
videoIcon.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true | ||||||
|
||||||
addSubview(durationLabel) | ||||||
durationLabel.translatesAutoresizingMaskIntoConstraints = false | ||||||
durationLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -4).isActive = true | ||||||
durationLabel.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true | ||||||
} | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be
all
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PHAsset has audio mediaType as well.
https://developer.apple.com/documentation/photokit/phassetmediatype
any better suggestion? or do u think can use
all
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.unknown
doesn't make sense I feel. How about removing.unknown
and bitmasking it usingOptionSet
?https://developer.apple.com/documentation/swift/optionset
Then the API consumer can pass in any combination of mediaType they desire:
mediaType: ImagePickerMediaType = [.video, .image]
mediaType: ImagePickerMediaType = [.video, .audio]
mediaType: ImagePickerMediaType = .video
mediaType: ImagePickerMediaType = .all
...