From ab687a9cc6b57461bcede24a17fab3c7f3b90f20 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 2 Mar 2020 16:27:33 +1100 Subject: [PATCH] Implement new conversation button redesign --- Signal.xcodeproj/project.pbxproj | 8 + .../Loki V2/Group.imageset/Contents.json | 12 + .../Loki V2/Group.imageset/Group.pdf | Bin 0 -> 30357 bytes .../Loki V2/Message.imageset/Contents.json | 12 + .../Loki V2/Message.imageset/Message.pdf | Bin 0 -> 5742 bytes .../Loki V2/Plus.imageset/Contents.json | 12 + .../Loki V2/Plus.imageset/Plus.pdf | Bin 0 -> 4018 bytes Signal/src/AppDelegate.m | 2 +- .../Components/NewConversationButtonSet.swift | 271 ++++++++++++++++++ Signal/src/Loki/Style Guide/Colors.swift | 1 + Signal/src/Loki/Style Guide/Values.swift | 3 +- .../src/Loki/Utilities/UIImage+Scaling.swift | 17 ++ Signal/src/Loki/View Controllers/HomeVC.swift | 56 +--- .../View Controllers/NewClosedGroupVC.swift | 6 +- 14 files changed, 354 insertions(+), 46 deletions(-) create mode 100644 Signal/Images.xcassets/Loki V2/Group.imageset/Contents.json create mode 100644 Signal/Images.xcassets/Loki V2/Group.imageset/Group.pdf create mode 100644 Signal/Images.xcassets/Loki V2/Message.imageset/Contents.json create mode 100644 Signal/Images.xcassets/Loki V2/Message.imageset/Message.pdf create mode 100644 Signal/Images.xcassets/Loki V2/Plus.imageset/Contents.json create mode 100644 Signal/Images.xcassets/Loki V2/Plus.imageset/Plus.pdf create mode 100644 Signal/src/Loki/Components/NewConversationButtonSet.swift create mode 100644 Signal/src/Loki/Utilities/UIImage+Scaling.swift diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 297b2117f..98b1893ba 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -573,6 +573,8 @@ B82B408E239DC00D00A248E7 /* DisplayNameVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B408D239DC00D00A248E7 /* DisplayNameVC.swift */; }; B82B4090239DD75000A248E7 /* RestoreVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B408F239DD75000A248E7 /* RestoreVC.swift */; }; B82B4094239DF15900A248E7 /* ConversationTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B4093239DF15900A248E7 /* ConversationTitleView.swift */; }; + B83F2B86240C7B8F000A54AB /* NewConversationButtonSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B83F2B85240C7B8F000A54AB /* NewConversationButtonSet.swift */; }; + B83F2B88240CB75A000A54AB /* UIImage+Scaling.swift in Sources */ = {isa = PBXBuildFile; fileRef = B83F2B87240CB75A000A54AB /* UIImage+Scaling.swift */; }; B846365B22B7418B00AF1514 /* Identicon+ObjC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B846365A22B7418B00AF1514 /* Identicon+ObjC.swift */; }; B84664F5235022F30083A1CD /* MentionUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = B84664F4235022F30083A1CD /* MentionUtilities.swift */; }; B847570323D5698100759540 /* LokiPushNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B847570223D5698100759540 /* LokiPushNotificationManager.swift */; }; @@ -1416,6 +1418,8 @@ B82B408D239DC00D00A248E7 /* DisplayNameVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayNameVC.swift; sourceTree = ""; }; B82B408F239DD75000A248E7 /* RestoreVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestoreVC.swift; sourceTree = ""; }; B82B4093239DF15900A248E7 /* ConversationTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationTitleView.swift; sourceTree = ""; }; + B83F2B85240C7B8F000A54AB /* NewConversationButtonSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewConversationButtonSet.swift; sourceTree = ""; }; + B83F2B87240CB75A000A54AB /* UIImage+Scaling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Scaling.swift"; sourceTree = ""; }; B846365A22B7418B00AF1514 /* Identicon+ObjC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Identicon+ObjC.swift"; sourceTree = ""; }; B84664F4235022F30083A1CD /* MentionUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionUtilities.swift; sourceTree = ""; }; B847570023D568EB00759540 /* SignalServiceKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SignalServiceKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2786,6 +2790,7 @@ B8162F0422892C5F00D46544 /* FriendRequestViewDelegate.swift */, B8B26C8E234D629C004ED98C /* MentionCandidateSelectionView.swift */, B8B26C90234D8CBD004ED98C /* MentionCandidateSelectionViewDelegate.swift */, + B83F2B85240C7B8F000A54AB /* NewConversationButtonSet.swift */, B8BB82B02390C37000BA5194 /* SearchBar.swift */, B85357BE23A1AE0800AAF6CD /* SeedReminderView.swift */, B85357C023A1B81900AAF6CD /* SeedReminderViewDelegate.swift */, @@ -2807,6 +2812,7 @@ B84664F4235022F30083A1CD /* MentionUtilities.swift */, B886B4A82398BA1500211ABE /* QRCode.swift */, B8783E9D23EB948D00404FB8 /* UILabel+Interaction.swift */, + B83F2B87240CB75A000A54AB /* UIImage+Scaling.swift */, ); path = Utilities; sourceTree = ""; @@ -3846,6 +3852,7 @@ 340FC8B8204DAC8D007AEB0F /* AddToGroupViewController.m in Sources */, 341F2C0F1F2B8AE700D07D6B /* DebugUIMisc.m in Sources */, B893063F2383961A005EAA8E /* ScanQRCodeWrapperVC.swift in Sources */, + B83F2B86240C7B8F000A54AB /* NewConversationButtonSet.swift in Sources */, 340FC8AF204DAC8D007AEB0F /* OWSLinkDeviceViewController.m in Sources */, 34E3EF0D1EFC235B007F6822 /* DebugUIDiskUsage.m in Sources */, 454A84042059C787008B8C75 /* MediaTileViewController.swift in Sources */, @@ -3883,6 +3890,7 @@ B885D5F4233491AB00EE0D8E /* DeviceLinkingModal.swift in Sources */, 45DF5DF21DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift in Sources */, 451166C01FD86B98000739BA /* AccountManager.swift in Sources */, + B83F2B88240CB75A000A54AB /* UIImage+Scaling.swift in Sources */, 3430FE181F7751D4000EC51B /* GiphyAPI.swift in Sources */, 4C2F454F214C00E1004871FF /* AvatarTableViewCell.swift in Sources */, 346E9D5421B040B700562252 /* RegistrationController.swift in Sources */, diff --git a/Signal/Images.xcassets/Loki V2/Group.imageset/Contents.json b/Signal/Images.xcassets/Loki V2/Group.imageset/Contents.json new file mode 100644 index 000000000..10de2f9a6 --- /dev/null +++ b/Signal/Images.xcassets/Loki V2/Group.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Group.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/Loki V2/Group.imageset/Group.pdf b/Signal/Images.xcassets/Loki V2/Group.imageset/Group.pdf new file mode 100644 index 0000000000000000000000000000000000000000..be41ce92df6735b7f431981cdb1d5fbb96bb73e5 GIT binary patch literal 30357 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 literal 0 HcmV?d00001 diff --git a/Signal/Images.xcassets/Loki V2/Message.imageset/Contents.json b/Signal/Images.xcassets/Loki V2/Message.imageset/Contents.json new file mode 100644 index 000000000..22681b32e --- /dev/null +++ b/Signal/Images.xcassets/Loki V2/Message.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Message.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/Loki V2/Message.imageset/Message.pdf b/Signal/Images.xcassets/Loki V2/Message.imageset/Message.pdf new file mode 100644 index 0000000000000000000000000000000000000000..46a40dafdb84ec47b20c20bac5bf85d2321aa0de GIT binary patch literal 5742 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 literal 0 HcmV?d00001 diff --git a/Signal/Images.xcassets/Loki V2/Plus.imageset/Contents.json b/Signal/Images.xcassets/Loki V2/Plus.imageset/Contents.json new file mode 100644 index 000000000..e34919cc9 --- /dev/null +++ b/Signal/Images.xcassets/Loki V2/Plus.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Plus.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/Loki V2/Plus.imageset/Plus.pdf b/Signal/Images.xcassets/Loki V2/Plus.imageset/Plus.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7d6855b3b49d5c0db0301c027b0ab4fd9fc61632 GIT binary patch literal 4018 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 E1K~p7P5=M^ literal 0 HcmV?d00001 diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 25a8de660..64721d20c 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -884,7 +884,7 @@ static NSTimeInterval launchStartedAt; return; } - [SignalApp.sharedApp.homeViewController createPrivateChat]; + [SignalApp.sharedApp.homeViewController createNewPrivateChat]; completionHandler(YES); }]; diff --git a/Signal/src/Loki/Components/NewConversationButtonSet.swift b/Signal/src/Loki/Components/NewConversationButtonSet.swift new file mode 100644 index 000000000..39fcd0e69 --- /dev/null +++ b/Signal/src/Loki/Components/NewConversationButtonSet.swift @@ -0,0 +1,271 @@ + +final class NewConversationButtonSet : UIView { + private var isUserDragging = false + private var horizontalButtonConstraints: [NewConversationButton:NSLayoutConstraint] = [:] + private var verticalButtonConstraints: [NewConversationButton:NSLayoutConstraint] = [:] + private var expandedButton: NewConversationButton? + var delegate: NewConversationButtonSetDelegate? + + // MARK: Settings + private let spacing = Values.largeSpacing + private let iconSize = CGFloat(24) + private let maxDragDistance = CGFloat(56) + + // MARK: Components + private lazy var mainButton = NewConversationButton(isMainButton: true, icon: #imageLiteral(resourceName: "Plus").scaled(to: CGSize(width: iconSize, height: iconSize))) + private lazy var newPrivateChatButton = NewConversationButton(isMainButton: false, icon: #imageLiteral(resourceName: "Message").scaled(to: CGSize(width: iconSize, height: iconSize))) + private lazy var newClosedGroupButton = NewConversationButton(isMainButton: false, icon: #imageLiteral(resourceName: "Group").scaled(to: CGSize(width: iconSize, height: iconSize))) + private lazy var joinOpenGroupButton = NewConversationButton(isMainButton: false, icon: #imageLiteral(resourceName: "Globe").scaled(to: CGSize(width: iconSize, height: iconSize))) + + // MARK: Initialization + override init(frame: CGRect) { + super.init(frame: frame) + setUpViewHierarchy() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + setUpViewHierarchy() + } + + private func setUpViewHierarchy() { + let inset = (Values.newConversationButtonExpandedSize - Values.newConversationButtonCollapsedSize) / 2 + addSubview(joinOpenGroupButton) + horizontalButtonConstraints[joinOpenGroupButton] = joinOpenGroupButton.pin(.left, to: .left, of: self, withInset: inset) + verticalButtonConstraints[joinOpenGroupButton] = joinOpenGroupButton.pin(.bottom, to: .bottom, of: self, withInset: -inset) + addSubview(newPrivateChatButton) + newPrivateChatButton.center(.horizontal, in: self) + verticalButtonConstraints[newPrivateChatButton] = newPrivateChatButton.pin(.top, to: .top, of: self, withInset: inset) + addSubview(newClosedGroupButton) + horizontalButtonConstraints[newClosedGroupButton] = newClosedGroupButton.pin(.right, to: .right, of: self, withInset: -inset) + verticalButtonConstraints[newClosedGroupButton] = newClosedGroupButton.pin(.bottom, to: .bottom, of: self, withInset: -inset) + addSubview(mainButton) + mainButton.center(.horizontal, in: self) + mainButton.pin(.bottom, to: .bottom, of: self) + let width = 3 * Values.newConversationButtonExpandedSize + 2 * spacing + set(.width, to: width) + let height = 2 * Values.newConversationButtonExpandedSize + spacing + set(.height, to: height) + collapse(withAnimation: false) + isUserInteractionEnabled = true + let mainButtonTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleMainButtonTapped)) + mainButton.addGestureRecognizer(mainButtonTapGestureRecognizer) + let joinOpenGroupButtonTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleJoinOpenGroupButtonTapped)) + joinOpenGroupButton.addGestureRecognizer(joinOpenGroupButtonTapGestureRecognizer) + let createNewPrivateChatButtonTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleCreateNewPrivateChatButtonTapped)) + newPrivateChatButton.addGestureRecognizer(createNewPrivateChatButtonTapGestureRecognizer) + let createNewClosedGroupButtonTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleCreateNewClosedGroupButtonTapped)) + newClosedGroupButton.addGestureRecognizer(createNewClosedGroupButtonTapGestureRecognizer) + } + + // MARK: Interaction + @objc private func handleMainButtonTapped() { expand(isUserDragging: false) } + @objc private func handleJoinOpenGroupButtonTapped() { delegate?.joinOpenGroup() } + @objc private func handleCreateNewPrivateChatButtonTapped() { delegate?.createNewPrivateChat() } + @objc private func handleCreateNewClosedGroupButtonTapped() { delegate?.createNewClosedGroup() } + + private func expand(isUserDragging: Bool) { + let buttons = [ joinOpenGroupButton, newPrivateChatButton, newClosedGroupButton ] + UIView.animate(withDuration: 0.25, animations: { + buttons.forEach { $0.alpha = 1 } + let inset = (Values.newConversationButtonExpandedSize - Values.newConversationButtonCollapsedSize) / 2 + let size = Values.newConversationButtonCollapsedSize + self.joinOpenGroupButton.frame = CGRect(origin: CGPoint(x: inset, y: self.height() - size - inset), size: CGSize(width: size, height: size)) + self.newPrivateChatButton.frame = CGRect(center: CGPoint(x: self.bounds.center.x, y: inset + size / 2), size: CGSize(width: size, height: size)) + self.newClosedGroupButton.frame = CGRect(origin: CGPoint(x: self.width() - size - inset, y: self.height() - size - inset), size: CGSize(width: size, height: size)) + }, completion: { _ in + self.isUserDragging = isUserDragging + }) + } + + private func collapse(withAnimation isAnimated: Bool) { + isUserDragging = false + let buttons = [ joinOpenGroupButton, newPrivateChatButton, newClosedGroupButton ] + UIView.animate(withDuration: isAnimated ? 0.25 : 0) { + buttons.forEach { button in + button.alpha = 0 + let size = Values.newConversationButtonCollapsedSize + button.frame = CGRect(center: self.mainButton.center, size: CGSize(width: size, height: size)) + } + } + } + + private func reset() { + let mainButtonLocationInSelfCoordinates = CGPoint(x: width() / 2, y: height() - Values.newConversationButtonExpandedSize / 2) + let mainButtonSize = mainButton.frame.size + UIView.animate(withDuration: 0.25) { + self.mainButton.frame = CGRect(center: mainButtonLocationInSelfCoordinates, size: mainButtonSize) + self.mainButton.alpha = 1 + } + if let expandedButton = expandedButton { collapse(expandedButton) } + expandedButton = nil + Timer.scheduledTimer(withTimeInterval: 0.25, repeats: false) { _ in + self.collapse(withAnimation: true) + } + } + + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + guard let touch = touches.first, mainButton.contains(touch), !isUserDragging else { return } + UIImpactFeedbackGenerator(style: .medium).impactOccurred() + expand(isUserDragging: true) + } + + override func touchesMoved(_ touches: Set, with event: UIEvent?) { + guard let touch = touches.first, isUserDragging else { return } + let mainButtonSize = mainButton.frame.size + let mainButtonLocationInSelfCoordinates = CGPoint(x: width() / 2, y: height() - Values.newConversationButtonExpandedSize / 2) + let touchLocationInSelfCoordinates = touch.location(in: self) + mainButton.frame = CGRect(center: touchLocationInSelfCoordinates, size: mainButtonSize) + mainButton.alpha = 1 - (touchLocationInSelfCoordinates.distance(to: mainButtonLocationInSelfCoordinates) / maxDragDistance) + let buttons = [ joinOpenGroupButton, newPrivateChatButton, newClosedGroupButton ] + let buttonToExpand = buttons.first { $0.contains(touch) } + if let buttonToExpand = buttonToExpand { + guard buttonToExpand != expandedButton else { return } + if let expandedButton = expandedButton { collapse(expandedButton) } + expand(buttonToExpand) + expandedButton = buttonToExpand + } else { + if let expandedButton = expandedButton { collapse(expandedButton) } + expandedButton = nil + } + } + + override func touchesEnded(_ touches: Set, with event: UIEvent?) { + guard let touch = touches.first, isUserDragging else { return } + if joinOpenGroupButton.contains(touch) { delegate?.joinOpenGroup() } + else if newPrivateChatButton.contains(touch) { delegate?.createNewPrivateChat() } + else if newClosedGroupButton.contains(touch) { delegate?.createNewClosedGroup() } + reset() + } + + override func touchesCancelled(_ touches: Set, with event: UIEvent?) { + guard isUserDragging else { return } + reset() + } + + private func expand(_ button: NewConversationButton) { + if let horizontalConstraint = horizontalButtonConstraints[button] { horizontalConstraint.constant = 0 } + if let verticalConstraint = verticalButtonConstraints[button] { verticalConstraint.constant = 0 } + let size = Values.newConversationButtonExpandedSize + let frame = CGRect(center: button.center, size: CGSize(width: size, height: size)) + button.widthConstraint.constant = size + button.heightConstraint.constant = size + UIView.animate(withDuration: 0.25) { + self.layoutIfNeeded() + button.frame = frame + button.layer.cornerRadius = size / 2 + button.addGlow(ofSize: size) + button.backgroundColor = Colors.accent + } + } + + private func collapse(_ button: NewConversationButton) { + let inset = (Values.newConversationButtonExpandedSize - Values.newConversationButtonCollapsedSize) / 2 + if joinOpenGroupButton == expandedButton { + horizontalButtonConstraints[joinOpenGroupButton]!.constant = inset + verticalButtonConstraints[joinOpenGroupButton]!.constant = -inset + } else if newPrivateChatButton == expandedButton { + verticalButtonConstraints[newPrivateChatButton]!.constant = inset + } else if newClosedGroupButton == expandedButton { + horizontalButtonConstraints[newClosedGroupButton]!.constant = -inset + verticalButtonConstraints[newClosedGroupButton]!.constant = -inset + } + let size = Values.newConversationButtonCollapsedSize + let frame = CGRect(center: button.center, size: CGSize(width: size, height: size)) + button.widthConstraint.constant = size + button.heightConstraint.constant = size + UIView.animate(withDuration: 0.25) { + self.layoutIfNeeded() + button.frame = frame + button.layer.cornerRadius = size / 2 + button.removeGlow() + button.backgroundColor = Colors.newConversationButtonCollapsedBackground + } + } +} + +// MARK: Delegate +protocol NewConversationButtonSetDelegate { + + func joinOpenGroup() + func createNewPrivateChat() + func createNewClosedGroup() +} + +// MARK: Button +private final class NewConversationButton : UIImageView { + private let isMainButton: Bool + private let icon: UIImage + var widthConstraint: NSLayoutConstraint! + var heightConstraint: NSLayoutConstraint! + + // Initialization + init(isMainButton: Bool, icon: UIImage) { + self.isMainButton = isMainButton + self.icon = icon + super.init(frame: CGRect.zero) + setUpViewHierarchy() + } + + override init(frame: CGRect) { + preconditionFailure("Use init(isMainButton:) instead.") + } + + required init?(coder: NSCoder) { + preconditionFailure("Use init(isMainButton:) instead.") + } + + private func setUpViewHierarchy() { + backgroundColor = isMainButton ? Colors.accent : Colors.newConversationButtonCollapsedBackground + let size = isMainButton ? Values.newConversationButtonExpandedSize : Values.newConversationButtonCollapsedSize + layer.cornerRadius = size / 2 + if isMainButton { addGlow(ofSize: size) } + layer.masksToBounds = false + image = icon + contentMode = .center + widthConstraint = set(.width, to: size) + heightConstraint = set(.height, to: size) + } + + // General + func addGlow(ofSize size: CGFloat) { + layer.shadowPath = UIBezierPath(ovalIn: CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: size, height: size))).cgPath + layer.shadowColor = Colors.newConversationButtonShadow.cgColor + layer.shadowOffset = CGSize(width: 0, height: 0.8) + layer.shadowOpacity = 1 + layer.shadowRadius = 6 + } + + func removeGlow() { + layer.shadowPath = nil + layer.shadowColor = nil + layer.shadowOffset = CGSize.zero + layer.shadowOpacity = 0 + layer.shadowRadius = 0 + } +} + +// MARK: Convenience +private extension UIView { + + func contains(_ touch: UITouch) -> Bool { + return bounds.contains(touch.location(in: self)) + } +} + +private extension CGPoint { + + func distance(to otherPoint: CGPoint) -> CGFloat { + return sqrt(pow(self.x - otherPoint.x, 2) + pow(self.y - otherPoint.y, 2)) + } +} + +private extension CGRect { + + init(center: CGPoint, size: CGSize) { + let originX = center.x - size.width / 2 + let originY = center.y - size.height / 2 + let origin = CGPoint(x: originX, y: originY) + self.init(origin: origin, size: size) + } +} diff --git a/Signal/src/Loki/Style Guide/Colors.swift b/Signal/src/Loki/Style Guide/Colors.swift index ee7d5c8e8..eba314018 100644 --- a/Signal/src/Loki/Style Guide/Colors.swift +++ b/Signal/src/Loki/Style Guide/Colors.swift @@ -35,4 +35,5 @@ final class Colors : NSObject { @objc static let composeViewTextFieldBackground = UIColor(hex: 0x141414) @objc static let receivedMessageBackground = UIColor(hex: 0x222325) @objc static let sentMessageBackground = UIColor(hex: 0x3F4146) + @objc static let newConversationButtonCollapsedBackground = UIColor(hex: 0x1F1F1F) } diff --git a/Signal/src/Loki/Style Guide/Values.swift b/Signal/src/Loki/Style Guide/Values.swift index 587f55a10..257e98d5e 100644 --- a/Signal/src/Loki/Style Guide/Values.swift +++ b/Signal/src/Loki/Style Guide/Values.swift @@ -30,7 +30,8 @@ final class Values : NSObject { @objc static let borderThickness = CGFloat(1) @objc static let conversationCellStatusIndicatorSize = CGFloat(14) @objc static let searchBarHeight = CGFloat(36) - @objc static let newConversationButtonSize = CGFloat(45) + @objc static let newConversationButtonCollapsedSize = CGFloat(48) + @objc static let newConversationButtonExpandedSize = CGFloat(60) @objc static let textFieldHeight = isSmallScreen ? CGFloat(48) : CGFloat(80) @objc static let textFieldCornerRadius = CGFloat(8) @objc static let separatorLabelHeight = CGFloat(24) diff --git a/Signal/src/Loki/Utilities/UIImage+Scaling.swift b/Signal/src/Loki/Utilities/UIImage+Scaling.swift new file mode 100644 index 000000000..2645c3d43 --- /dev/null +++ b/Signal/src/Loki/Utilities/UIImage+Scaling.swift @@ -0,0 +1,17 @@ + +extension UIImage { + + func scaled(to size: CGSize) -> UIImage { + var rect = CGRect.zero + let aspectRatio = min(size.width / self.size.width, size.height / self.size.height) + rect.size.width = self.size.width * aspectRatio + rect.size.height = self.size.height * aspectRatio + rect.origin.x = (size.width - rect.size.width) / 2 + rect.origin.y = (size.height - rect.size.height) / 2 + UIGraphicsBeginImageContextWithOptions(size, false, 0) + draw(in: rect) + let result = UIGraphicsGetImageFromCurrentImageContext()! + UIGraphicsEndImageContext() + return result + } +} diff --git a/Signal/src/Loki/View Controllers/HomeVC.swift b/Signal/src/Loki/View Controllers/HomeVC.swift index 554f65498..c9a40faef 100644 --- a/Signal/src/Loki/View Controllers/HomeVC.swift +++ b/Signal/src/Loki/View Controllers/HomeVC.swift @@ -1,5 +1,5 @@ -final class HomeVC : UIViewController, UITableViewDataSource, UITableViewDelegate, UIScrollViewDelegate, UIViewControllerPreviewingDelegate, SeedReminderViewDelegate { +final class HomeVC : UIViewController, UITableViewDataSource, UITableViewDelegate, UIScrollViewDelegate, UIViewControllerPreviewingDelegate, NewConversationButtonSetDelegate, SeedReminderViewDelegate { private var threadViewModelCache: [String:ThreadViewModel] = [:] private var isObservingDatabase = true private var isViewVisible = false { didSet { updateIsObservingDatabase() } } @@ -45,23 +45,9 @@ final class HomeVC : UIViewController, UITableViewDataSource, UITableViewDelegat return result }() - private lazy var newConversationButton: UIButton = { - let result = UIButton() - result.setTitle("+", for: UIControl.State.normal) - result.titleLabel!.font = .systemFont(ofSize: 35) - result.setTitleColor(UIColor(hex: 0x121212), for: UIControl.State.normal) - result.titleEdgeInsets = UIEdgeInsets(top: 0, left: 1, bottom: 4, right: 0) // Slight adjustment to make the plus exactly centered - result.backgroundColor = Colors.accent - let size = Values.newConversationButtonSize - result.layer.cornerRadius = size / 2 - result.layer.shadowPath = UIBezierPath(ovalIn: CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: size, height: size))).cgPath - result.layer.shadowColor = Colors.newConversationButtonShadow.cgColor - result.layer.shadowOffset = CGSize(width: 0, height: 0.8) - result.layer.shadowOpacity = 1 - result.layer.shadowRadius = 6 - result.layer.masksToBounds = false - result.set(.width, to: size) - result.set(.height, to: size) + private lazy var newConversationButtonSet: NewConversationButtonSet = { + let result = NewConversationButtonSet() + result.delegate = self return result }() @@ -113,11 +99,10 @@ final class HomeVC : UIViewController, UITableViewDataSource, UITableViewDelegat // tableView.tableHeaderView = searchBar // searchBar.sizeToFit() // tableView.contentOffset = CGPoint(x: 0, y: searchBar.frame.height) - // Set up new conversation button - newConversationButton.addTarget(self, action: #selector(createPrivateChat), for: UIControl.Event.touchUpInside) - view.addSubview(newConversationButton) - newConversationButton.center(.horizontal, in: view) - newConversationButton.pin(.bottom, to: .bottom, of: view, withInset: -Values.newConversationButtonBottomOffset) // Negative due to how the constraint is set up + // Set up new conversation button set + view.addSubview(newConversationButtonSet) + newConversationButtonSet.center(.horizontal, in: view) + newConversationButtonSet.pin(.bottom, to: .bottom, of: view, withInset: -Values.newConversationButtonBottomOffset) // Negative due to how the constraint is set up // Set up previewing if (traitCollection.forceTouchCapability == .available) { registerForPreviewing(with: self, sourceView: tableView) @@ -261,17 +246,6 @@ final class HomeVC : UIViewController, UITableViewDataSource, UITableViewDelegat let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(openSettings)) profilePictureView.addGestureRecognizer(tapGestureRecognizer) navigationItem.leftBarButtonItem = UIBarButtonItem(customView: profilePictureView) - let newClosedGroupButton = UIButton(type: .custom) - newClosedGroupButton.setImage(#imageLiteral(resourceName: "btnGroup--white"), for: UIControl.State.normal) - newClosedGroupButton.addTarget(self, action: #selector(createClosedGroup), for: UIControl.Event.touchUpInside) - newClosedGroupButton.tintColor = Colors.text - let joinPublicChatButton = UIButton(type: .custom) - joinPublicChatButton.setImage(#imageLiteral(resourceName: "Globe"), for: UIControl.State.normal) - joinPublicChatButton.addTarget(self, action: #selector(joinPublicChat), for: UIControl.Event.touchUpInside) - joinPublicChatButton.tintColor = Colors.text - let buttonStackView = UIStackView(arrangedSubviews: [ newClosedGroupButton, joinPublicChatButton ]) - buttonStackView.axis = .horizontal - navigationItem.rightBarButtonItem = UIBarButtonItem(customView: buttonStackView) } // MARK: Interaction @@ -371,21 +345,21 @@ final class HomeVC : UIViewController, UITableViewDataSource, UITableViewDelegat present(navigationController, animated: true, completion: nil) } - @objc private func joinPublicChat() { + @objc func joinOpenGroup() { let joinPublicChatVC = JoinPublicChatVC() let navigationController = OWSNavigationController(rootViewController: joinPublicChatVC) present(navigationController, animated: true, completion: nil) } - @objc private func createClosedGroup() { - let newClosedGroupVC = NewClosedGroupVC() - let navigationController = OWSNavigationController(rootViewController: newClosedGroupVC) + @objc func createNewPrivateChat() { + let newPrivateChatVC = NewPrivateChatVC() + let navigationController = OWSNavigationController(rootViewController: newPrivateChatVC) present(navigationController, animated: true, completion: nil) } - @objc func createPrivateChat() { - let newPrivateChatVC = NewPrivateChatVC() - let navigationController = OWSNavigationController(rootViewController: newPrivateChatVC) + @objc func createNewClosedGroup() { + let newClosedGroupVC = NewClosedGroupVC() + let navigationController = OWSNavigationController(rootViewController: newClosedGroupVC) present(navigationController, animated: true, completion: nil) } diff --git a/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift b/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift index 3fcf7cace..cb46342ab 100644 --- a/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift +++ b/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift @@ -107,7 +107,7 @@ final class NewClosedGroupVC : UIViewController, UITableViewDataSource, UITableV explanationLabel.text = NSLocalizedString("You don't have any contacts yet", comment: "") let createNewPrivateChatButton = Button(style: .prominentOutline, size: .medium) createNewPrivateChatButton.setTitle(NSLocalizedString("Start a Session", comment: ""), for: UIControl.State.normal) - createNewPrivateChatButton.addTarget(self, action: #selector(createPrivateChat), for: UIControl.Event.touchUpInside) + createNewPrivateChatButton.addTarget(self, action: #selector(createNewPrivateChat), for: UIControl.Event.touchUpInside) createNewPrivateChatButton.set(.width, to: 160) let stackView = UIStackView(arrangedSubviews: [ explanationLabel, createNewPrivateChatButton ]) stackView.axis = .vertical @@ -201,9 +201,9 @@ final class NewClosedGroupVC : UIViewController, UITableViewDataSource, UITableV } } - @objc private func createPrivateChat() { + @objc private func createNewPrivateChat() { presentingViewController?.dismiss(animated: true, completion: nil) - SignalApp.shared().homeViewController!.createPrivateChat() + SignalApp.shared().homeViewController!.createNewPrivateChat() } }