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 000000000..be41ce92d Binary files /dev/null and b/Signal/Images.xcassets/Loki V2/Group.imageset/Group.pdf differ 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 000000000..46a40dafd Binary files /dev/null and b/Signal/Images.xcassets/Loki V2/Message.imageset/Message.pdf differ 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 000000000..7d6855b3b Binary files /dev/null and b/Signal/Images.xcassets/Loki V2/Plus.imageset/Plus.pdf differ 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() } }