label add/remove working

This commit is contained in:
Ryan Nystrom
2017-06-06 17:43:53 -04:00
parent e829963e0b
commit 6857ba1ce0
9 changed files with 218 additions and 0 deletions

View File

@@ -45,6 +45,24 @@ extension IssueQuery.Data.Repository.Issue: IssueType {
) {
results.append(model)
}
} else if let unlabeled = node.asUnlabeledEvent {
let model = IssueLabeledModel(
id: unlabeled.id,
actor: unlabeled.actor?.login ?? Strings.unknown,
title: unlabeled.label.name,
color: unlabeled.label.color,
type: .removed
)
results.append(model)
} else if let labeled = node.asLabeledEvent {
let model = IssueLabeledModel(
id: labeled.id,
actor: labeled.actor?.login ?? Strings.unknown,
title: labeled.label.name,
color: labeled.label.color,
type: .added
)
results.append(model)
}
}

View File

@@ -62,6 +62,8 @@ final class IssuesViewController: UIViewController, IGListAdapterDataSource, Fee
return IssueLabelsSectionController()
} else if object is IssueStatusModel {
return IssueStatusSectionController()
} else if object is IssueLabeledModel {
return IssueLabeledSectionController()
}
return IGListSectionController()
}

View File

@@ -0,0 +1,83 @@
//
// IssueLabeledCell.swift
// Freetime
//
// Created by Ryan Nystrom on 6/6/17.
// Copyright © 2017 Ryan Nystrom. All rights reserved.
//
import UIKit
import SnapKit
final class IssueLabeledCell: UICollectionViewCell {
let descriptionLabel = UILabel()
let labelBackgroundView = UIView()
let titleLabel = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
descriptionLabel.backgroundColor = .clear
contentView.addSubview(descriptionLabel)
descriptionLabel.snp.makeConstraints { make in
make.left.equalTo(Styles.Sizes.gutter)
make.centerY.equalTo(contentView)
}
titleLabel.font = Styles.Fonts.smallTitle
contentView.addSubview(titleLabel)
titleLabel.snp.makeConstraints { make in
make.left.equalTo(descriptionLabel.snp.right).offset(Styles.Sizes.columnSpacing)
make.centerY.equalTo(descriptionLabel)
}
// even though the background view is behind the title, add it second so that constraints can be setup
labelBackgroundView.layer.cornerRadius = Styles.Sizes.avatarCornerRadius
labelBackgroundView.clipsToBounds = true
contentView.addSubview(labelBackgroundView)
labelBackgroundView.snp.makeConstraints { make in
make.center.equalTo(titleLabel)
make.width.equalTo(titleLabel).offset(Styles.Sizes.columnSpacing)
make.height.equalTo(titleLabel).offset(Styles.Sizes.rowSpacing)
}
// then swap the z indexes of the label and background
contentView.bringSubview(toFront: titleLabel)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: Public API
func configure(_ model: IssueLabeledModel) {
let actorAttributes = [
NSForegroundColorAttributeName: Styles.Colors.Gray.dark,
NSFontAttributeName: Styles.Fonts.bodyBold
]
let actor = NSAttributedString(string: model.actor, attributes: actorAttributes)
let actionString: String
switch model.type {
case .added: actionString = NSLocalizedString(" added label", comment: "")
case .removed: actionString = NSLocalizedString(" removed label", comment: "")
}
let actionAttributes = [
NSForegroundColorAttributeName: Styles.Colors.Gray.medium,
NSFontAttributeName: Styles.Fonts.body
]
let action = NSAttributedString(string: actionString, attributes: actionAttributes)
let descriptionText = NSMutableAttributedString(attributedString: actor)
descriptionText.append(action)
descriptionLabel.attributedText = descriptionText
let color = UIColor.fromHex(model.color)
labelBackgroundView.backgroundColor = color
titleLabel.text = model.title
titleLabel.textColor = color.textOverlayColor
}
}

View File

