diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 18f085045..9d8a52cfc 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -228,6 +228,7 @@ 450DF2051E0D74AC003D14BE /* Platform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 450DF2041E0D74AC003D14BE /* Platform.swift */; }; 450DF2091E0DD2C6003D14BE /* UserNotificationsAdaptee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 450DF2081E0DD2C6003D14BE /* UserNotificationsAdaptee.swift */; }; 451166C01FD86B98000739BA /* AccountManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451166BF1FD86B98000739BA /* AccountManager.swift */; }; + 451573962061B49500803601 /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451573952061B49500803601 /* GradientView.swift */; }; 451686AB1F520CDA00AC3D4B /* MultiDeviceProfileKeyUpdateJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451686AA1F520CDA00AC3D4B /* MultiDeviceProfileKeyUpdateJob.swift */; }; 4517642A1DE939FD00EDB8B9 /* ContactCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 451764281DE939FD00EDB8B9 /* ContactCell.xib */; }; 4517642B1DE939FD00EDB8B9 /* ContactCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451764291DE939FD00EDB8B9 /* ContactCell.swift */; }; @@ -843,6 +844,7 @@ 450DF2041E0D74AC003D14BE /* Platform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Platform.swift; sourceTree = ""; }; 450DF2081E0DD2C6003D14BE /* UserNotificationsAdaptee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; name = UserNotificationsAdaptee.swift; path = UserInterface/Notifications/UserNotificationsAdaptee.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 451166BF1FD86B98000739BA /* AccountManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountManager.swift; sourceTree = ""; }; + 451573952061B49500803601 /* GradientView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = GradientView.swift; path = SignalMessaging/Views/GradientView.swift; sourceTree = SOURCE_ROOT; }; 451686AA1F520CDA00AC3D4B /* MultiDeviceProfileKeyUpdateJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiDeviceProfileKeyUpdateJob.swift; sourceTree = ""; }; 451764281DE939FD00EDB8B9 /* ContactCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ContactCell.xib; sourceTree = ""; }; 451764291DE939FD00EDB8B9 /* ContactCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactCell.swift; sourceTree = ""; }; @@ -1504,6 +1506,7 @@ 340CB2231EAC155C0001CAA1 /* ContactsViewHelper.m */, 346129D11FD2085A00532771 /* CommonStrings.swift */, 45BE4EA12012AD2000935E59 /* DisappearingTimerConfigurationView.swift */, + 451573952061B49500803601 /* GradientView.swift */, 346129CF1FD207F200532771 /* OWSAlerts.swift */, 454A965E1FD60EA2008D2A0E /* OWSFlatButton.swift */, 3400C7971EAFB772008A8584 /* ThreadViewHelper.h */, @@ -3049,6 +3052,7 @@ 346129D01FD207F300532771 /* OWSAlerts.swift in Sources */, 454A965F1FD60EA3008D2A0E /* OWSFlatButton.swift in Sources */, 346129B61FD1F7E800532771 /* ProfileFetcherJob.swift in Sources */, + 451573962061B49500803601 /* GradientView.swift in Sources */, 346129F51FD5F31400532771 /* OWS102MoveLoggingPreferenceToUserDefaults.m in Sources */, 45194F8F1FD71FF500333B2C /* ThreadUtil.m in Sources */, 451F8A3B1FD71297005CB9DA /* UIUtil.m in Sources */, diff --git a/Signal/Images.xcassets/ic_gallery_badge_gif.imageset/Contents.json b/Signal/Images.xcassets/ic_gallery_badge_gif.imageset/Contents.json new file mode 100644 index 000000000..be7b71198 --- /dev/null +++ b/Signal/Images.xcassets/ic_gallery_badge_gif.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_GIF@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "icon_GIF@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "icon_GIF@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@1x.png b/Signal/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@1x.png new file mode 100644 index 000000000..58592c846 Binary files /dev/null and b/Signal/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@1x.png differ diff --git a/Signal/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@2x.png b/Signal/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@2x.png new file mode 100644 index 000000000..529bb11da Binary files /dev/null and b/Signal/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@2x.png differ diff --git a/Signal/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@3x.png b/Signal/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@3x.png new file mode 100644 index 000000000..df5f374ad Binary files /dev/null and b/Signal/Images.xcassets/ic_gallery_badge_gif.imageset/icon_GIF@3x.png differ diff --git a/Signal/Images.xcassets/ic_gallery_badge_video.imageset/Contents.json b/Signal/Images.xcassets/ic_gallery_badge_video.imageset/Contents.json new file mode 100644 index 000000000..e3cdd23b0 --- /dev/null +++ b/Signal/Images.xcassets/ic_gallery_badge_video.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_video@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "icon_video@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "icon_video@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@1x.png b/Signal/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@1x.png new file mode 100644 index 000000000..d5435c662 Binary files /dev/null and b/Signal/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@1x.png differ diff --git a/Signal/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@2x.png b/Signal/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@2x.png new file mode 100644 index 000000000..e6880defb Binary files /dev/null and b/Signal/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@2x.png differ diff --git a/Signal/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@3x.png b/Signal/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@3x.png new file mode 100644 index 000000000..b520831e4 Binary files /dev/null and b/Signal/Images.xcassets/ic_gallery_badge_video.imageset/icon_video@3x.png differ diff --git a/Signal/src/ViewControllers/MediaGalleryViewController.swift b/Signal/src/ViewControllers/MediaGalleryViewController.swift index 2a17bae05..f2de5ced0 100644 --- a/Signal/src/ViewControllers/MediaGalleryViewController.swift +++ b/Signal/src/ViewControllers/MediaGalleryViewController.swift @@ -25,6 +25,14 @@ public struct MediaGalleryItem: Equatable, Hashable { return attachmentStream.isVideo() } + var isAnimated: Bool { + return attachmentStream.isAnimated() + } + + var isImage: Bool { + return attachmentStream.isImage() + } + var thumbnailImage: UIImage { guard let image = attachmentStream.thumbnailImage() else { owsFail("\(logTag) in \(#function) unexpectedly unable to build attachment thumbnail") diff --git a/Signal/src/ViewControllers/MediaTileViewController.swift b/Signal/src/ViewControllers/MediaTileViewController.swift index d739cc2c6..d2a2522ea 100644 --- a/Signal/src/ViewControllers/MediaTileViewController.swift +++ b/Signal/src/ViewControllers/MediaTileViewController.swift @@ -554,22 +554,38 @@ fileprivate class MediaGalleryCell: UICollectionViewCell { public let imageView: UIImageView private var tapGesture: UITapGestureRecognizer! + private let badgeView: UIImageView + private var item: MediaGalleryItem? public weak var delegate: MediaGalleryCellDelegate? + static let videoBadgeImage = #imageLiteral(resourceName: "ic_gallery_badge_video") + static let animatedBadgeImage = #imageLiteral(resourceName: "ic_gallery_badge_gif") + override init(frame: CGRect) { self.imageView = UIImageView() imageView.contentMode = .scaleAspectFill + self.badgeView = UIImageView() + badgeView.isHidden = true + super.init(frame: frame) self.tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTap)) self.addGestureRecognizer(tapGesture) self.clipsToBounds = true - self.addSubview(imageView) + self.contentView.addSubview(imageView) + self.contentView.addSubview(badgeView) imageView.autoPinEdgesToSuperviewEdges() + + // Note assets were rendered to match exactly. We don't want to re-size with + // content mode lest they become less legible. + let kBadgeSize = CGSize(width: 18, height: 12) + badgeView.autoPinEdge(toSuperviewEdge: .leading, withInset: 3) + badgeView.autoPinEdge(toSuperviewEdge: .bottom, withInset: 3) + badgeView.autoSetDimensions(to: kBadgeSize) } @available(*, unavailable, message: "Unimplemented") @@ -580,6 +596,17 @@ fileprivate class MediaGalleryCell: UICollectionViewCell { public func configure(item: MediaGalleryItem, delegate: MediaGalleryCellDelegate) { self.item = item self.imageView.image = item.thumbnailImage + if item.isVideo { + self.badgeView.isHidden = false + self.badgeView.image = MediaGalleryCell.videoBadgeImage + } else if item.isAnimated { + self.badgeView.isHidden = false + self.badgeView.image = MediaGalleryCell.animatedBadgeImage + } else { + assert(item.isImage) + self.badgeView.isHidden = true + } + self.delegate = delegate } @@ -588,6 +615,7 @@ fileprivate class MediaGalleryCell: UICollectionViewCell { self.item = nil self.imageView.image = nil + self.badgeView.isHidden = true self.delegate = nil } diff --git a/SignalMessaging/Views/GradientView.swift b/SignalMessaging/Views/GradientView.swift new file mode 100644 index 000000000..c0d256340 --- /dev/null +++ b/SignalMessaging/Views/GradientView.swift @@ -0,0 +1,24 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +public class GradientView: UIView { + + let gradientLayer = CAGradientLayer() + + public required init(from fromColor: UIColor, to toColor: UIColor) { + gradientLayer.colors = [fromColor.cgColor, toColor.cgColor] + super.init(frame: CGRect.zero) + + self.layer.addSublayer(gradientLayer) + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + public override func layoutSubviews() { + super.layoutSubviews() + gradientLayer.frame = self.bounds + } +} diff --git a/SignalMessaging/attachments/AttachmentApprovalViewController.swift b/SignalMessaging/attachments/AttachmentApprovalViewController.swift index 3d2da6289..a29f4275d 100644 --- a/SignalMessaging/attachments/AttachmentApprovalViewController.swift +++ b/SignalMessaging/attachments/AttachmentApprovalViewController.swift @@ -472,27 +472,6 @@ extension AttachmentApprovalViewController: UIScrollViewDelegate { } } -private class GradientView: UIView { - - let gradientLayer = CAGradientLayer() - - required init(from fromColor: UIColor, to toColor: UIColor) { - gradientLayer.colors = [fromColor.cgColor, toColor.cgColor] - super.init(frame: CGRect.zero) - - self.layer.addSublayer(gradientLayer) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func layoutSubviews() { - super.layoutSubviews() - gradientLayer.frame = self.bounds - } -} - protocol CaptioningToolbarDelegate: class { func captioningToolbarDidTapSend(_ captioningToolbar: CaptioningToolbar, captionText: String?) func captioningToolbarDidBeginEditing(_ captioningToolbar: CaptioningToolbar)