mirror of
https://github.com/zhigang1992/GitHawk.git
synced 2026-05-30 12:15:26 +08:00
label add/remove working
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
83
Classes/Issues/Labeled/IssueLabeledCell.swift
Normal file
83
Classes/Issues/Labeled/IssueLabeledCell.swift
Normal 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
|
||||
}
|
||||
|
||||
}
|
||||
48
Classes/Issues/Labeled/IssueLabeledModel.swift
Normal file
48
Classes/Issues/Labeled/IssueLabeledModel.swift
Normal 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
|
||||
}
|
||||
|
||||
}
|
||||
27
Classes/Issues/Labeled/IssueLabeledSectionController.swift
Normal file
27
Classes/Issues/Labeled/IssueLabeledSectionController.swift
Normal 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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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: "")
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 */,
|
||||
|
||||
Reference in New Issue
Block a user