forked from shadowfacts/Tusker
Fix crash when fetching recommended instances fails
This commit is contained in:
parent
1d79918a94
commit
85e1e131f6
|
@ -50,6 +50,11 @@ class InstanceSelectorTableViewController: UITableViewController {
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
// disable transparent background when scrolled to top because it gets weird with animating table items in and out
|
||||||
|
let appearance = UINavigationBarAppearance()
|
||||||
|
appearance.configureWithDefaultBackground()
|
||||||
|
navigationItem.scrollEdgeAppearance = appearance
|
||||||
|
|
||||||
tableView.register(UINib(nibName: "InstanceTableViewCell", bundle: .main), forCellReuseIdentifier: instanceCell)
|
tableView.register(UINib(nibName: "InstanceTableViewCell", bundle: .main), forCellReuseIdentifier: instanceCell)
|
||||||
|
|
||||||
tableView.rowHeight = UITableView.automaticDimension
|
tableView.rowHeight = UITableView.automaticDimension
|
||||||
|
@ -120,14 +125,18 @@ class InstanceSelectorTableViewController: UITableViewController {
|
||||||
client.run(request) { (response) in
|
client.run(request) { (response) in
|
||||||
var snapshot = self.dataSource.snapshot()
|
var snapshot = self.dataSource.snapshot()
|
||||||
if snapshot.indexOfSection(.selected) != nil {
|
if snapshot.indexOfSection(.selected) != nil {
|
||||||
snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .selected))
|
snapshot.deleteSections([.selected])
|
||||||
}
|
}
|
||||||
|
|
||||||
if case let .success(instance, _) = response {
|
if case let .success(instance, _) = response {
|
||||||
if !snapshot.sectionIdentifiers.contains(.selected) {
|
if snapshot.indexOfSection(.recommendedInstances) != nil {
|
||||||
|
snapshot.insertSections([.selected], beforeSection: .recommendedInstances)
|
||||||
|
} else {
|
||||||
snapshot.appendSections([.selected])
|
snapshot.appendSections([.selected])
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot.appendItems([.selected(url, instance)], toSection: .selected)
|
snapshot.appendItems([.selected(url, instance)], toSection: .selected)
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.dataSource.apply(snapshot)
|
self.dataSource.apply(snapshot)
|
||||||
}
|
}
|
||||||
|
@ -137,14 +146,47 @@ class InstanceSelectorTableViewController: UITableViewController {
|
||||||
|
|
||||||
private func loadRecommendedInstances() {
|
private func loadRecommendedInstances() {
|
||||||
InstanceSelector.getInstances(category: nil) { (response) in
|
InstanceSelector.getInstances(category: nil) { (response) in
|
||||||
guard case let .success(instances, _) = response else { fatalError() }
|
DispatchQueue.main.async {
|
||||||
|
switch response {
|
||||||
self.recommendedInstances = instances
|
case let .failure(error):
|
||||||
self.filterRecommendedResults()
|
self.showRecommendationsError(error)
|
||||||
|
case let .success(instances, _):
|
||||||
|
self.recommendedInstances = instances
|
||||||
|
self.filterRecommendedResults()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterRecommendedResults() {
|
private func showRecommendationsError(_ error: Client.Error) {
|
||||||
|
let footer = UITableViewHeaderFooterView()
|
||||||
|
footer.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
|
||||||
|
let label = UILabel()
|
||||||
|
label.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
label.textColor = .secondaryLabel
|
||||||
|
label.textAlignment = .center
|
||||||
|
label.font = .boldSystemFont(ofSize: 17)
|
||||||
|
label.numberOfLines = 0
|
||||||
|
label.text = "Could not fetch suggested instances: \(error.localizedDescription)"
|
||||||
|
|
||||||
|
footer.contentView.addSubview(label)
|
||||||
|
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
label.leadingAnchor.constraint(equalToSystemSpacingAfter: footer.contentView.leadingAnchor, multiplier: 1),
|
||||||
|
footer.contentView.trailingAnchor.constraint(equalToSystemSpacingAfter: label.trailingAnchor, multiplier: 1),
|
||||||
|
label.topAnchor.constraint(equalTo: footer.contentView.topAnchor, constant: 8),
|
||||||
|
label.bottomAnchor.constraint(equalTo: footer.contentView.bottomAnchor, constant: 8),
|
||||||
|
])
|
||||||
|
|
||||||
|
let fittingSize = CGSize(width: tableView.bounds.width - (tableView.safeAreaInsets.left + tableView.safeAreaInsets.right), height: 0)
|
||||||
|
let size = footer.systemLayoutSizeFitting(fittingSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
|
||||||
|
footer.frame = CGRect(origin: .zero, size: size)
|
||||||
|
|
||||||
|
tableView.tableFooterView = footer
|
||||||
|
}
|
||||||
|
|
||||||
|
private func filterRecommendedResults() {
|
||||||
let filteredInstances: [InstanceSelector.Instance]
|
let filteredInstances: [InstanceSelector.Instance]
|
||||||
if let currentQuery = currentQuery, !currentQuery.isEmpty {
|
if let currentQuery = currentQuery, !currentQuery.isEmpty {
|
||||||
filteredInstances = recommendedInstances.filter {
|
filteredInstances = recommendedInstances.filter {
|
||||||
|
@ -155,12 +197,20 @@ class InstanceSelectorTableViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
var snapshot = self.dataSource.snapshot()
|
var snapshot = self.dataSource.snapshot()
|
||||||
snapshot.deleteSections([.recommendedInstances])
|
if snapshot.indexOfSection(.recommendedInstances) != nil {
|
||||||
snapshot.appendSections([.recommendedInstances])
|
let toRemove = snapshot.itemIdentifiers(inSection: .recommendedInstances).filter {
|
||||||
snapshot.appendItems(filteredInstances.map { Item.recommended($0) }, toSection: .recommendedInstances)
|
if case .recommended(_) = $0 {
|
||||||
DispatchQueue.main.async {
|
return true
|
||||||
self.dataSource.apply(snapshot)
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
snapshot.deleteItems(toRemove)
|
||||||
|
} else {
|
||||||
|
snapshot.appendSections([.recommendedInstances])
|
||||||
}
|
}
|
||||||
|
snapshot.appendItems(filteredInstances.map { Item.recommended($0) }, toSection: .recommendedInstances)
|
||||||
|
self.dataSource.apply(snapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Table view delegate
|
// MARK: - Table view delegate
|
||||||
|
@ -194,29 +244,30 @@ extension InstanceSelectorTableViewController {
|
||||||
case recommended(InstanceSelector.Instance)
|
case recommended(InstanceSelector.Instance)
|
||||||
|
|
||||||
static func ==(lhs: Item, rhs: Item) -> Bool {
|
static func ==(lhs: Item, rhs: Item) -> Bool {
|
||||||
if case let .selected(url, instance) = lhs,
|
switch (lhs, rhs) {
|
||||||
case let .selected(otherUrl, other) = rhs {
|
case let (.selected(urlA, instanceA), .selected(urlB, instanceB)):
|
||||||
return url == otherUrl && instance.uri == other.uri
|
return urlA == urlB && instanceA.uri == instanceB.uri
|
||||||
} else if case let .recommended(instance) = lhs,
|
case let (.recommended(a), .recommended(b)):
|
||||||
case let .recommended(other) = rhs {
|
return a.domain == b.domain
|
||||||
return instance.domain == other.domain
|
default:
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func hash(into hasher: inout Hasher) {
|
func hash(into hasher: inout Hasher) {
|
||||||
switch self {
|
switch self {
|
||||||
case let .selected(url, instance):
|
case let .selected(url, instance):
|
||||||
hasher.combine(Section.selected)
|
hasher.combine(0)
|
||||||
hasher.combine(url)
|
hasher.combine(url)
|
||||||
hasher.combine(instance.uri)
|
hasher.combine(instance.uri)
|
||||||
case let .recommended(instance):
|
case let .recommended(instance):
|
||||||
hasher.combine(Section.recommendedInstances)
|
hasher.combine(1)
|
||||||
hasher.combine(instance.domain)
|
hasher.combine(instance.domain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class DataSource: UITableViewDiffableDataSource<Section, Item> {
|
class DataSource: UITableViewDiffableDataSource<Section, Item> {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue