Skip to content
This repository was archived by the owner on Sep 20, 2023. It is now read-only.

Commit c62ce4a

Browse files
BrianLitwinrnystrom
authored andcommitted
change repo branch (#2202)
* change repo branch additions: - A change-repository-branch workflow thats very similar to the workflow in Milestones - GraphQL query to fetch a repo's branches modifications: - a mutable "branch" string in RepositoryOverviewController and RepositoryCodeDirectoryViewController - updated the V3RepositoryReadME fetch to include a branch parameter - a protocol RepositoryBranchUpdatable to flag and update the appropriate ViewControllers when a user switches branches - ContextMenu and UIAlertAction setup - Removed some outdated code to get a repo's branch name from fetch(page:) in RepositoryOverviewViewController - Added a line feed.adapter.reloadData() in fetch(page:) because app was crashing intermittently after a user switched branches without that line - was always an IGListKit duplicate identifier error on StyledTextRenderers - to reproduce, remove the feed.adapter.reloadData(), go to https://github.com/TheAlgorithms/Python, try to switch branches and the app will crash. I'm working raising an issue for it. * requested changes - changed public var to private(set) for var branch: String - removed wasteful feed.adapter.reloadData() call - re-formated params in switchBranchAction() * style nit
1 parent d94eb86 commit c62ce4a

13 files changed

+584
-15
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//
2+
// GitHubClient+RepoBranches.swift
3+
// Freetime
4+
//
5+
// Created by B_Litwin on 9/25/18.
6+
// Copyright © 2018 Ryan Nystrom. All rights reserved.
7+
//
8+
9+
import GitHubAPI
10+
11+
extension GithubClient {
12+
13+
func fetchRepositoryBranches(owner: String,
14+
repo: String,
15+
completion: @escaping (Result<([String])>)->Void
16+
) {
17+
let query = FetchRepositoryBranchesQuery(owner: owner, name: repo)
18+
client.query(query, result: { $0.repository }) { result in
19+
20+
switch result {
21+
case .failure(let error):
22+
completion(.error(error))
23+
24+
case .success(let repository):
25+
var branches: [String] = []
26+
repository.refs.map { edges in
27+
edges.edges.map { edge in
28+
branches += edge.compactMap {
29+
$0?.node?.name
30+
}
31+
}
32+
}
33+
34+
completion(.success(branches))
35+
}
36+
}
37+
}
38+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//
2+
// RepositoryBranchUpdatable.swift
3+
// Freetime
4+
//
5+
// Created by B_Litwin on 9/28/18.
6+
// Copyright © 2018 Ryan Nystrom. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
protocol RepositoryBranchUpdatable: class {
12+
func updateBranch(to newBranch: String)
13+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//
2+
// RepoBranchesCell.swift
3+
// Freetime
4+
//
5+
// Created by B_Litwin on 9/25/18.
6+
// Copyright © 2018 Ryan Nystrom. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
final class RepositoryBranchCell: SelectableCell {
12+
public let label = UILabel()
13+
private let checkedImageView = UIImageView(image: UIImage(named: "check-small")?.withRenderingMode(.alwaysTemplate))
14+
15+
override init(frame: CGRect) {
16+
super.init(frame: frame)
17+
18+
backgroundColor = nil
19+
contentView.backgroundColor = nil
20+
21+
contentView.addSubview(checkedImageView)
22+
checkedImageView.tintColor = Styles.Colors.Blue.medium.color
23+
checkedImageView.snp.makeConstraints { make in
24+
make.right.equalTo(-Styles.Sizes.gutter)
25+
make.centerY.equalTo(contentView.snp.centerY)
26+
}
27+
28+
contentView.addSubview(label)
29+
label.font = Styles.Text.bodyBold.preferredFont
30+
label.textColor = .white
31+
label.snp.makeConstraints { make in
32+
make.left.equalTo(Styles.Sizes.gutter)
33+
make.right.lessThanOrEqualTo(checkedImageView.snp.left)
34+
make.centerY.equalTo(contentView.snp.centerY)
35+
}
36+
37+
let border = contentView.addBorder(.bottom,
38+
left: Styles.Sizes.gutter,
39+
right: -Styles.Sizes.gutter
40+
)
41+
border.backgroundColor = Styles.Colors.Gray.medium.color
42+
}
43+
44+
func setSelected(_ selected: Bool) {
45+
checkedImageView.isHidden = !selected
46+
}
47+
48+
required init?(coder aDecoder: NSCoder) {
49+
fatalError("init(coder:) has not been implemented")
50+
}
51+
52+
// MARK: Accessibility
53+
54+
override var accessibilityLabel: String? {
55+
get { return AccessibilityHelper.generatedLabel(forCell: self) }
56+
set { }
57+
}
58+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//
2+
// RepoBranchesSectionController.swift
3+
// Freetime
4+
//
5+
// Created by B_Litwin on 9/25/18.
6+
// Copyright © 2018 Ryan Nystrom. All rights reserved.
7+
//
8+
9+
import UIKit
10+
import IGListKit
11+
12+
protocol RepositoryBranchSectionControllerDelegate: class {
13+
func didSelect(value: RepositoryBranchViewModel)
14+
}
15+
16+
final class RepositoryBranchSectionController: ListSwiftSectionController<RepositoryBranchViewModel> {
17+
18+
public weak var delegate: RepositoryBranchSectionControllerDelegate?
19+
20+
override func createBinders(from value: RepositoryBranchViewModel) -> [ListBinder] {
21+
return [
22+
binder(
23+
value,
24+
cellType: ListCellType.class(RepositoryBranchCell.self),
25+
size: {
26+
return CGSize(
27+
width: $0.collection.containerSize.width,
28+
height: Styles.Sizes.tableCellHeightLarge
29+
)
30+
},
31+
configure: {
32+
$0.label.text = $1.value.branch
33+
$0.setSelected($1.value.selected)
34+
},
35+
didSelect: { [weak self] context in
36+
guard let strongSelf = self else { return }
37+
context.deselect(animated: true)
38+
strongSelf.delegate?.didSelect(value: context.value)
39+
})
40+
]
41+
}
42+
}
43+
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//
2+
// RepoBranchesViewController.swift
3+
// Freetime
4+
//
5+
// Created by B_Litwin on 9/25/18.
6+
// Copyright © 2018 Ryan Nystrom. All rights reserved.
7+
//
8+
9+
import UIKit
10+
import Squawk
11+
import IGListKit
12+
13+
final class RepositoryBranchesViewController: BaseListViewController2<String>,
14+
BaseListViewController2DataSource,
15+
RepositoryBranchSectionControllerDelegate
16+
{
17+
18+
private let owner: String
19+
private let repo: String
20+
private let client: GithubClient
21+
private var branches: [String] = []
22+
public var branch: String
23+
24+
init(branch: String,
25+
owner: String,
26+
repo: String,
27+
client: GithubClient
28+
)
29+
{
30+
self.branch = branch
31+
self.owner = owner
32+
self.repo = repo
33+
self.client = client
34+
super.init(emptyErrorMessage: "Couldn't load repository branches")
35+
36+
title = NSLocalizedString("Branches", comment: "")
37+
preferredContentSize = Styles.Sizes.contextMenuSize
38+
feed.collectionView.backgroundColor = Styles.Colors.menuBackgroundColor.color
39+
dataSource = self
40+
}
41+
42+
override func viewDidLoad() {
43+
super.viewDidLoad()
44+
navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white]
45+
addMenuDoneButton()
46+
}
47+
48+
required init?(coder aDecoder: NSCoder) {
49+
fatalError("init(coder:) has not been implemented")
50+
}
51+
52+
override func fetch(page: String?) {
53+
client.fetchRepositoryBranches(owner: owner,
54+
repo: repo
55+
)
56+
{ [weak self] result in
57+
switch result {
58+
case .success(let branches):
59+
self?.branches = branches
60+
case .error:
61+
Squawk.showError(message: "Couldn't fetch repository branches")
62+
}
63+
self?.update(animated: true)
64+
}
65+
}
66+
67+
func models(adapter: ListSwiftAdapter) -> [ListSwiftPair] {
68+
guard feed.status == .idle else { return [] }
69+
return branches.map {
70+
let value = RepositoryBranchViewModel(branch: $0,
71+
selected: $0 == self.branch)
72+
73+
return ListSwiftPair(value) { [weak self] in
74+
let controller = RepositoryBranchSectionController()
75+
controller.delegate = self
76+
return controller
77+
}
78+
}
79+
}
80+
81+
func didSelect(value: RepositoryBranchViewModel) {
82+
self.branch = value.branch
83+
fetch(page: nil)
84+
}
85+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// RepoBranchesViewModel.swift
3+
// Freetime
4+
//
5+
// Created by B_Litwin on 9/25/18.
6+
// Copyright © 2018 Ryan Nystrom. All rights reserved.
7+
//
8+
9+
import IGListKit
10+
11+
struct RepositoryBranchViewModel: ListSwiftDiffable {
12+
let branch: String
13+
let selected: Bool
14+
15+
var identifier: String {
16+
return branch
17+
}
18+
19+
func isEqual(to value: ListSwiftDiffable) -> Bool {
20+
guard let value = value as? RepositoryBranchViewModel else { return false }
21+
return value.branch == branch
22+
&& value.selected == selected
23+
}
24+
}
25+

Classes/Repository/RepositoryCodeDirectoryViewController.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ import IGListKit
1111

1212
final class RepositoryCodeDirectoryViewController: BaseListViewController<NSNumber>,
1313
BaseListViewControllerDataSource,
14-
ListSingleSectionControllerDelegate {
14+
ListSingleSectionControllerDelegate,
15+
RepositoryBranchUpdatable
16+
{
1517

1618
private let client: GithubClient
17-
private let branch: String
19+
private var branch: String
1820
private let path: FilePath
1921
private let repo: RepositoryDetails
2022
private var files = [RepositoryFile]()
@@ -177,5 +179,13 @@ extension RepositoryCodeDirectoryViewController {
177179

178180
navigationController?.pushViewController(controller, animated: trueUnlessReduceMotionEnabled)
179181
}
182+
183+
//Mark: RepositoryBranchUpdatable
184+
185+
func updateBranch(to newBranch: String) {
186+
guard self.branch != newBranch else { return }
187+
self.branch = newBranch
188+
fetch(page: nil)
189+
}
180190

181191
}

Classes/Repository/RepositoryOverviewViewController.swift

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@ class HackScrollIndicatorInsetsCollectionView: UICollectionView {
2020
}
2121

2222
class RepositoryOverviewViewController: BaseListViewController<NSString>,
23-
BaseListViewControllerDataSource {
23+
BaseListViewControllerDataSource,
24+
RepositoryBranchUpdatable
25+
{
2426

2527
private let repo: RepositoryDetails
2628
private let client: RepositoryClient
2729
private var readme: RepositoryReadmeModel?
30+
private var branch: String
2831

2932
// lazy var _feed: Feed = { Feed(
3033
// viewController: self,
@@ -41,6 +44,7 @@ BaseListViewControllerDataSource {
4144
init(client: GithubClient, repo: RepositoryDetails) {
4245
self.repo = repo
4346
self.client = RepositoryClient(githubClient: client, owner: repo.owner, name: repo.name)
47+
self.branch = repo.defaultBranch
4448
super.init(
4549
emptyErrorMessage: NSLocalizedString("Cannot load README.", comment: "")
4650
)
@@ -71,20 +75,13 @@ BaseListViewControllerDataSource {
7175
// let contentInset = feed.collectionView.contentInset
7276
let width = view.bounds.width - Styles.Sizes.gutter * 2
7377
let contentSizeCategory = UIContentSizeCategory.preferred
78+
let branch = self.branch
7479

7580
client.githubClient.client
76-
.send(V3RepositoryReadmeRequest(owner: repo.owner, repo: repo.name)) { [weak self] result in
81+
.send(V3RepositoryReadmeRequest(owner: repo.owner, repo: repo.name, branch: branch)) { [weak self] result in
7782
switch result {
7883
case .success(let response):
7984
DispatchQueue.global().async {
80-
let branch: String
81-
if let items = URLComponents(url: response.data.url, resolvingAgainstBaseURL: false)?.queryItems,
82-
let index = items.index(where: { $0.name == "ref" }),
83-
let value = items[index].value {
84-
branch = value
85-
} else {
86-
branch = "master"
87-
}
8885

8986
let models = MarkdownModels(
9087
response.data.content,
@@ -130,5 +127,13 @@ BaseListViewControllerDataSource {
130127
type: .readme
131128
)
132129
}
130+
131+
//Mark: RepositoryBranchUpdatable
132+
133+
func updateBranch(to newBranch: String) {
134+
guard self.branch != newBranch else { return }
135+
self.branch = newBranch
136+
fetch(page: nil)
137+
}
133138

134139
}

0 commit comments

Comments
 (0)