@@ -0,0 +1,48 @@
//
// IssueLabeledModel.swift
// Freetime
//
// Created by Ryan Nystrom on 6/6/17.
// Copyright © 2017 Ryan Nystrom. All rights reserved.
//
import Foundation
import IGListKit
final class IssueLabeledModel: IGListDiffable {
enum EventType {
case added
case removed
}
let id: String
let actor: String
let title: String
let color: String
let type: EventType
init(id: String, actor: String, title: String, color: String, type: EventType) {
self.id = id
self.actor = actor
self.title = title
self.color = color
self.type = type
}
// MARK: IGListDiffable
func diffIdentifier() -> NSObjectProtocol {
return id as NSObjectProtocol
}
func isEqual(toDiffableObject object: IGListDiffable?) -> Bool {
if self === object { return true }
guard let object = object as? IssueLabeledModel else { return false }
return actor == object.actor
&& title == object.title
&& color == object.color
// skipping type in favor of the event id distinguishing between the two
}
}

View File

@@ -0,0 +1,27 @@
//
// IssueLabeledSectionController.swift
// Freetime
//
// Created by Ryan Nystrom on 6/6/17.
// Copyright © 2017 Ryan Nystrom. All rights reserved.
//
import Foundation
import IGListKit
final class IssueLabeledSectionController: IGListGenericSectionController<IssueLabeledModel> {
override func sizeForItem(at index: Int) -> CGSize {
guard let width = collectionContext?.containerSize.width else { return .zero }
return CGSize(width: width, height: 30)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
guard let cell = collectionContext?.dequeueReusableCell(of: IssueLabeledCell.self, for: self, at: index) as? IssueLabeledCell,
let object = self.object
else { return UICollectionViewCell() }
cell.configure(object)
return cell
}
}

View File

@@ -45,6 +45,24 @@ extension PullRequestQuery.Data.Repository.PullRequest: IssueType {
) {
results.append(model)
}
} else if let unlabeled = node.asUnlabeledEvent {
let model = IssueLabeledModel(
id: unlabeled.id,
actor: unlabeled.actor?.login ?? Strings.unknown,
title: unlabeled.label.name,
color: unlabeled.label.color,
type: .removed
)
results.append(model)
} else if let labeled = node.asLabeledEvent {
let model = IssueLabeledModel(
id: labeled.id,
actor: labeled.actor?.login ?? Strings.unknown,
title: labeled.label.name,
color: labeled.label.color,
type: .added
)
results.append(model)
}
}

View File

@@ -17,5 +17,6 @@ struct Strings {
static let signout = NSLocalizedString("Sign out", comment: "")
static let open = NSLocalizedString("Open", comment: "")
static let closed = NSLocalizedString("Closed", comment: "")
static let unknown = NSLocalizedString("Unknown", comment: "")
}

View File

@@ -25,6 +25,7 @@ struct Styles {
struct Fonts {
static let body = UIFont.systemFont(ofSize: 16)
static let bodyBold = UIFont.boldSystemFont(ofSize: 16)
static let secondary = UIFont.systemFont(ofSize: 13)
static let title = UIFont.boldSystemFont(ofSize: 14)
static let button = UIFont.systemFont(ofSize: 17)

View File

@@ -141,6 +141,9 @@
29C9FDDB1EC6627200EE3A52 /* NotificationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29C9FDDA1EC6627200EE3A52 /* NotificationCell.swift */; };
29C9FDDD1EC6628200EE3A52 /* NotificationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29C9FDDC1EC6628200EE3A52 /* NotificationViewModel.swift */; };
29C9FDE11EC667AE00EE3A52 /* Styles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29C9FDE01EC667AE00EE3A52 /* Styles.swift */; };
29FB942C1EE750DB0016E6D4 /* IssueLabeledModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29FB942B1EE750DB0016E6D4 /* IssueLabeledModel.swift */; };
29FB942E1EE751F70016E6D4 /* IssueLabeledSectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29FB942D1EE751F70016E6D4 /* IssueLabeledSectionController.swift */; };
29FB94301EE752280016E6D4 /* IssueLabeledCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29FB942F1EE752280016E6D4 /* IssueLabeledCell.swift */; };
29FF85A31EE1CFF7007B8762 /* IssueLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29FF85A21EE1CFF7007B8762 /* IssueLabelModel.swift */; };
29FF85A51EE1EA7A007B8762 /* ReactionContent+ReactionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29FF85A41EE1EA7A007B8762 /* ReactionContent+ReactionType.swift */; };
7C3E80AE871BAB9F2CE23FBA /* Pods_Freetime.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 56223772300F4C201A21701F /* Pods_Freetime.framework */; };
@@ -293,6 +296,9 @@
29C9FDE01EC667AE00EE3A52 /* Styles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Styles.swift; sourceTree = "<group>"; };
29F63FD01EC530BD007F55E4 /* Github API.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "Github API.playground"; sourceTree = "<group>"; };
29F63FD11EC530E7007F55E4 /* TextViews.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = TextViews.playground; sourceTree = "<group>"; };
29FB942B1EE750DB0016E6D4 /* IssueLabeledModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IssueLabeledModel.swift; sourceTree = "<group>"; };
29FB942D1EE751F70016E6D4 /* IssueLabeledSectionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IssueLabeledSectionController.swift; sourceTree = "<group>"; };
29FB942F1EE752280016E6D4 /* IssueLabeledCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IssueLabeledCell.swift; sourceTree = "<group>"; };
29FF85A21EE1CFF7007B8762 /* IssueLabelModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IssueLabelModel.swift; sourceTree = "<group>"; };
29FF85A41EE1EA7A007B8762 /* ReactionContent+ReactionType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ReactionContent+ReactionType.swift"; sourceTree = "<group>"; };
56223772300F4C201A21701F /* Pods_Freetime.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Freetime.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -332,6 +338,7 @@
292FCAE91EDFCC510026635E /* IssuesViewController.swift */,
294563EF1EE5036A00DBCD35 /* IssueType.swift */,
292FCAEA1EDFCC510026635E /* IssueViewModels.swift */,
29FB942A1EE750720016E6D4 /* Labeled */,
292FCAEC1EDFCC510026635E /* Labels */,
294563ED1EE5012900DBCD35 /* PullRequest+IssueType.swift */,
294563E41EE4EE5B00DBCD35 /* Status */,
@@ -676,6 +683,16 @@
path = Notifications;
sourceTree = "<group>";
};
29FB942A1EE750720016E6D4 /* Labeled */ = {
isa = PBXGroup;
children = (
29FB942F1EE752280016E6D4 /* IssueLabeledCell.swift */,
29FB942B1EE750DB0016E6D4 /* IssueLabeledModel.swift */,
29FB942D1EE751F70016E6D4 /* IssueLabeledSectionController.swift */,
);
path = Labeled;
sourceTree = "<group>";
};
4AC385A3A25CE8377A0E2188 /* Pods */ = {
isa = PBXGroup;
children = (
@@ -1007,18 +1024,21 @@
29C9FDD81EC65FEE00EE3A52 /* User.swift in Sources */,
292FCB0A1EDFCC510026635E /* IssueCommentTextCell.swift in Sources */,
29C167671ECA005500439D62 /* Strings.swift in Sources */,
29FB942E1EE751F70016E6D4 /* IssueLabeledSectionController.swift in Sources */,
29316DC31ECC981D007CAE3F /* RootNavigationManager.swift in Sources */,
29C9FDCF1EC65FEE00EE3A52 /* Organization.swift in Sources */,
292FCAFF1EDFCC510026635E /* IssueCommentSectionController.swift in Sources */,
297AE87A1EC0D5C200B44A1F /* Authorization.swift in Sources */,
29C1677A1ECA14F700439D62 /* Feed.swift in Sources */,
292FCB171EDFCC510026635E /* IssueLabelSummaryModel.swift in Sources */,
29FB94301EE752280016E6D4 /* IssueLabeledCell.swift in Sources */,
292FCB051EDFCC510026635E /* MarkdownScanner.swift in Sources */,
29C295171EC7BCDA00D46CD2 /* NotificationsViewController.swift in Sources */,
292FCB101EDFCC510026635E /* IssueViewModels.swift in Sources */,
29316DB11ECC7D89007CAE3F /* SettingsUsersSectionController.swift in Sources */,
294563EE1EE5012900DBCD35 /* PullRequest+IssueType.swift in Sources */,
292FCB0C1EDFCC510026635E /* IssueEvent.swift in Sources */,
29FB942C1EE750DB0016E6D4 /* IssueLabeledModel.swift in Sources */,
29C295111EC7B83200D46CD2 /* ShowMoreDetailsLabel.swift in Sources */,
29C9FDCE1EC65FEE00EE3A52 /* Notification.swift in Sources */,
297AE8791EC0D5C200B44A1F /* App.swift in Sources */,