2021-03-05 15:50:20 +01:00
|
|
|
//
|
|
|
|
// PickServerSection.swift
|
|
|
|
// Mastodon
|
|
|
|
//
|
|
|
|
// Created by Cirno MainasuK on 2021/3/5.
|
|
|
|
//
|
|
|
|
|
|
|
|
import UIKit
|
|
|
|
import MastodonSDK
|
|
|
|
import Kanna
|
2021-03-06 05:55:52 +01:00
|
|
|
import AlamofireImage
|
2021-03-05 15:50:20 +01:00
|
|
|
|
|
|
|
enum PickServerSection: Equatable, Hashable {
|
|
|
|
case header
|
|
|
|
case category
|
|
|
|
case search
|
|
|
|
case servers
|
|
|
|
}
|
|
|
|
|
|
|
|
extension PickServerSection {
|
|
|
|
static func tableViewDiffableDataSource(
|
|
|
|
for tableView: UITableView,
|
|
|
|
dependency: NeedsDependency,
|
2021-03-06 07:46:04 +01:00
|
|
|
pickServerCategoriesCellDelegate: PickServerCategoriesCellDelegate,
|
2021-03-05 15:50:20 +01:00
|
|
|
pickServerSearchCellDelegate: PickServerSearchCellDelegate,
|
|
|
|
pickServerCellDelegate: PickServerCellDelegate
|
|
|
|
) -> UITableViewDiffableDataSource<PickServerSection, PickServerItem> {
|
2021-04-09 05:05:10 +02:00
|
|
|
UITableViewDiffableDataSource(tableView: tableView) { [
|
|
|
|
weak dependency,
|
|
|
|
weak pickServerCategoriesCellDelegate,
|
|
|
|
weak pickServerSearchCellDelegate,
|
|
|
|
weak pickServerCellDelegate
|
|
|
|
] tableView, indexPath, item -> UITableViewCell? in
|
|
|
|
guard let dependency = dependency else { return nil }
|
2021-03-05 15:50:20 +01:00
|
|
|
switch item {
|
|
|
|
case .header:
|
|
|
|
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PickServerTitleCell.self), for: indexPath) as! PickServerTitleCell
|
|
|
|
return cell
|
|
|
|
case .categoryPicker(let items):
|
|
|
|
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PickServerCategoriesCell.self), for: indexPath) as! PickServerCategoriesCell
|
2021-03-06 07:46:04 +01:00
|
|
|
cell.delegate = pickServerCategoriesCellDelegate
|
2021-03-05 15:50:20 +01:00
|
|
|
cell.diffableDataSource = CategoryPickerSection.collectionViewDiffableDataSource(
|
|
|
|
for: cell.collectionView,
|
|
|
|
dependency: dependency
|
|
|
|
)
|
|
|
|
var snapshot = NSDiffableDataSourceSnapshot<CategoryPickerSection, CategoryPickerItem>()
|
|
|
|
snapshot.appendSections([.main])
|
|
|
|
snapshot.appendItems(items, toSection: .main)
|
|
|
|
cell.diffableDataSource?.apply(snapshot, animatingDifferences: false, completion: nil)
|
|
|
|
return cell
|
|
|
|
case .search:
|
|
|
|
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PickServerSearchCell.self), for: indexPath) as! PickServerSearchCell
|
|
|
|
cell.delegate = pickServerSearchCellDelegate
|
|
|
|
return cell
|
|
|
|
case .server(let server, let attribute):
|
|
|
|
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PickServerCell.self), for: indexPath) as! PickServerCell
|
|
|
|
PickServerSection.configure(cell: cell, server: server, attribute: attribute)
|
|
|
|
cell.delegate = pickServerCellDelegate
|
|
|
|
return cell
|
2021-05-13 11:50:37 +02:00
|
|
|
case .loader(let attribute):
|
|
|
|
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PickServerLoaderTableViewCell.self), for: indexPath) as! PickServerLoaderTableViewCell
|
|
|
|
PickServerSection.configure(cell: cell, attribute: attribute)
|
|
|
|
return cell
|
2021-03-05 15:50:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extension PickServerSection {
|
|
|
|
|
|
|
|
static func configure(cell: PickServerCell, server: Mastodon.Entity.Server, attribute: PickServerItem.ServerItemAttribute) {
|
|
|
|
cell.domainLabel.text = server.domain
|
|
|
|
cell.descriptionLabel.text = {
|
|
|
|
guard let html = try? HTML(html: server.description, encoding: .utf8) else {
|
|
|
|
return server.description
|
|
|
|
}
|
|
|
|
|
|
|
|
return html.text ?? server.description
|
|
|
|
}()
|
|
|
|
cell.langValueLabel.text = server.language.uppercased()
|
|
|
|
cell.usersValueLabel.text = parseUsersCount(server.totalUsers)
|
|
|
|
cell.categoryValueLabel.text = server.category.uppercased()
|
|
|
|
|
|
|
|
cell.updateExpandMode(mode: attribute.isExpand ? .expand : .collapse)
|
2021-03-06 05:55:52 +01:00
|
|
|
|
2021-05-19 11:40:09 +02:00
|
|
|
attribute.isLast
|
|
|
|
.receive(on: DispatchQueue.main)
|
|
|
|
.sink { [weak cell] isLast in
|
|
|
|
guard let cell = cell else { return }
|
|
|
|
if isLast {
|
|
|
|
cell.containerView.layer.maskedCorners = [
|
|
|
|
.layerMinXMaxYCorner,
|
|
|
|
.layerMaxXMaxYCorner
|
|
|
|
]
|
|
|
|
cell.containerView.layer.cornerCurve = .continuous
|
|
|
|
cell.containerView.layer.cornerRadius = MastodonPickServerAppearance.tableViewCornerRadius
|
|
|
|
cell.containerView.layer.masksToBounds = true
|
|
|
|
} else {
|
|
|
|
cell.containerView.layer.cornerRadius = 0
|
|
|
|
cell.containerView.layer.masksToBounds = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.store(in: &cell.disposeBag)
|
2021-03-06 06:29:45 +01:00
|
|
|
|
2021-03-06 05:55:52 +01:00
|
|
|
cell.expandMode
|
|
|
|
.receive(on: DispatchQueue.main)
|
|
|
|
.sink { mode in
|
|
|
|
switch mode {
|
|
|
|
case .collapse:
|
|
|
|
// do nothing
|
|
|
|
break
|
|
|
|
case .expand:
|
|
|
|
let placeholderImage = UIImage.placeholder(size: cell.thumbnailImageView.frame.size, color: .systemFill)
|
|
|
|
.af.imageRounded(withCornerRadius: 3.0, divideRadiusByImageScale: false)
|
|
|
|
guard let proxiedThumbnail = server.proxiedThumbnail,
|
|
|
|
let url = URL(string: proxiedThumbnail) else {
|
|
|
|
cell.thumbnailImageView.image = placeholderImage
|
2021-06-16 08:24:19 +02:00
|
|
|
cell.thumbnailActivityIndicator.stopAnimating()
|
2021-03-06 05:55:52 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
cell.thumbnailImageView.isHidden = false
|
2021-06-16 08:24:19 +02:00
|
|
|
cell.thumbnailActivityIndicator.startAnimating()
|
2021-03-06 05:55:52 +01:00
|
|
|
|
|
|
|
cell.thumbnailImageView.af.setImage(
|
|
|
|
withURL: url,
|
|
|
|
placeholderImage: placeholderImage,
|
|
|
|
filter: AspectScaledToFillSizeWithRoundedCornersFilter(size: cell.thumbnailImageView.frame.size, radius: 3),
|
|
|
|
imageTransition: .crossDissolve(0.33),
|
|
|
|
completion: { [weak cell] response in
|
|
|
|
switch response.result {
|
|
|
|
case .success, .failure:
|
2021-06-16 08:24:19 +02:00
|
|
|
cell?.thumbnailActivityIndicator.stopAnimating()
|
2021-03-06 05:55:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.store(in: &cell.disposeBag)
|
2021-03-05 15:50:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private static func parseUsersCount(_ usersCount: Int) -> String {
|
|
|
|
switch usersCount {
|
|
|
|
case 0..<1000:
|
|
|
|
return "\(usersCount)"
|
|
|
|
default:
|
|
|
|
let usersCountInThousand = Float(usersCount) / 1000.0
|
|
|
|
return String(format: "%.1fK", usersCountInThousand)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2021-05-13 11:50:37 +02:00
|
|
|
|
|
|
|
extension PickServerSection {
|
|
|
|
|
|
|
|
static func configure(cell: PickServerLoaderTableViewCell, attribute: PickServerItem.LoaderItemAttribute) {
|
|
|
|
if attribute.isLast {
|
|
|
|
cell.containerView.layer.maskedCorners = [
|
|
|
|
.layerMinXMaxYCorner,
|
|
|
|
.layerMaxXMaxYCorner
|
|
|
|
]
|
|
|
|
cell.containerView.layer.cornerCurve = .continuous
|
|
|
|
cell.containerView.layer.cornerRadius = MastodonPickServerAppearance.tableViewCornerRadius
|
2021-05-19 11:40:09 +02:00
|
|
|
cell.containerView.layer.masksToBounds = true
|
2021-05-13 11:50:37 +02:00
|
|
|
} else {
|
|
|
|
cell.containerView.layer.cornerRadius = 0
|
2021-05-19 11:40:09 +02:00
|
|
|
cell.containerView.layer.masksToBounds = false
|
2021-05-13 11:50:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
attribute.isNoResult ? cell.stopAnimating() : cell.startAnimating()
|
|
|
|
cell.emptyStatusLabel.isHidden = !attribute.isNoResult
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|