From 29a95fac0babbf2e5ac4d4dee6e07fe7d117cdde Mon Sep 17 00:00:00 2001 From: Bruno Muniz Azevedo Filho <bruno@elixxir.io> Date: Wed, 13 Jul 2022 14:48:48 -0300 Subject: [PATCH] Implemented placeholder UI for usrename search controller --- .../ChatListFeature/Views/ChatListView.swift | 54 ++++++++-------- .../SearchUsernameController.swift | 60 ++++++++++++++++++ .../Views/SearchUsernamePlaceholderView.swift | 61 +++++++++++++++++-- .../Views/SearchUsernameView.swift | 27 ++++---- Sources/Shared/AutoGenerated/Strings.swift | 16 +++++ .../Resources/en.lproj/Localizable.strings | 9 +++ 6 files changed, 186 insertions(+), 41 deletions(-) diff --git a/Sources/ChatListFeature/Views/ChatListView.swift b/Sources/ChatListFeature/Views/ChatListView.swift index c7303c48..03a40798 100644 --- a/Sources/ChatListFeature/Views/ChatListView.swift +++ b/Sources/ChatListFeature/Views/ChatListView.swift @@ -14,7 +14,7 @@ final class ChatListView: UIView { backgroundColor = Asset.neutralWhite.color listContainerView.backgroundColor = Asset.neutralWhite.color searchListContainerView.backgroundColor = Asset.neutralWhite.color - searchView.update(placeholder: "Search chats") + searchView.update(placeholder: Localized.ChatList.Search.title) addSubview(snackBar) addSubview(searchView) @@ -22,6 +22,34 @@ final class ChatListView: UIView { containerView.addSubview(searchListContainerView) containerView.addSubview(listContainerView) + setupConstraints() + } + + required init?(coder: NSCoder) { nil } + + func showConnectingBanner(_ show: Bool) { + if show == true { + snackBar.alpha = 0.0 + snackBar.snp.updateConstraints { + $0.bottom + .equalTo(snp.top) + .offset(snackBar.bounds.height) + } + } else { + snackBar.alpha = 1.0 + snackBar.snp.updateConstraints { + $0.bottom.equalTo(snp.top) + } + } + + UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseInOut) { + self.setNeedsLayout() + self.layoutIfNeeded() + self.snackBar.alpha = show ? 1.0 : 0.0 + } + } + + private func setupConstraints() { snackBar.snp.makeConstraints { $0.left.equalToSuperview() $0.right.equalToSuperview() @@ -49,28 +77,4 @@ final class ChatListView: UIView { $0.edges.equalToSuperview() } } - - required init?(coder: NSCoder) { nil } - - func showConnectingBanner(_ show: Bool) { - if show == true { - snackBar.alpha = 0.0 - snackBar.snp.updateConstraints { - $0.bottom - .equalTo(snp.top) - .offset(snackBar.bounds.height) - } - } else { - snackBar.alpha = 1.0 - snackBar.snp.updateConstraints { - $0.bottom.equalTo(snp.top) - } - } - - UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseInOut) { - self.setNeedsLayout() - self.layoutIfNeeded() - self.snackBar.alpha = show ? 1.0 : 0.0 - } - } } diff --git a/Sources/SearchFeature/Controllers/SearchUsernameController.swift b/Sources/SearchFeature/Controllers/SearchUsernameController.swift index 136951c8..563cc86f 100644 --- a/Sources/SearchFeature/Controllers/SearchUsernameController.swift +++ b/Sources/SearchFeature/Controllers/SearchUsernameController.swift @@ -1,9 +1,69 @@ import UIKit +import Shared +import Combine +import DrawerFeature +import DependencyInjection final class SearchUsernameController: UIViewController { + @Dependency private var coordinator: SearchCoordinating + lazy private var screenView = SearchUsernameView() + private var cancellables = Set<AnyCancellable>() + private var drawerCancellables = Set<AnyCancellable>() + override func loadView() { view = screenView } + + override func viewDidLoad() { + super.viewDidLoad() + setupBindings() + } + + private func setupBindings() { + screenView.placeholderView + .infoPublisher + .receive(on: DispatchQueue.main) + .sink { [unowned self] in presentSearchDisclaimer() } + .store(in: &cancellables) + } + + private func presentSearchDisclaimer() { + let actionButton = CapsuleButton() + actionButton.set( + style: .seeThrough, + title: Localized.Ud.Placeholder.Drawer.action + ) + + let drawer = DrawerController(with: [ + DrawerText( + font: Fonts.Mulish.bold.font(size: 26.0), + text: Localized.Ud.Placeholder.Drawer.title, + color: Asset.neutralActive.color, + alignment: .left, + spacingAfter: 19 + ), + DrawerLinkText( + text: Localized.Ud.Placeholder.Drawer.subtitle, + urlString: "https://links.xx.network/adrp", + spacingAfter: 37 + ), + DrawerStack(views: [ + actionButton, + FlexibleSpace() + ]) + ]) + + actionButton.publisher(for: .touchUpInside) + .receive(on: DispatchQueue.main) + .sink { + drawer.dismiss(animated: true) { [weak self] in + guard let self = self else { return } + self.drawerCancellables.removeAll() + } + }.store(in: &self.drawerCancellables) + + coordinator.toDrawer(drawer, from: self) + } } diff --git a/Sources/SearchFeature/Views/SearchUsernamePlaceholderView.swift b/Sources/SearchFeature/Views/SearchUsernamePlaceholderView.swift index effcf607..8b249aac 100644 --- a/Sources/SearchFeature/Views/SearchUsernamePlaceholderView.swift +++ b/Sources/SearchFeature/Views/SearchUsernamePlaceholderView.swift @@ -1,20 +1,73 @@ import UIKit import Shared +import Combine final class SearchUsernamePlaceholderView: UIView { let titleLabel = UILabel() + let subtitleWithInfo = TextWithInfoView() + + var infoPublisher: AnyPublisher<Void, Never> { + infoSubject.eraseToAnyPublisher() + } + + private let infoSubject = PassthroughSubject<Void, Never>() init() { super.init(frame: .zero) - titleLabel.text = "[SearchUsernamePlaceholderView]" + let attrString = NSMutableAttributedString( + string: Localized.Ud.Username.Search.Placeholder.title, + attributes: [ + .foregroundColor: Asset.neutralDark.color, + .font: Fonts.Mulish.bold.font(size: 32.0) + ] + ) + + attrString.addAttribute( + name: .foregroundColor, + value: Asset.brandPrimary.color, + betweenCharacters: "#" + ) + + titleLabel.numberOfLines = 0 + titleLabel.attributedText = attrString + + let paragraph = NSMutableParagraphStyle() + paragraph.lineHeightMultiple = 1.3 + + subtitleWithInfo.setup( + text: Localized.Ud.Username.Search.Placeholder.subtitle, + attributes: [ + .paragraphStyle: paragraph, + .foregroundColor: Asset.neutralBody.color, + .font: Fonts.Mulish.regular.font(size: 16.0) + ], + didTapInfo: { [weak self] in + guard let self = self else { return } + self.infoSubject.send(()) + } + ) addSubview(titleLabel) + addSubview(subtitleWithInfo) - titleLabel.snp.makeConstraints { - $0.center.equalToSuperview() - } + setupConstraints() } required init?(coder: NSCoder) { nil } + + private func setupConstraints() { + titleLabel.snp.makeConstraints { + $0.top.equalToSuperview().offset(50) + $0.left.equalToSuperview() + $0.right.equalToSuperview() + } + + subtitleWithInfo.snp.makeConstraints { + $0.top.equalTo(titleLabel.snp.bottom).offset(30) + $0.left.equalToSuperview() + $0.right.equalToSuperview() + $0.bottom.equalToSuperview() + } + } } diff --git a/Sources/SearchFeature/Views/SearchUsernameView.swift b/Sources/SearchFeature/Views/SearchUsernameView.swift index 2dd66fcd..f8c56223 100644 --- a/Sources/SearchFeature/Views/SearchUsernameView.swift +++ b/Sources/SearchFeature/Views/SearchUsernameView.swift @@ -3,34 +3,37 @@ import Shared import InputField final class SearchUsernameView: UIView { - let inputField = InputField() + let inputField = SearchComponent() let placeholderView = SearchUsernamePlaceholderView() init() { super.init(frame: .zero) - inputField.setup( - style: .regular, - title: "Username", - placeholder: "Username" + inputField.set( + placeholder: Localized.Ud.Username.Search.inputPlaceholder, + imageAtRight: nil ) addSubview(inputField) addSubview(placeholderView) + setupConstraints() + } + + required init?(coder: NSCoder) { nil } + + private func setupConstraints() { inputField.snp.makeConstraints { - $0.top.equalToSuperview().offset(15) - $0.left.equalToSuperview().offset(15) - $0.right.equalToSuperview().offset(-15) + $0.top.equalToSuperview().offset(20) + $0.left.equalToSuperview().offset(20) + $0.right.equalToSuperview().offset(-20) } placeholderView.snp.makeConstraints { $0.top.equalTo(inputField.snp.bottom) - $0.left.equalToSuperview() - $0.right.equalToSuperview() + $0.left.equalToSuperview().offset(32.5) + $0.right.equalToSuperview().offset(-32.5) $0.bottom.equalToSuperview() } } - - required init?(coder: NSCoder) { nil } } diff --git a/Sources/Shared/AutoGenerated/Strings.swift b/Sources/Shared/AutoGenerated/Strings.swift index 9f9fbfb2..2265b055 100644 --- a/Sources/Shared/AutoGenerated/Strings.swift +++ b/Sources/Shared/AutoGenerated/Strings.swift @@ -430,6 +430,10 @@ public enum Localized { /// Cancel public static let cancel = Localized.tr("Localizable", "chatList.navigationBar.cancel") } + public enum Search { + /// Search chats + public static let title = Localized.tr("Localizable", "chatList.search.title") + } public enum Traffic { /// Not now public static let negative = Localized.tr("Localizable", "chatList.traffic.negative") @@ -1247,6 +1251,18 @@ public enum Localized { /// Username public static let username = Localized.tr("Localizable", "ud.tab.username") } + public enum Username { + public enum Search { + /// Search by username + public static let inputPlaceholder = Localized.tr("Localizable", "ud.username.search.inputPlaceholder") + public enum Placeholder { + /// Your searches are anonymous. Search information is never linked to your account or personally identifiable. + public static let subtitle = Localized.tr("Localizable", "ud.username.search.placeholder.subtitle") + /// Search for #friends# anonymously, add them to your #connections# to start a completely private messaging channel. + public static let title = Localized.tr("Localizable", "ud.username.search.placeholder.title") + } + } + } } public enum Validator { diff --git a/Sources/Shared/Resources/en.lproj/Localizable.strings b/Sources/Shared/Resources/en.lproj/Localizable.strings index 3aa07ced..e16bf6fa 100644 --- a/Sources/Shared/Resources/en.lproj/Localizable.strings +++ b/Sources/Shared/Resources/en.lproj/Localizable.strings @@ -25,6 +25,8 @@ // ChatListFeature +"chatList.search.title" += "Search chats"; "chatList.navigationBar.cancel" = "Cancel"; "chatList.title" @@ -985,6 +987,13 @@ "ud.nicknameDrawer.save" = "Save"; +"ud.username.search.inputPlaceholder" += "Search by username"; +"ud.username.search.placeholder.title" += "Search for #friends# anonymously, add them to your #connections# to start a completely private messaging channel."; +"ud.username.search.placeholder.subtitle" += "Your searches are anonymous. Search information is never linked to your account or personally identifiable."; + // LaunchFeature "launch.version.failed" -- GitLab