diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index f1a416dd1..9241aa40b 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -176,6 +176,7 @@ 7BD477B027F526FF004E2822 /* BlockListUIUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD477AF27F526FF004E2822 /* BlockListUIUtils.swift */; }; 7BDCFC08242186E700641C39 /* NotificationServiceExtensionContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDCFC07242186E700641C39 /* NotificationServiceExtensionContext.swift */; }; 7BDCFC0B2421EB7600641C39 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B6F509951AA53F760068F56A /* Localizable.strings */; }; + 7BFA8AE32831D0D4001876F3 /* ContextMenuVC+EmojiReactsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BFA8AE22831D0D4001876F3 /* ContextMenuVC+EmojiReactsView.swift */; }; 7BFD1A8A2745C4F000FB91B9 /* Permissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BFD1A892745C4F000FB91B9 /* Permissions.swift */; }; 7BFD1A8C2747150E00FB91B9 /* TurnServerInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BFD1A8B2747150E00FB91B9 /* TurnServerInfo.swift */; }; 7BFD1A972747689000FB91B9 /* Session-Turn-Server in Resources */ = {isa = PBXBuildFile; fileRef = 7BFD1A962747689000FB91B9 /* Session-Turn-Server */; }; @@ -1166,6 +1167,7 @@ 7BD477AF27F526FF004E2822 /* BlockListUIUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockListUIUtils.swift; sourceTree = ""; }; 7BDCFC0424206E7300641C39 /* SessionNotificationServiceExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SessionNotificationServiceExtension.entitlements; sourceTree = ""; }; 7BDCFC07242186E700641C39 /* NotificationServiceExtensionContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationServiceExtensionContext.swift; sourceTree = ""; }; + 7BFA8AE22831D0D4001876F3 /* ContextMenuVC+EmojiReactsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContextMenuVC+EmojiReactsView.swift"; sourceTree = ""; }; 7BFD1A892745C4F000FB91B9 /* Permissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Permissions.swift; sourceTree = ""; }; 7BFD1A8B2747150E00FB91B9 /* TurnServerInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TurnServerInfo.swift; sourceTree = ""; }; 7BFD1A962747689000FB91B9 /* Session-Turn-Server */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "Session-Turn-Server"; sourceTree = ""; }; @@ -2616,6 +2618,7 @@ C328253F25CA55880062D0A7 /* ContextMenuVC.swift */, C328254825CA60E60062D0A7 /* ContextMenuVC+Action.swift */, C328255125CA64470062D0A7 /* ContextMenuVC+ActionView.swift */, + 7BFA8AE22831D0D4001876F3 /* ContextMenuVC+EmojiReactsView.swift */, ); path = "Context Menu"; sourceTree = ""; @@ -4853,6 +4856,7 @@ 452EC6DF205E9E30000E787C /* MediaGalleryViewController.swift in Sources */, 4C1885D2218F8E1C00B67051 /* PhotoGridViewCell.swift in Sources */, 34D1F0501F7D45A60066283D /* GifPickerCell.swift in Sources */, + 7BFA8AE32831D0D4001876F3 /* ContextMenuVC+EmojiReactsView.swift in Sources */, 7B13E1EB2811138200BD4F64 /* PrivacySettingsTableViewController.swift in Sources */, C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */, 7BAF54D027ACCEEC003D12F8 /* EmptySearchResultCell.swift in Sources */, diff --git a/Session/Conversations/Context Menu/ContextMenuVC+EmojiReactsView.swift b/Session/Conversations/Context Menu/ContextMenuVC+EmojiReactsView.swift new file mode 100644 index 000000000..d46573888 --- /dev/null +++ b/Session/Conversations/Context Menu/ContextMenuVC+EmojiReactsView.swift @@ -0,0 +1,89 @@ + +extension ContextMenuVC { + + final class EmojiReactsView: UIView { + private let emoji: String + private let dismiss: () -> Void + + // MARK: Settings + private static let size: CGFloat = 40 + + // MARK: Lifecycle + init(for emoji: String, dismiss: @escaping () -> Void) { + self.emoji = emoji + self.dismiss = dismiss + super.init(frame: CGRect.zero) + setUpViewHierarchy() + } + + override init(frame: CGRect) { + preconditionFailure("Use init(for:) instead.") + } + + required init?(coder: NSCoder) { + preconditionFailure("Use init(for:) instead.") + } + + private func setUpViewHierarchy() { + let emojiLabel = UILabel() + emojiLabel.text = self.emoji + emojiLabel.font = .systemFont(ofSize: Values.veryLargeFontSize) + emojiLabel.set(.height, to: ContextMenuVC.EmojiReactsView.size) + addSubview(emojiLabel) + emojiLabel.pin(to: self) + // Tap gesture recognizer + let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap)) + addGestureRecognizer(tapGestureRecognizer) + } + + // MARK: Interaction + @objc private func handleTap() { + dismiss() + } + } + + final class EmojiPlusButton: UIView { + private let dismiss: () -> Void + + // MARK: Settings + public static let size: CGFloat = 28 + private let iconSize: CGFloat = 14 + + // MARK: Lifecycle + init(dismiss: @escaping () -> Void) { + self.dismiss = dismiss + super.init(frame: CGRect.zero) + setUpViewHierarchy() + } + + override init(frame: CGRect) { + preconditionFailure("Use init(for:) instead.") + } + + required init?(coder: NSCoder) { + preconditionFailure("Use init(for:) instead.") + } + + private func setUpViewHierarchy() { + // Icon image + let iconImageView = UIImageView(image: #imageLiteral(resourceName: "ic_plus_24").withTint(Colors.text)) + iconImageView.set(.width, to: iconSize) + iconImageView.set(.height, to: iconSize) + iconImageView.contentMode = .scaleAspectFit + addSubview(iconImageView) + iconImageView.center(in: self) + // Background + isUserInteractionEnabled = true + backgroundColor = Colors.sessionEmojiPlusButtonBackground + // Tap gesture recognizer + let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap)) + addGestureRecognizer(tapGestureRecognizer) + } + + // MARK: Interaction + @objc private func handleTap() { + dismiss() + } + } + +} diff --git a/Session/Conversations/Context Menu/ContextMenuVC.swift b/Session/Conversations/Context Menu/ContextMenuVC.swift index 9bf1733ba..d1d7a2dd2 100644 --- a/Session/Conversations/Context Menu/ContextMenuVC.swift +++ b/Session/Conversations/Context Menu/ContextMenuVC.swift @@ -18,6 +18,15 @@ final class ContextMenuVC : UIViewController { result.set(.height, to: ContextMenuVC.actionViewHeight) return result }() + + private lazy var emojiPlusButton: EmojiPlusButton = { + let result = EmojiPlusButton(dismiss: snDismiss) + result.set(.width, to: EmojiPlusButton.size) + result.set(.height, to: EmojiPlusButton.size) + result.layer.cornerRadius = EmojiPlusButton.size / 2 + result.layer.masksToBounds = true + return result + }() private lazy var menuView: UIView = { let result = UIView() @@ -92,19 +101,21 @@ final class ContextMenuVC : UIViewController { emojiBarBackgroundView.layer.masksToBounds = true emojiBar.addSubview(emojiBarBackgroundView) emojiBarBackgroundView.pin(to: emojiBar) - let emojiLabels = ["🙈", "🙉", "🙊", "😈", "🥸", "🐀", "😃"].map { emoji -> UILabel in - let label = UILabel() - label.text = emoji - label.font = .systemFont(ofSize: Values.veryLargeFontSize) - return label - } + + emojiBar.addSubview(emojiPlusButton) + emojiPlusButton.pin(.right, to: .right, of: emojiBar, withInset: -Values.smallSpacing) + emojiPlusButton.center(.vertical, in: emojiBar) + + let emojiLabels = ["🙈", "🙉", "🙊", "😈", "🥸", "🐀"].map { EmojiReactsView(for: $0, dismiss: snDismiss) } let emojiBarStackView = UIStackView(arrangedSubviews: emojiLabels) emojiBarStackView.axis = .horizontal emojiBarStackView.spacing = Values.smallSpacing - emojiBarStackView.layoutMargins = UIEdgeInsets(top: 0, left: Values.mediumSpacing, bottom: 0, right: Values.mediumSpacing) + emojiBarStackView.layoutMargins = UIEdgeInsets(top: 0, left: Values.smallSpacing, bottom: 0, right: Values.smallSpacing) emojiBarStackView.isLayoutMarginsRelativeArrangement = true emojiBar.addSubview(emojiBarStackView) - emojiBarStackView.pin(to: emojiBar) + emojiBarStackView.pin([ UIView.HorizontalEdge.left, UIView.VerticalEdge.top, UIView.VerticalEdge.bottom ], to: emojiBar) + emojiBarStackView.pin(.right, to: .left, of: emojiPlusButton) + view.addSubview(emojiBar) // Menu let menuBackgroundView = UIView() diff --git a/SessionUIKit/Style Guide/Colors.swift b/SessionUIKit/Style Guide/Colors.swift index c2b09e5f0..3059b4518 100644 --- a/SessionUIKit/Style Guide/Colors.swift +++ b/SessionUIKit/Style Guide/Colors.swift @@ -49,4 +49,5 @@ public final class Colors : NSObject { @objc public static var sessionMessageRequestsIcon: UIColor { UIColor(named: "session_message_requests_icon")! } @objc public static var sessionMessageRequestsTitle: UIColor { UIColor(named: "session_message_requests_title")! } @objc public static var sessionMessageRequestsInfoText: UIColor { UIColor(named: "session_message_requests_info_text")! } + @objc public static var sessionEmojiPlusButtonBackground: UIColor { UIColor(named: "session_emoji_plus_button_background")! } } diff --git a/SessionUIKit/Style Guide/Colors.xcassets/session_emoji_plus_button_background.colorset/Contents.json b/SessionUIKit/Style Guide/Colors.xcassets/session_emoji_plus_button_background.colorset/Contents.json new file mode 100644 index 000000000..c76746b18 --- /dev/null +++ b/SessionUIKit/Style Guide/Colors.xcassets/session_emoji_plus_button_background.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xFF", + "green" : "0xFF", + "red" : "0xFF" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x23", + "green" : "0x23", + "red" : "0x23" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +}