Skip to content

Commit

Permalink
Merge pull request #97 from boostcamp-2020/iOS-filter-logic
Browse files Browse the repository at this point in the history
 [feat] 필터 화면 구현
  • Loading branch information
devilzCough authored Nov 10, 2020
2 parents 66b9f6a + 6fb5b4c commit 51c0f65
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ extension Notification.Name {
static let issueDidChange = Notification.Name("issueDidChange")
static let labelDidChange = Notification.Name("labelDidChange")
static let milestoneDidChange = Notification.Name("milestoneDidChange")
static let issueFilterDidChange = Notification.Name("issueFilterDidChange")
}
21 changes: 14 additions & 7 deletions iOS/IssueTracker/IssueTracker/Issue/View/FilterTableViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,35 @@ class FilterTableViewCell: UITableViewCell {
@IBOutlet weak var accessoryImageView: UIImageView!

private var section = 0
private var hasChild = false
private var isChild = false

override func awakeFromNib() {
super.awakeFromNib()
if section == 1 && hasChild {
if section == 1 {
if isChild {
backgroundColor = UIColor.systemGray6
}
accessoryImageView.image = UIImage(systemName: "chevron.right")
}
}

override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
if section == 1 && hasChild {
accessoryImageView.image = selected ? UIImage(systemName: "chevron.down") : UIImage(systemName: "chevron.right")
} else {
accessoryImageView.image = selected ? UIImage(systemName: "checkmark") : nil
if section == 1 && !isChild {
DispatchQueue.main.async { [weak self] in
self?.accessoryImageView.image = selected ? UIImage(systemName: "chevron.down") : UIImage(systemName: "chevron.right")
}

} else {
DispatchQueue.main.async { [weak self] in
self?.accessoryImageView.image = selected ? UIImage(systemName: "checkmark") : nil
}
}
}

func initCell(filter: Filter, section: Int) {
self.titleLabel.text = filter.description
self.section = section
self.hasChild = filter.hasChild
self.isChild = filter.isChild
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,10 @@
</designables>
<resources>
<namedColor name="openIssue Background Color">
<color red="0.42745098039215684" green="0.87058823529411766" blue="0.49803921568627452" alpha="0.30276188380000002" colorSpace="custom" customColorSpace="displayP3"/>
<color red="0.42699998617172241" green="0.87099999189376831" blue="0.49799999594688416" alpha="0.30300000309944153" colorSpace="custom" customColorSpace="displayP3"/>
</namedColor>
<namedColor name="openIssueColor">
<color red="0.32547658680000002" green="0.64634907249999995" blue="0.31758281589999998" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
<color red="0.32499998807907104" green="0.64600002765655518" blue="0.31799998879432678" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</namedColor>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@
import UIKit

class IssueFilterViewController: UIViewController {

@IBOutlet weak var filterTableView: UITableView!

typealias FilterDataSource = UITableViewDiffableDataSource<Section, Filter>
private var mainFilterContents = MainFilters().contents
private var detailFilterContents = DetailFilters().contents
private lazy var dataSource = createDataSource()
private var labelFilters = [Filter]()
private var milestonFilters = [Filter]()
private var writerFilters = [Filter]()
private var assigneeFilters = [Filter]()

enum Section: Int, CustomStringConvertible {
case main
Expand All @@ -31,6 +35,15 @@ class IssueFilterViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
filterTableView.delegate = self

}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
reloadWriterFilters()
reloadLabelFilters()
reloadMilestoneFilters()
reloadAssigneeFilters()
applySnapshot()
}

Expand All @@ -45,23 +58,72 @@ class IssueFilterViewController: UIViewController {
}

func applySnapshot() {

var snapshot = NSDiffableDataSourceSnapshot<Section, Filter>()
snapshot.appendSections([.main, .detail])
snapshot.appendItems(mainFilterContents, toSection: .main)
snapshot.appendItems(detailFilterContents, toSection: .detail)
self.dataSource.apply(snapshot)
}

func reloadWriterFilters() {
NetworkManager.shared.getRequest(url: .user, type: UserArray.self) { result in
guard let userArray = result else { return }
self.writerFilters = userArray.userArray.map {
Filter(criteria: WriterCriteria(writer: $0.userName), description: $0.userName, isChild: true)
}
}
}

func reloadLabelFilters() {
NetworkManager.shared.getRequest(url: .label, type: LabelArray.self) { result in
guard let labelArray = result else { return }
self.labelFilters = labelArray.labelArray.map {
Filter(criteria: LabelCriteria(labelId: $0.labelId), description: $0.labelName, isChild: true)
}
}
}

func reloadMilestoneFilters() {
NetworkManager.shared.getRequest(url: .milestone, type: MilestoneArray.self) { result in
guard let milestoneArray = result else { return }
self.milestonFilters = milestoneArray.milestoneArray.map {
Filter(criteria: MilestoneCriteria(milestoneId: $0.milestoneId), description: $0.title, isChild: true)
}
}
}
func reloadAssigneeFilters() {
NetworkManager.shared.getRequest(url: .user, type: UserArray.self) { result in
guard let userArray = result else { return }
self.assigneeFilters = userArray.userArray.map {
Filter(criteria: AssignedCriteria(assignee: $0), description: $0.userName, isChild: true)
}
}
}

@IBAction func cancelButtonDidTouch(_ sender: Any) {
dismiss(animated: true, completion: nil)
}

@IBAction func doneButtonDidTouch(_ sender: Any) {
// 처리
var mainFilters = [Filterable]()
var detailFilters = [Filterable]()

guard let indexPaths = filterTableView.indexPathsForSelectedRows else {
NotificationCenter.default.post(name: .issueFilterDidChange, object: nil, userInfo: ["filters": []])
dismiss(animated: true, completion: nil)
return
}
indexPaths.forEach { indexPath in
guard let filter = dataSource.itemIdentifier(for: indexPath)?.criteria else { return }
if indexPath.section == 0 {
mainFilters.append(filter)
} else {
detailFilters.append(filter)
}
}
NotificationCenter.default.post(name: .issueFilterDidChange, object: nil, userInfo: ["mainFilters": mainFilters, "detailFilters": detailFilters])
dismiss(animated: true, completion: nil)
}

}

extension IssueFilterViewController: UITableViewDelegate {
Expand All @@ -83,16 +145,35 @@ extension IssueFilterViewController: UITableViewDelegate {
])
return headerView
}

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let selectedItem = dataSource.itemIdentifier(for: indexPath),
let cell = tableView.cellForRow(at: indexPath) as? FilterTableViewCell else { return }
if selectedItem.childItem.count > 0 {
detailFilterContents.insert(contentsOf: selectedItem.childItem, at: indexPath.row + 1)
if !selectedItem.isChild && indexPath.section == 1 {
switch selectedItem.criteria {
case is WriterCriteria:
reloadWriterFilters()
selectedItem.setChildren(childItems: writerFilters)
case is LabelCriteria:
reloadLabelFilters()
selectedItem.setChildren(childItems: labelFilters)
case is MilestoneCriteria:
reloadMilestoneFilters()
selectedItem.setChildren(childItems: milestonFilters)
case is AssignedCriteria:
reloadAssigneeFilters()
selectedItem.setChildren(childItems: assigneeFilters)
default:
break
}
}

if selectedItem.childItems.count > 0 {
detailFilterContents.insert(contentsOf: selectedItem.childItems, at: indexPath.row + 1)
applySnapshot()
}
cell.initCell(filter: selectedItem, section: indexPath.section)
Expand All @@ -101,8 +182,8 @@ extension IssueFilterViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
guard let selectedItem = dataSource.itemIdentifier(for: indexPath),
let cell = tableView.cellForRow(at: indexPath) as? FilterTableViewCell else { return }
if selectedItem.childItem.count > 0 {
let range = indexPath.row + 1...indexPath.row + selectedItem.childItem.count
if selectedItem.childItems.count > 0 {
let range = indexPath.row + 1...indexPath.row + selectedItem.childItems.count
detailFilterContents.removeSubrange(range)
applySnapshot()
}
Expand Down
49 changes: 19 additions & 30 deletions iOS/IssueTracker/IssueTracker/Model/Filter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,29 @@ import Foundation

class Filter: Hashable {
static func == (lhs: Filter, rhs: Filter) -> Bool {
return lhs.description == rhs.description
return lhs.uuid == rhs.uuid && lhs.description == rhs.description
}

func hash(into hasher: inout Hasher) {
return hasher.combine(description)
hasher.combine(uuid)
hasher.combine(description)
}

let criteria: filterable
let uuid = UUID()
let criteria: Filterable
let description: String
let hasChild: Bool
let childItem: [Filter]
let isChild: Bool
var childItems: [Filter]

init(criteria: filterable, description: String, hasChild: Bool = false, childItem: [Filter] = []) {
init(criteria: Filterable, description: String, isChild: Bool = false, childItem: [Filter] = []) {
self.criteria = criteria
self.description = description
self.hasChild = hasChild
self.childItem = childItem
self.isChild = isChild
self.childItems = childItem
}

func setChildren(childItems: [Filter]) {
self.childItems = childItems
}

}
Expand All @@ -34,8 +40,7 @@ struct MainFilters {
let contents: [Filter] = [
Filter(criteria: OpenCriteria(), description: "열린 이슈들"),
Filter(criteria: CloseCriteria(), description: "닫힌 이슈들"),

Filter(criteria: WriterCriteria(writer: User(userName: "me", social: "test")), description: "내가 작성한 이슈들"),
Filter(criteria: WriterCriteria(writer: "githubtest"), description: "내가 작성한 이슈들"),
Filter(criteria: AssignedCriteria(assignee: User(userName: "me", social: "test")), description: "나한테 할당된 이슈들"),
Filter(criteria: CommentCriteria(), description: "내가 댓글을 남긴 이슈들")
]
Expand All @@ -44,25 +49,9 @@ struct MainFilters {
struct DetailFilters {
// 필터들 구현 필요
let contents: [Filter] = [
Filter(criteria: WriterCriteria(
writer: User(userName: "me", social: "test")),
description: "작성자",
hasChild: true,
childItem: [Filter(criteria: CommentCriteria(), description: "테스트1"),Filter(criteria: CommentCriteria(), description: "테스트2."), Filter(criteria: CommentCriteria(), description: "테스트3")]),
Filter(criteria: WriterCriteria(
writer: User(userName: "me1", social: "test")),
description: "레이블",
hasChild: true,
childItem: [Filter(criteria: CommentCriteria(), description: "테스트1"), Filter(criteria: CommentCriteria(), description: "테스트2."), Filter(criteria: CommentCriteria(), description: "테스트3")]),
Filter(criteria: WriterCriteria(
writer: User(userName: "me2", social: "test")),
description: "마일스톤",
hasChild: true,
childItem: [Filter(criteria: CommentCriteria(), description: "테스트1"), Filter(criteria: CommentCriteria(), description: "테스트2."), Filter(criteria: CommentCriteria(), description: "테스트3")]),
Filter(criteria: WriterCriteria(
writer: User(userName: "me3", social: "test")),
description: "담당자",
hasChild: true,
childItem: [Filter(criteria: CommentCriteria(), description: "테스트1"), Filter(criteria: CommentCriteria(), description: "테스트2."), Filter(criteria: CommentCriteria(), description: "테스트3")])
Filter(criteria: WriterCriteria(writer: "githubtest"), description: "작성자"),
Filter(criteria: LabelCriteria(labelId: -1), description: "레이블"),
Filter(criteria: MilestoneCriteria(milestoneId: -1), description: "마일스톤"),
Filter(criteria: WriterCriteria(writer: "githubtest"), description: "담당자")
]
}
Loading

0 comments on commit 51c0f65

Please sign in to comment.