Cleanup/Style TableView (IOS-157)

This commit is contained in:
Nathan Mattes 2023-05-12 22:06:44 +02:00
parent c0532d7b56
commit 66ce4802ef
7 changed files with 73 additions and 297 deletions

View File

@ -75,7 +75,6 @@
2D38F1F725CD47AC00561493 /* HomeTimelineViewModel+LoadOldestState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D38F1F625CD47AC00561493 /* HomeTimelineViewModel+LoadOldestState.swift */; };
2D38F20825CD491300561493 /* DisposeBagCollectable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D38F20725CD491300561493 /* DisposeBagCollectable.swift */; };
2D3F9E0425DFA133004262D9 /* UITapGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D3F9E0325DFA133004262D9 /* UITapGestureRecognizer.swift */; };
2D4AD89C263165B500613EFC /* SuggestionAccountCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D4AD89B263165B500613EFC /* SuggestionAccountCollectionViewCell.swift */; };
2D571B2F26004EC000540450 /* NavigationBarProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D571B2E26004EC000540450 /* NavigationBarProgressView.swift */; };
2D59819B25E4A581000FB903 /* MastodonConfirmEmailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D59819A25E4A581000FB903 /* MastodonConfirmEmailViewController.swift */; };
2D5981A125E4A593000FB903 /* MastodonConfirmEmailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5981A025E4A593000FB903 /* MastodonConfirmEmailViewModel.swift */; };
@ -692,7 +691,6 @@
2D38F1F625CD47AC00561493 /* HomeTimelineViewModel+LoadOldestState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HomeTimelineViewModel+LoadOldestState.swift"; sourceTree = "<group>"; };
2D38F20725CD491300561493 /* DisposeBagCollectable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisposeBagCollectable.swift; sourceTree = "<group>"; };
2D3F9E0325DFA133004262D9 /* UITapGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITapGestureRecognizer.swift; sourceTree = "<group>"; };
2D4AD89B263165B500613EFC /* SuggestionAccountCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionAccountCollectionViewCell.swift; sourceTree = "<group>"; };
2D571B2E26004EC000540450 /* NavigationBarProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBarProgressView.swift; sourceTree = "<group>"; };
2D59819A25E4A581000FB903 /* MastodonConfirmEmailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonConfirmEmailViewController.swift; sourceTree = "<group>"; };
2D5981A025E4A593000FB903 /* MastodonConfirmEmailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonConfirmEmailViewModel.swift; sourceTree = "<group>"; };
@ -1572,14 +1570,6 @@
path = Button;
sourceTree = "<group>";
};
2D4AD89A2631659400613EFC /* CollectionViewCell */ = {
isa = PBXGroup;
children = (
2D4AD89B263165B500613EFC /* SuggestionAccountCollectionViewCell.swift */,
);
path = CollectionViewCell;
sourceTree = "<group>";
};
2D59819925E4A55C000FB903 /* ConfirmEmail */ = {
isa = PBXGroup;
children = (
@ -1681,7 +1671,6 @@
2DAC9E37262FC2320062E1A6 /* SuggestionAccountViewController.swift */,
2DAC9E3D262FC2400062E1A6 /* SuggestionAccountViewModel.swift */,
DBB45B6127B51112002DC5A7 /* SuggestionAccountViewModel+Diffable.swift */,
2D4AD89A2631659400613EFC /* CollectionViewCell */,
2DAC9E43262FC9DE0062E1A6 /* TableViewCell */,
);
path = SuggestionAccount;
@ -3841,7 +3830,6 @@
DB938F0326240EA300E5B6C1 /* CachedThreadViewModel.swift in Sources */,
DBA5A53526F0A36A00CACBAA /* AddAccountTableViewCell.swift in Sources */,
2D35237A26256D920031AF25 /* NotificationSection.swift in Sources */,
2D4AD89C263165B500613EFC /* SuggestionAccountCollectionViewCell.swift in Sources */,
DB98EB6927B21A7C0082E365 /* ReportResultActionTableViewCell.swift in Sources */,
DB9282B225F3222800823B15 /* PickServerEmptyStateView.swift in Sources */,
DB697DDF278F524F004EF2F7 /* DataSourceFacade+Profile.swift in Sources */,

View File

@ -19,117 +19,6 @@ enum RecommendAccountSection: Equatable, Hashable {
case main
}
//extension RecommendAccountSection {
// static func collectionViewDiffableDataSource(
// for collectionView: UICollectionView,
// dependency: NeedsDependency,
// delegate: SearchRecommendAccountsCollectionViewCellDelegate,
// managedObjectContext: NSManagedObjectContext
// ) -> UICollectionViewDiffableDataSource<RecommendAccountSection, NSManagedObjectID> {
// UICollectionViewDiffableDataSource(collectionView: collectionView) { [weak delegate] collectionView, indexPath, objectID -> UICollectionViewCell? in
// let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: SearchRecommendAccountsCollectionViewCell.self), for: indexPath) as! SearchRecommendAccountsCollectionViewCell
// managedObjectContext.performAndWait {
// let user = managedObjectContext.object(with: objectID) as! MastodonUser
// configure(cell: cell, user: user, dependency: dependency)
// }
// cell.delegate = delegate
// return cell
// }
// }
//
// static func configure(
// cell: SearchRecommendAccountsCollectionViewCell,
// user: MastodonUser,
// dependency: NeedsDependency
// ) {
// configureContent(cell: cell, user: user)
//
// if let currentMastodonUser = dependency.context.authenticationService.activeMastodonAuthentication.value?.user {
// configureFollowButton(with: user, currentMastodonUser: currentMastodonUser, followButton: cell.followButton)
// }
//
// Publishers.CombineLatest(
// ManagedObjectObserver.observe(object: user).eraseToAnyPublisher().mapError { $0 as Error },
// dependency.context.authenticationService.activeMastodonAuthentication.setFailureType(to: Error.self)
// )
// .receive(on: DispatchQueue.main)
// .sink { _ in
// // do nothing
// } receiveValue: { [weak cell] change, authentication in
// guard let cell = cell else { return }
// guard case .update(let object) = change.changeType,
// let user = object as? MastodonUser else { return }
// guard let currentMastodonUser = authentication?.user else { return }
//
// configureFollowButton(with: user, currentMastodonUser: currentMastodonUser, followButton: cell.followButton)
// }
// .store(in: &cell.disposeBag)
//
// }
//
// static func configureContent(
// cell: SearchRecommendAccountsCollectionViewCell,
// user: MastodonUser
// ) {
// do {
// let mastodonContent = MastodonContent(content: user.displayNameWithFallback, emojis: user.emojis.asDictionary)
// let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
// cell.displayNameLabel.configure(content: metaContent)
// } catch {
// let metaContent = PlaintextMetaContent(string: user.displayNameWithFallback)
// cell.displayNameLabel.configure(content: metaContent)
// }
// cell.acctLabel.text = "@" + user.acct
// cell.avatarImageView.af.setImage(
// withURL: user.avatarImageURLWithFallback(domain: user.domain),
// placeholderImage: UIImage.placeholder(color: .systemFill),
// imageTransition: .crossDissolve(0.2)
// )
// cell.headerImageView.af.setImage(
// withURL: URL(string: user.header)!,
// placeholderImage: UIImage.placeholder(color: .systemFill),
// imageTransition: .crossDissolve(0.2)
// )
// }
//
// static func configureFollowButton(
// with mastodonUser: MastodonUser,
// currentMastodonUser: MastodonUser,
// followButton: HighlightDimmableButton
// ) {
// let relationshipActionSet = relationShipActionSet(mastodonUser: mastodonUser, currentMastodonUser: currentMastodonUser)
// followButton.setTitle(relationshipActionSet.title, for: .normal)
// }
//
// static func relationShipActionSet(
// mastodonUser: MastodonUser,
// currentMastodonUser: MastodonUser
// ) -> ProfileViewModel.RelationshipActionOptionSet {
// var relationshipActionSet = ProfileViewModel.RelationshipActionOptionSet([.follow])
// let isFollowing = mastodonUser.followingBy.flatMap { $0.contains(currentMastodonUser) } ?? false
// if isFollowing {
// relationshipActionSet.insert(.following)
// }
//
// let isPending = mastodonUser.followRequestedBy.flatMap { $0.contains(currentMastodonUser) } ?? false
// if isPending {
// relationshipActionSet.insert(.pending)
// }
//
// let isBlocking = mastodonUser.blockingBy.flatMap { $0.contains(currentMastodonUser) } ?? false
// if isBlocking {
// relationshipActionSet.insert(.blocking)
// }
//
// let isBlockedBy = currentMastodonUser.blockingBy.flatMap { $0.contains(mastodonUser) } ?? false
// if isBlockedBy {
// relationshipActionSet.insert(.blocked)
// }
// return relationshipActionSet
// }
//
//}
//
extension RecommendAccountSection {
struct Configuration {

View File

@ -1,58 +0,0 @@
//
// SuggestionAccountCollectionViewCell.swift
// Mastodon
//
// Created by sxiaojian on 2021/4/22.
//
import CoreDataStack
import Foundation
import UIKit
import MastodonAsset
import MastodonLocalization
class SuggestionAccountCollectionViewCell: UICollectionViewCell {
let imageView: UIImageView = {
let imageView = UIImageView()
imageView.tintColor = Asset.Colors.Label.tertiary.color
imageView.layer.cornerRadius = 4
imageView.clipsToBounds = true
imageView.image = UIImage.placeholder(color: .systemFill)
return imageView
}()
func configAsPlaceHolder() {
imageView.tintColor = Asset.Colors.Label.tertiary.color
imageView.image = UIImage.placeholder(color: .systemFill)
}
func config(with mastodonUser: MastodonUser) {
imageView.af.setImage(
withURL: URL(string: mastodonUser.avatar)!,
placeholderImage: UIImage.placeholder(color: .systemFill),
imageTransition: .crossDissolve(0.2)
)
}
override func prepareForReuse() {
super.prepareForReuse()
}
override init(frame: CGRect) {
super.init(frame: .zero)
configure()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
configure()
}
}
extension SuggestionAccountCollectionViewCell {
private func configure() {
contentView.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.pinToParent()
}
}

View File

@ -9,7 +9,6 @@ import Combine
import CoreData
import CoreDataStack
import Foundation
import OSLog
import UIKit
import MastodonAsset
import MastodonCore
@ -23,51 +22,19 @@ class SuggestionAccountViewController: UIViewController, NeedsDependency {
var disposeBag = Set<AnyCancellable>()
var viewModel: SuggestionAccountViewModel!
private static func createCollectionViewLayout() -> UICollectionViewLayout {
let itemSize = NSCollectionLayoutSize(widthDimension: .absolute(64), heightDimension: .absolute(64))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: itemSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
section.contentInsets = NSDirectionalEdgeInsets(top: 24, leading: 0, bottom: 24, trailing: 0)
section.orthogonalScrollingBehavior = .continuous
section.contentInsetsReference = .readableContent
section.interGroupSpacing = 16
return UICollectionViewCompositionalLayout(section: section)
}
let tableView: UITableView = {
let tableView = ControlContainableTableView()
let tableView = UITableView(frame: .zero, style: .insetGrouped)
tableView.register(SuggestionAccountTableViewCell.self, forCellReuseIdentifier: String(describing: SuggestionAccountTableViewCell.self))
tableView.rowHeight = UITableView.automaticDimension
tableView.tableFooterView = UIView()
tableView.separatorStyle = .singleLine
tableView.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
tableView.separatorStyle = .none
return tableView
}()
deinit {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s:", (#file as NSString).lastPathComponent, #line, #function)
}
}
//TODO: Add "follow all"-footer-cell
extension SuggestionAccountViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
ThemeService.shared.currentTheme
.receive(on: DispatchQueue.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.setupBackgroundColor(theme: theme)
}
.store(in: &disposeBag)
title = L10n.Scene.SuggestionAccount.title
navigationItem.rightBarButtonItem = UIBarButtonItem(
barButtonSystemItem: UIBarButtonItem.SystemItem.done,
@ -78,7 +45,7 @@ extension SuggestionAccountViewController {
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
@ -89,6 +56,11 @@ extension SuggestionAccountViewController {
tableView: tableView,
suggestionAccountTableViewCellDelegate: self
)
view.backgroundColor = .secondarySystemBackground
tableView.backgroundColor = .secondarySystemBackground
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.largeTitleDisplayMode = .always
}
override func viewWillAppear(_ animated: Bool) {
@ -96,10 +68,6 @@ extension SuggestionAccountViewController {
tableView.deselectRow(with: transitionCoordinator, animated: animated)
}
private func setupBackgroundColor(theme: Theme) {
view.backgroundColor = theme.systemBackgroundColor
}
}
// MARK: - UITableViewDelegate
@ -156,8 +124,5 @@ extension SuggestionAccountViewController: SuggestionAccountTableViewCellDelegat
extension SuggestionAccountViewController {
@objc func doneButtonDidClick(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
// if viewModel.selectedAccounts.value.count > 0 {
// viewModel.delegate?.homeTimelineNeedRefresh.send()
// }
}
}

View File

@ -21,7 +21,7 @@ extension SuggestionAccountViewModel {
suggestionAccountTableViewCellDelegate: suggestionAccountTableViewCellDelegate
)
)
userFetchedResultsController.$records
.removeDuplicates()
.receive(on: DispatchQueue.main)

View File

@ -16,70 +16,6 @@ import Meta
extension SuggestionAccountTableViewCell {
class ViewModel {
var disposeBag = Set<AnyCancellable>()
@Published public var userIdentifier: UserIdentifier? // me
@Published var avatarImageURL: URL?
@Published public var authorName: MetaContent?
@Published public var authorUsername: String?
@Published var isFollowing = false
@Published var isPending = false
func prepareForReuse() {
isFollowing = false
isPending = false
}
}
}
extension SuggestionAccountTableViewCell.ViewModel {
func bind(cell: SuggestionAccountTableViewCell) {
// avatar
$avatarImageURL.removeDuplicates()
.sink { url in
let configuration = AvatarImageView.Configuration(url: url)
cell.avatarButton.avatarImageView.configure(configuration: configuration)
cell.avatarButton.avatarImageView.configure(cornerConfiguration: .init(corner: .fixed(radius: 12)))
}
.store(in: &disposeBag)
// name
$authorName
.sink { metaContent in
let metaContent = metaContent ?? PlaintextMetaContent(string: " ")
cell.titleLabel.configure(content: metaContent)
}
.store(in: &disposeBag)
// username
$authorUsername
.map { text -> String in
guard let text = text else { return "" }
return "@\(text)"
}
.sink { username in
cell.subTitleLabel.text = username
}
.store(in: &disposeBag)
// button
Publishers.CombineLatest(
$isFollowing,
$isPending
)
.sink { isFollowing, isPending in
let isFollowState = isFollowing || isPending
let imageName = isFollowState ? "minus.circle.fill" : "plus.circle"
let image = UIImage(systemName: imageName, withConfiguration: UIImage.SymbolConfiguration(pointSize: 22, weight: .regular))
cell.button.setImage(image, for: .normal)
cell.button.tintColor = isFollowState ? Asset.Colors.danger.color : Asset.Colors.Label.secondary.color
}
.store(in: &disposeBag)
}
}
extension SuggestionAccountTableViewCell {
func configure(user: MastodonUser) {
// author avatar
Publishers.CombineLatest(
@ -138,4 +74,62 @@ extension SuggestionAccountTableViewCell {
.assign(to: \.isPending, on: viewModel)
.store(in: &disposeBag)
}
class ViewModel {
var disposeBag = Set<AnyCancellable>()
@Published public var userIdentifier: UserIdentifier? // me
@Published var avatarImageURL: URL?
@Published public var authorName: MetaContent?
@Published public var authorUsername: String?
@Published var isFollowing = false
@Published var isPending = false
func prepareForReuse() {
isFollowing = false
isPending = false
}
func bind(cell: SuggestionAccountTableViewCell) {
// avatar
$avatarImageURL.removeDuplicates()
.sink { url in
let configuration = AvatarImageView.Configuration(url: url)
cell.avatarButton.avatarImageView.configure(configuration: configuration)
cell.avatarButton.avatarImageView.configure(cornerConfiguration: .init(corner: .fixed(radius: 12)))
}
.store(in: &disposeBag)
// name
$authorName
.sink { metaContent in
let metaContent = metaContent ?? PlaintextMetaContent(string: " ")
cell.titleLabel.configure(content: metaContent)
}
.store(in: &disposeBag)
// username
$authorUsername
.map { text -> String in
guard let text = text else { return "" }
return "@\(text)"
}
.sink { username in
cell.subTitleLabel.text = username
}
.store(in: &disposeBag)
// button
Publishers.CombineLatest(
$isFollowing,
$isPending
)
.sink { isFollowing, isPending in
let isFollowState = isFollowing || isPending
let imageName = isFollowState ? "minus.circle.fill" : "plus.circle"
let image = UIImage(systemName: imageName, withConfiguration: UIImage.SymbolConfiguration(pointSize: 22, weight: .regular))
cell.button.setImage(image, for: .normal)
cell.button.tintColor = isFollowState ? Asset.Colors.danger.color : Asset.Colors.Label.secondary.color
}
.store(in: &disposeBag)
}
}
}

View File

@ -5,7 +5,6 @@
// Created by sxiaojian on 2021/4/21.
//
import os.log
import Combine
import CoreData
import CoreDataStack
@ -23,9 +22,7 @@ protocol SuggestionAccountTableViewCellDelegate: AnyObject {
}
final class SuggestionAccountTableViewCell: UITableViewCell {
let logger = Logger(subsystem: "SuggestionAccountTableViewCell", category: "View")
var disposeBag = Set<AnyCancellable>()
weak var delegate: SuggestionAccountTableViewCellDelegate?
@ -35,7 +32,8 @@ final class SuggestionAccountTableViewCell: UITableViewCell {
viewModel.bind(cell: self)
return viewModel
}()
//TODO: Replace this with user view
let avatarButton = AvatarButton()
let titleLabel = MetaLabel(style: .statusName)
@ -49,7 +47,6 @@ final class SuggestionAccountTableViewCell: UITableViewCell {
let buttonContainer: UIView = {
let view = UIView()
view.backgroundColor = .clear
return view
}()
@ -89,6 +86,8 @@ final class SuggestionAccountTableViewCell: UITableViewCell {
extension SuggestionAccountTableViewCell {
private func configure() {
backgroundColor = .systemBackground
let containerStackView = UIStackView()
containerStackView.axis = .horizontal
containerStackView.distribution = .fill
@ -147,7 +146,6 @@ extension SuggestionAccountTableViewCell {
extension SuggestionAccountTableViewCell {
@objc private func buttonDidPressed(_ sender: UIButton) {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
delegate?.suggestionAccountTableViewCell(self, friendshipDidPressed: sender)
}
}