-
Notifications
You must be signed in to change notification settings - Fork 385
Allow for quick toggle between open/closed issues #2687
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,7 +29,8 @@ IndicatorInfoProvider { | |
private let type: RepositoryIssuesType | ||
private let searchKey: ListDiffable = "searchKey" as ListDiffable | ||
private let debouncer = Debouncer() | ||
private var previousSearchString = "is:open " | ||
private var previousSearchString = "" | ||
private var prefix = "is:open " | ||
private var label: String? | ||
|
||
init(client: GithubClient, owner: String, repo: String, type: RepositoryIssuesType, label: String? = nil) { | ||
|
@@ -103,14 +104,23 @@ IndicatorInfoProvider { | |
debouncer.action = { [weak self] in self?.fetch(page: nil) } | ||
} | ||
|
||
func didChangeSegment(sectionController: SearchBarSectionController, index: Int) { | ||
switch index { | ||
case 0: updateState(isOpen: true) | ||
case 1: updateState(isOpen: false) | ||
default: break | ||
} | ||
} | ||
|
||
// MARK: BaseListViewControllerHeaderDataSource | ||
|
||
func headerModel(for adapter: ListSwiftAdapter) -> ListSwiftPair { | ||
return ListSwiftPair.pair("header", { [weak self, previousSearchString] in | ||
SearchBarSectionController( | ||
placeholder: Constants.Strings.search, | ||
delegate: self, | ||
query: previousSearchString | ||
query: previousSearchString, | ||
items: ["Open", "Closed"] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Localization? Also... what would this look like if these would be awfully long? Not sure if that would scale... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well localization of those would never be done here, it would be done before adding to the segment control. Aka, user passes in array of strings, we localize and add to control. |
||
) | ||
}) | ||
} | ||
|
@@ -151,7 +161,12 @@ IndicatorInfoProvider { | |
case .issues: typeQuery = "is:issue" | ||
case .pullRequests: typeQuery = "is:pr" | ||
} | ||
return "repo:\(owner)/\(repo) \(typeQuery) \(previousSearchString)".lowercased() | ||
return "repo:\(owner)/\(repo) \(typeQuery) \(prefix + previousSearchString)".lowercased() | ||
} | ||
|
||
func updateState(isOpen: Bool = true) { | ||
prefix = isOpen ? "is:open " : "is:closed " | ||
debouncer.action = { [weak self] in self?.fetch(page: nil) } | ||
} | ||
|
||
// MARK: IndicatorInfoProvider | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
// | ||
// SearchSegementBarCell.swift | ||
// Freetime | ||
// | ||
// Created by Ehud Adler on 3/12/19. | ||
// Copyright © 2019 Ryan Nystrom. All rights reserved. | ||
// | ||
|
||
import UIKit | ||
import SnapKit | ||
|
||
final class SearchSegmentBarCell: UICollectionViewCell, SearchableCell, UISearchBarDelegate { | ||
|
||
weak var delegate: SearchBarCellDelegate? | ||
|
||
private let searchBar = UISearchBar(frame: .zero) | ||
private let segmentControl = UISegmentedControl(frame: .zero) | ||
var segmentControlLeadingConstraint: Constraint! | ||
|
||
override init(frame: CGRect) { | ||
super.init(frame: frame) | ||
backgroundColor = .white | ||
|
||
searchBar.returnKeyType = .search | ||
searchBar.enablesReturnKeyAutomatically = false | ||
searchBar.searchBarStyle = .minimal | ||
searchBar.delegate = self | ||
|
||
contentView.addSubview(searchBar) | ||
contentView.addSubview(segmentControl) | ||
|
||
searchBar.snp.makeConstraints { make in | ||
make.leading.centerY.equalTo(contentView) | ||
make.trailing.equalTo(segmentControl.snp.leading) | ||
} | ||
|
||
segmentControl.snp.makeConstraints { make in | ||
segmentControlLeadingConstraint = make.leading.equalTo(contentView.snp.trailing).constraint | ||
make.trailing.equalTo(contentView.safeAreaLayoutGuide).inset(15) | ||
make.top.bottom.equalTo(contentView) | ||
|
||
} | ||
|
||
segmentControl.addTarget(self, action: #selector(updateSegement), for: .valueChanged) | ||
|
||
setSegmentControl() | ||
segmentControlLeadingConstraint.deactivate() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you need this constraint for if you There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Deactivated on start due to the search bar not being in editing mode. Once you start editing the constraint becomes activated |
||
searchBar.resignWhenKeyboardHides() | ||
segmentControl.removeBorders() | ||
} | ||
|
||
required init?(coder aDecoder: NSCoder) { | ||
fatalError("init(coder:) has not been implemented") | ||
} | ||
|
||
override func layoutSubviews() { | ||
super.layoutSubviews() | ||
layoutContentView() | ||
} | ||
|
||
// MARK: Public API | ||
|
||
func set(items: [String], selectedIndex: Int = 0) { | ||
for title in items { | ||
segmentControl.insertSegment( | ||
withTitle: title, | ||
at: segmentControl.numberOfSegments, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm reading this as it will always insert it at the end as the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes correct, the order in which you pass in the array is the order it will appear. |
||
animated: true | ||
) | ||
} | ||
segmentControl.selectedSegmentIndex = selectedIndex | ||
} | ||
|
||
func configure(query: String, placeholder: String) { | ||
searchBar.text = query | ||
searchBar.placeholder = placeholder | ||
} | ||
|
||
// MARK: Private API | ||
|
||
func setSegmentControl() { | ||
|
||
segmentControl.backgroundColor = .clear | ||
segmentControl.tintColor = .clear | ||
|
||
let normalFont: [AnyHashable: Any] = [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure thing! |
||
NSAttributedStringKey.foregroundColor: Styles.Colors.Gray.dark.color, | ||
NSAttributedStringKey.font: UIFont.systemFont(ofSize: 15) | ||
] | ||
let selectedFont: [AnyHashable: Any] = [ | ||
NSAttributedStringKey.foregroundColor: Styles.Colors.Blue.medium.color, | ||
NSAttributedStringKey.font: UIFont.systemFont(ofSize: 15) | ||
] | ||
segmentControl.setTitleTextAttributes(normalFont, for: .normal) | ||
segmentControl.setTitleTextAttributes(selectedFont, for: .selected) | ||
} | ||
|
||
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { | ||
delegate?.didChangeSearchText(cell: self, query: searchText) | ||
} | ||
|
||
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { | ||
searchBar.resignFirstResponder() | ||
} | ||
|
||
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) { | ||
UIView.animate(withDuration: 0.3) { | ||
self.segmentControlLeadingConstraint.deactivate() | ||
self.segmentControl.alpha = 1 | ||
self.layoutIfNeeded() | ||
} | ||
} | ||
|
||
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) { | ||
UIView.animate(withDuration: 0.3) { | ||
self.segmentControlLeadingConstraint.activate() | ||
self.segmentControl.alpha = 0 | ||
self.layoutIfNeeded() | ||
} | ||
|
||
} | ||
|
||
@objc func updateSegement() { | ||
delegate?.didChangeSegment(cell: self, index: self.segmentControl.selectedSegmentIndex) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// | ||
// SegmentControl+Border.swift | ||
// Freetime | ||
// | ||
// Created by Ehud Adler on 3/12/19. | ||
// Copyright © 2019 Ryan Nystrom. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
extension UISegmentedControl { | ||
func removeBorders() { | ||
setBackgroundImage(imageWithColor(color: backgroundColor ?? .white), for: .normal, barMetrics: .default) | ||
setBackgroundImage(imageWithColor(color: tintColor ?? .white), for: .selected, barMetrics: .default) | ||
setDividerImage(imageWithColor(color: UIColor.clear), forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default) | ||
} | ||
|
||
// create a 1x1 image with this color | ||
private func imageWithColor(color: UIColor) -> UIImage { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we have this somewhere else already by chance? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ill search |
||
let rect = CGRect(x: 0.0, y: 0.0, width: 1.0, height: 1.0) | ||
UIGraphicsBeginImageContext(rect.size) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should be able to use |
||
if let context = UIGraphicsGetCurrentContext() { | ||
context.setFillColor(color.cgColor) | ||
context.fill(rect) | ||
} | ||
let image = UIGraphicsGetImageFromCurrentImageContext() | ||
UIGraphicsEndImageContext() | ||
return image! | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does the GitHub highlighter think
prefix
is a keyword? 🤔There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤷 Problem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No should be good 😊