Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
|
|
@ -0,0 +1,65 @@
|
|||
protocol SearchCategoriesViewControllerDelegate: SearchOnMapScrollViewDelegate {
|
||||
func categoriesViewController(_ viewController: SearchCategoriesViewController,
|
||||
didSelect category: String)
|
||||
}
|
||||
|
||||
final class SearchCategoriesViewController: MWMTableViewController {
|
||||
private weak var delegate: SearchCategoriesViewControllerDelegate?
|
||||
private let categories: [String]
|
||||
|
||||
init(frameworkHelper: MWMSearchFrameworkHelper.Type, delegate: SearchCategoriesViewControllerDelegate?) {
|
||||
self.delegate = delegate
|
||||
categories = frameworkHelper.searchCategories()
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
tableView.setStyle(.background)
|
||||
tableView.register(cell: SearchCategoryCell.self)
|
||||
tableView.keyboardDismissMode = .onDrag
|
||||
let footerHeight = (UIApplication.shared.connectedScenes.filter { $0.activationState == .foregroundActive }.first(where: { $0 is UIWindowScene }) as? UIWindowScene)?.keyWindow?.safeAreaInsets.bottom ?? 1
|
||||
tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: footerHeight))
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return categories.count
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(cell: SearchCategoryCell.self, indexPath: indexPath)
|
||||
cell.configure(with: category(at: indexPath))
|
||||
return cell
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let selectedCategory = category(at: indexPath)
|
||||
delegate?.categoriesViewController(self, didSelect: selectedCategory)
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
}
|
||||
|
||||
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
delegate?.scrollViewDidScroll(scrollView)
|
||||
}
|
||||
|
||||
override func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
|
||||
delegate?.scrollViewWillEndDragging(scrollView, withVelocity: velocity, targetContentOffset: targetContentOffset)
|
||||
}
|
||||
|
||||
func category(at indexPath: IndexPath) -> String {
|
||||
let index = indexPath.row
|
||||
return categories[index]
|
||||
}
|
||||
}
|
||||
|
||||
extension SearchCategoriesViewController: ModallyPresentedViewController {
|
||||
func presentationFrameDidChange(_ frame: CGRect) {
|
||||
guard isViewLoaded else { return }
|
||||
tableView.contentInset.bottom = frame.origin.y + view.safeAreaInsets.bottom
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
final class SearchCategoryCell: UITableViewCell {
|
||||
|
||||
private var categoryName: String = ""
|
||||
|
||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: .default, reuseIdentifier: reuseIdentifier)
|
||||
setStyle(.defaultTableViewCell)
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func configure(with categoryName: String) {
|
||||
self.categoryName = categoryName
|
||||
textLabel?.text = L(categoryName)
|
||||
imageView?.image = UIImage(named: String(format: "Search/Categories/%@", categoryName.replacingOccurrences(of: "category_", with: "")))
|
||||
}
|
||||
|
||||
override func applyTheme() {
|
||||
super.applyTheme()
|
||||
imageView?.image = UIImage(named: String(format: "Search/Categories/%@", categoryName.replacingOccurrences(of: "category_", with: "")))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
final class SearchHistoryCell: MWMTableViewCell {
|
||||
enum Content {
|
||||
case query(String)
|
||||
case clear
|
||||
}
|
||||
|
||||
static private let placeholderImage = UIImage.filled(with: .clear, size: CGSize(width: 28, height: 28))
|
||||
|
||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: .default, reuseIdentifier: reuseIdentifier)
|
||||
setStyle(.defaultTableViewCell)
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func configure(for content: Content) {
|
||||
switch content {
|
||||
case .query(let query):
|
||||
textLabel?.text = query
|
||||
textLabel?.setFontStyleAndApply(.regular17, color: .blackSecondary)
|
||||
imageView?.image = UIImage(resource: .icSearch)
|
||||
imageView?.setStyleAndApply(.black)
|
||||
isSeparatorHidden = false
|
||||
case .clear:
|
||||
textLabel?.text = L("clear_search")
|
||||
textLabel?.setFontStyleAndApply(.regular14, color: .linkBlue)
|
||||
imageView?.image = Self.placeholderImage
|
||||
isSeparatorHidden = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
protocol SearchHistoryViewControllerDelegate: SearchOnMapScrollViewDelegate {
|
||||
func searchHistoryViewController(_ viewController: SearchHistoryViewController,
|
||||
didSelect query: String)
|
||||
}
|
||||
|
||||
final class SearchHistoryViewController: MWMViewController {
|
||||
private weak var delegate: SearchHistoryViewControllerDelegate?
|
||||
private var lastQueries: [String] = []
|
||||
private let frameworkHelper: MWMSearchFrameworkHelper.Type
|
||||
private let emptyHistoryView = PlaceholderView(title: L("search_history_title"),
|
||||
subtitle: L("search_history_text"))
|
||||
|
||||
private let tableView = UITableView()
|
||||
|
||||
// MARK: - Init
|
||||
init(frameworkHelper: MWMSearchFrameworkHelper.Type, delegate: SearchHistoryViewControllerDelegate?) {
|
||||
self.delegate = delegate
|
||||
self.frameworkHelper = frameworkHelper
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
// MARK: - Lifecycle
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
setupTableView()
|
||||
setupNoResultsView()
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
reload()
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
private func setupTableView() {
|
||||
tableView.setStyle(.background)
|
||||
tableView.register(cell: SearchHistoryCell.self)
|
||||
tableView.keyboardDismissMode = .onDrag
|
||||
tableView.delegate = self
|
||||
tableView.dataSource = self
|
||||
let footerHeight = (UIApplication.shared.connectedScenes.filter { $0.activationState == .foregroundActive }.first(where: { $0 is UIWindowScene }) as? UIWindowScene)?.keyWindow?.safeAreaInsets.bottom ?? 1
|
||||
tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: footerHeight))
|
||||
|
||||
view.addSubview(tableView)
|
||||
tableView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
tableView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
|
||||
])
|
||||
}
|
||||
|
||||
private func setupNoResultsView() {
|
||||
view.addSubview(emptyHistoryView)
|
||||
emptyHistoryView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
emptyHistoryView.topAnchor.constraint(equalTo: view.topAnchor),
|
||||
emptyHistoryView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
||||
emptyHistoryView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
emptyHistoryView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
|
||||
])
|
||||
}
|
||||
|
||||
private func showEmptyHistoryView(_ isVisible: Bool = true, animated: Bool = true) {
|
||||
UIView.transition(with: emptyHistoryView,
|
||||
duration: animated ? kDefaultAnimationDuration : 0,
|
||||
options: [.transitionCrossDissolve, .curveEaseInOut]) {
|
||||
self.emptyHistoryView.alpha = isVisible ? 1.0 : 0.0
|
||||
self.emptyHistoryView.isHidden = !isVisible
|
||||
}
|
||||
}
|
||||
|
||||
private func clearSearchHistory() {
|
||||
frameworkHelper.clearSearchHistory()
|
||||
reload()
|
||||
}
|
||||
|
||||
// MARK: - Public methods
|
||||
func reload() {
|
||||
guard isViewLoaded else { return }
|
||||
lastQueries = frameworkHelper.lastSearchQueries()
|
||||
showEmptyHistoryView(lastQueries.isEmpty ? true : false)
|
||||
tableView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
extension SearchHistoryViewController: UITableViewDataSource {
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return lastQueries.isEmpty ? 0 : lastQueries.count + 1
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
let cell = tableView.dequeueReusableCell(cell: SearchHistoryCell.self, indexPath: indexPath)
|
||||
if indexPath.row == lastQueries.count {
|
||||
cell.configure(for: .clear)
|
||||
} else {
|
||||
cell.configure(for: .query(lastQueries[indexPath.row]))
|
||||
}
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
extension SearchHistoryViewController: UITableViewDelegate {
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
if indexPath.row == lastQueries.count {
|
||||
clearSearchHistory()
|
||||
} else {
|
||||
let query = lastQueries[indexPath.row]
|
||||
delegate?.searchHistoryViewController(self, didSelect: query)
|
||||
}
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
}
|
||||
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
delegate?.scrollViewDidScroll(scrollView)
|
||||
}
|
||||
}
|
||||
|
||||
extension SearchHistoryViewController: ModallyPresentedViewController {
|
||||
func presentationFrameDidChange(_ frame: CGRect) {
|
||||
guard isViewLoaded else { return }
|
||||
tableView.contentInset.bottom = frame.origin.y
|
||||
emptyHistoryView.presentationFrameDidChange(frame)
|
||||
}
|
||||
}
|
||||
87
iphone/Maps/UI/Search/Tabs/SearchTabViewController.swift
Normal file
87
iphone/Maps/UI/Search/Tabs/SearchTabViewController.swift
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
@objc(MWMSearchTabViewControllerDelegate)
|
||||
protocol SearchTabViewControllerDelegate: SearchOnMapScrollViewDelegate {
|
||||
func searchTabController(_ viewController: SearchTabViewController, didSearch: SearchQuery)
|
||||
}
|
||||
|
||||
@objc(MWMSearchTabViewController)
|
||||
final class SearchTabViewController: TabViewController {
|
||||
private enum SearchActiveTab: Int {
|
||||
case history = 0
|
||||
case categories
|
||||
}
|
||||
|
||||
private static let selectedIndexKey = "SearchTabViewController_selectedIndexKey"
|
||||
@objc weak var delegate: SearchTabViewControllerDelegate?
|
||||
|
||||
private var frameworkHelper = MWMSearchFrameworkHelper.self
|
||||
|
||||
private var activeTab: SearchActiveTab = SearchActiveTab.init(rawValue:
|
||||
UserDefaults.standard.integer(forKey: SearchTabViewController.selectedIndexKey)) ?? .categories {
|
||||
didSet {
|
||||
UserDefaults.standard.set(activeTab.rawValue, forKey: SearchTabViewController.selectedIndexKey)
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
let history = SearchHistoryViewController(frameworkHelper: frameworkHelper,
|
||||
delegate: self)
|
||||
history.title = L("history")
|
||||
|
||||
let categories = SearchCategoriesViewController(frameworkHelper: frameworkHelper,
|
||||
delegate: self)
|
||||
categories.title = L("categories")
|
||||
viewControllers = [history, categories]
|
||||
|
||||
if frameworkHelper.isSearchHistoryEmpty() {
|
||||
tabView.selectedIndex = SearchActiveTab.categories.rawValue
|
||||
} else {
|
||||
tabView.selectedIndex = activeTab.rawValue
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidDisappear(_ animated: Bool) {
|
||||
super.viewDidDisappear(animated)
|
||||
activeTab = SearchActiveTab.init(rawValue: tabView.selectedIndex ?? 0) ?? .categories
|
||||
}
|
||||
|
||||
func reloadSearchHistory() {
|
||||
(viewControllers[SearchActiveTab.history.rawValue] as? SearchHistoryViewController)?.reload()
|
||||
}
|
||||
}
|
||||
|
||||
extension SearchTabViewController: ModallyPresentedViewController {
|
||||
func presentationFrameDidChange(_ frame: CGRect) {
|
||||
viewControllers.forEach { ($0 as? ModallyPresentedViewController)?.presentationFrameDidChange(frame) }
|
||||
}
|
||||
}
|
||||
|
||||
extension SearchTabViewController: SearchOnMapScrollViewDelegate {
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
delegate?.scrollViewDidScroll(scrollView)
|
||||
}
|
||||
|
||||
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
|
||||
delegate?.scrollViewWillEndDragging(scrollView, withVelocity: velocity, targetContentOffset: targetContentOffset)
|
||||
}
|
||||
}
|
||||
|
||||
extension SearchTabViewController: SearchCategoriesViewControllerDelegate {
|
||||
func categoriesViewController(_ viewController: SearchCategoriesViewController,
|
||||
didSelect category: String) {
|
||||
let preferredLang = AppInfo.shared().languageId
|
||||
let supportedBySearchLang = MWMSearchFrameworkHelper.isLanguageSupported(preferredLang) ? preferredLang : "en"
|
||||
let searchText = L(category, languageCode: supportedBySearchLang) + " "
|
||||
let query = SearchQuery(searchText, locale: supportedBySearchLang, source: .category)
|
||||
delegate?.searchTabController(self, didSearch: query)
|
||||
}
|
||||
}
|
||||
|
||||
extension SearchTabViewController: SearchHistoryViewControllerDelegate {
|
||||
func searchHistoryViewController(_ viewController: SearchHistoryViewController,
|
||||
didSelect query: String) {
|
||||
let query = SearchQuery(query.trimmingCharacters(in: .whitespacesAndNewlines) + " ", source: .history)
|
||||
delegate?.searchTabController(self, didSearch: query)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue