diff --git a/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents b/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents
index 1ef9f929d..96ec6971d 100644
--- a/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents
+++ b/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents
@@ -150,7 +150,7 @@
-
+
@@ -168,9 +168,9 @@
-
-
+
+
\ No newline at end of file
diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj
index e1283e374..7509264bb 100644
--- a/Mastodon.xcodeproj/project.pbxproj
+++ b/Mastodon.xcodeproj/project.pbxproj
@@ -153,7 +153,7 @@
DB8AF55025C13703002E6C99 /* MainTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8AF54F25C13703002E6C99 /* MainTabBarController.swift */; };
DB8AF55D25C138B7002E6C99 /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8AF55C25C138B7002E6C99 /* UIViewController.swift */; };
DB8AF56825C13E2A002E6C99 /* HomeTimelineIndex.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8AF56725C13E2A002E6C99 /* HomeTimelineIndex.swift */; };
- DB92CF7225E7BB98002C1017 /* PollTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB92CF7125E7BB98002C1017 /* PollTableViewCell.swift */; };
+ DB92CF7225E7BB98002C1017 /* PollOptionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB92CF7125E7BB98002C1017 /* PollOptionTableViewCell.swift */; };
DB98336B25C9420100AD9700 /* APIService+App.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98336A25C9420100AD9700 /* APIService+App.swift */; };
DB98337125C9443200AD9700 /* APIService+Authentication.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98337025C9443200AD9700 /* APIService+Authentication.swift */; };
DB98337F25C9452D00AD9700 /* APIService+APIError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98337E25C9452D00AD9700 /* APIService+APIError.swift */; };
@@ -379,7 +379,7 @@
DB8AF54F25C13703002E6C99 /* MainTabBarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainTabBarController.swift; sourceTree = ""; };
DB8AF55C25C138B7002E6C99 /* UIViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewController.swift; sourceTree = ""; };
DB8AF56725C13E2A002E6C99 /* HomeTimelineIndex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTimelineIndex.swift; sourceTree = ""; };
- DB92CF7125E7BB98002C1017 /* PollTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollTableViewCell.swift; sourceTree = ""; };
+ DB92CF7125E7BB98002C1017 /* PollOptionTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollOptionTableViewCell.swift; sourceTree = ""; };
DB98336A25C9420100AD9700 /* APIService+App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+App.swift"; sourceTree = ""; };
DB98337025C9443200AD9700 /* APIService+Authentication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Authentication.swift"; sourceTree = ""; };
DB98337E25C9452D00AD9700 /* APIService+APIError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "APIService+APIError.swift"; sourceTree = ""; };
@@ -684,7 +684,7 @@
2DA7D04325CA52B200804E11 /* TimelineLoaderTableViewCell.swift */,
2DA7D04925CA52CB00804E11 /* TimelineBottomLoaderTableViewCell.swift */,
2D32EAAB25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift */,
- DB92CF7125E7BB98002C1017 /* PollTableViewCell.swift */,
+ DB92CF7125E7BB98002C1017 /* PollOptionTableViewCell.swift */,
);
path = TableviewCell;
sourceTree = "";
@@ -1469,7 +1469,7 @@
2D5A3D3825CF8D9F002347D6 /* ScrollViewContainer.swift in Sources */,
0FAA101225E105390017CCDE /* PrimaryActionButton.swift in Sources */,
DB8AF53025C13561002E6C99 /* AppContext.swift in Sources */,
- DB92CF7225E7BB98002C1017 /* PollTableViewCell.swift in Sources */,
+ DB92CF7225E7BB98002C1017 /* PollOptionTableViewCell.swift in Sources */,
DB72602725E36A6F00235243 /* MastodonServerRulesViewModel.swift in Sources */,
2D364F7225E66D7500204FDC /* MastodonResendEmailViewController.swift in Sources */,
2D38F1F125CD477D00561493 /* HomeTimelineViewModel+LoadMiddleState.swift in Sources */,
diff --git a/Mastodon/Diffiable/Item/PollItem.swift b/Mastodon/Diffiable/Item/PollItem.swift
index 7a13df413..1ae8f34e3 100644
--- a/Mastodon/Diffiable/Item/PollItem.swift
+++ b/Mastodon/Diffiable/Item/PollItem.swift
@@ -9,7 +9,7 @@ import Foundation
import CoreData
enum PollItem {
- case pollOpion(objectID: NSManagedObjectID, attribute: Attribute)
+ case opion(objectID: NSManagedObjectID, attribute: Attribute)
}
@@ -17,6 +17,10 @@ extension PollItem {
class Attribute: Hashable {
var voted: Bool = false
+ init(voted: Bool = false) {
+ self.voted = voted
+ }
+
static func == (lhs: PollItem.Attribute, rhs: PollItem.Attribute) -> Bool {
return lhs.voted == rhs.voted
}
@@ -30,10 +34,8 @@ extension PollItem {
extension PollItem: Equatable {
static func == (lhs: PollItem, rhs: PollItem) -> Bool {
switch (lhs, rhs) {
- case (.pollOpion(let objectIDLeft, _), .pollOpion(let objectIDRight, _)):
+ case (.opion(let objectIDLeft, _), .opion(let objectIDRight, _)):
return objectIDLeft == objectIDRight
- default:
- return false
}
}
}
@@ -42,7 +44,7 @@ extension PollItem: Equatable {
extension PollItem: Hashable {
func hash(into hasher: inout Hasher) {
switch self {
- case .pollOpion(let objectID, _):
+ case .opion(let objectID, _):
hasher.combine(objectID)
}
}
diff --git a/Mastodon/Diffiable/Section/PollSection.swift b/Mastodon/Diffiable/Section/PollSection.swift
index 9b175c3f9..b48231dbf 100644
--- a/Mastodon/Diffiable/Section/PollSection.swift
+++ b/Mastodon/Diffiable/Section/PollSection.swift
@@ -9,7 +9,7 @@ import UIKit
import CoreData
import CoreDataStack
-enum PollSection {
+enum PollSection: Equatable, Hashable {
case main
}
@@ -19,7 +19,25 @@ extension PollSection {
managedObjectContext: NSManagedObjectContext
) -> UITableViewDiffableDataSource {
return UITableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, item -> UITableViewCell? in
- return nil
+ switch item {
+ case .opion(let objectID, let attribute):
+ let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PollOptionTableViewCell.self), for: indexPath) as! PollOptionTableViewCell
+ managedObjectContext.performAndWait {
+ let option = managedObjectContext.object(with: objectID) as! PollOption
+ PollSection.configure(cell: cell, pollOption: option, itemAttribute: attribute)
+ }
+ return cell
+ }
}
}
}
+
+extension PollSection {
+ static func configure(
+ cell: PollOptionTableViewCell,
+ pollOption: PollOption,
+ itemAttribute: PollItem.Attribute
+ ) {
+ cell.optionLabel.text = pollOption.title
+ }
+}
diff --git a/Mastodon/Diffiable/Section/StatusSection.swift b/Mastodon/Diffiable/Section/StatusSection.swift
index 89bf1c6e1..b8838869c 100644
--- a/Mastodon/Diffiable/Section/StatusSection.swift
+++ b/Mastodon/Diffiable/Section/StatusSection.swift
@@ -155,7 +155,31 @@ extension StatusSection {
cell.statusView.statusMosaicImageView.vibrancyVisualEffectView.alpha = isStatusSensitive ? 1.0 : 0.0
// set poll
-
+ if let poll = (toot.reblog ?? toot).poll {
+ cell.statusView.statusPollTableView.isHidden = false
+
+ let managedObjectContext = toot.managedObjectContext!
+ cell.statusView.statusPollTableViewDataSource = PollSection.tableViewDiffableDataSource(
+ for: cell.statusView.statusPollTableView,
+ managedObjectContext: managedObjectContext
+ )
+
+ var snapshot = NSDiffableDataSourceSnapshot()
+ snapshot.appendSections([.main])
+ let pollItems = poll.options
+ .sorted(by: { $0.index.intValue < $1.index.intValue })
+ .map { option -> PollItem in
+ let isVoted = (option.votedBy ?? Set()).map { $0.id }.contains(requestUserID)
+ let attribute = PollItem.Attribute(voted: isVoted)
+ let option = PollItem.opion(objectID: option.objectID, attribute: attribute)
+ return option
+ }
+ snapshot.appendItems(pollItems, toSection: .main)
+ cell.statusView.statusPollTableViewDataSource?.apply(snapshot, animatingDifferences: false, completion: nil)
+ // cell.statusView.statusPollTableView.layoutIfNeeded()
+ } else {
+ cell.statusView.statusPollTableView.isHidden = true
+ }
// toolbar
let replyCountTitle: String = {
diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift
index bb6d6dae4..0937e1fb4 100644
--- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift
+++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift
@@ -152,6 +152,10 @@ extension HomeTimelineViewController {
self.context.apiService.backgroundManagedObjectContext.delete(toot)
}
}
+ .sink { _ in
+ // do nothing
+ }
+ .store(in: &self.disposeBag)
case .failure(let error):
assertionFailure(error.localizedDescription)
}
diff --git a/Mastodon/Scene/Share/View/Content/StatusView.swift b/Mastodon/Scene/Share/View/Content/StatusView.swift
index abaa38f33..77cc851c1 100644
--- a/Mastodon/Scene/Share/View/Content/StatusView.swift
+++ b/Mastodon/Scene/Share/View/Content/StatusView.swift
@@ -17,6 +17,8 @@ protocol StatusViewDelegate: class {
final class StatusView: UIView {
+ var statusPollTableViewHeightObservation: NSKeyValueObservation?
+
static let avatarImageSize = CGSize(width: 42, height: 42)
static let avatarImageCornerRadius: CGFloat = 4
static let contentWarningBlurRadius: CGFloat = 12
@@ -24,6 +26,7 @@ final class StatusView: UIView {
weak var delegate: StatusViewDelegate?
var isStatusTextSensitive = false
var statusPollTableViewDataSource: UITableViewDiffableDataSource?
+ var statusPollTableViewHeightLaoutConstraint: NSLayoutConstraint!
let headerContainerStackView = UIStackView()
@@ -103,9 +106,11 @@ final class StatusView: UIView {
let statusMosaicImageView = MosaicImageViewContainer()
let statusPollTableView: UITableView = {
- let tableView = UITableView()
- tableView.register(PollTableViewCell.self, forCellReuseIdentifier: String(describing: PollTableViewCell.self))
+ let tableView = UITableView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
+ tableView.register(PollOptionTableViewCell.self, forCellReuseIdentifier: String(describing: PollOptionTableViewCell.self))
tableView.isScrollEnabled = false
+ tableView.separatorStyle = .none
+ tableView.backgroundColor = .clear
return tableView
}()
@@ -144,6 +149,10 @@ final class StatusView: UIView {
drawContentWarningImageView()
}
}
+
+ deinit {
+ statusPollTableViewHeightObservation = nil
+ }
}
@@ -265,8 +274,23 @@ extension StatusView {
])
statusContentWarningContainerStackView.addArrangedSubview(contentWarningTitle)
statusContentWarningContainerStackView.addArrangedSubview(contentWarningActionButton)
+
statusContainerStackView.addArrangedSubview(statusMosaicImageView)
+ statusPollTableView.translatesAutoresizingMaskIntoConstraints = false
statusContainerStackView.addArrangedSubview(statusPollTableView)
+ statusPollTableViewHeightLaoutConstraint = statusPollTableView.heightAnchor.constraint(equalToConstant: 44.0).priority(.required - 1)
+ NSLayoutConstraint.activate([
+ statusPollTableViewHeightLaoutConstraint,
+ ])
+
+ statusPollTableViewHeightObservation = statusPollTableView.observe(\.contentSize, options: .new, changeHandler: { [weak self] tableView, _ in
+ guard let self = self else { return }
+ guard self.statusPollTableView.contentSize.height != .zero else {
+ self.statusPollTableViewHeightLaoutConstraint.constant = 44
+ return
+ }
+ self.statusPollTableViewHeightLaoutConstraint.constant = self.statusPollTableView.contentSize.height
+ })
// action toolbar container
containerStackView.addArrangedSubview(actionToolbarContainer)
@@ -322,14 +346,13 @@ extension StatusView {
}
}
+// MARK: - AvatarConfigurableView
extension StatusView: AvatarConfigurableView {
static var configurableAvatarImageSize: CGSize { return Self.avatarImageSize }
static var configurableAvatarImageCornerRadius: CGFloat { return 4 }
var configurableAvatarImageView: UIImageView? { return nil }
var configurableAvatarButton: UIButton? { return avatarButton }
var configurableVerifiedBadgeImageView: UIImageView? { nil }
-
-
}
#if canImport(SwiftUI) && DEBUG
diff --git a/Mastodon/Scene/Share/View/TableviewCell/PollTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/PollOptionTableViewCell.swift
similarity index 86%
rename from Mastodon/Scene/Share/View/TableviewCell/PollTableViewCell.swift
rename to Mastodon/Scene/Share/View/TableviewCell/PollOptionTableViewCell.swift
index d41fd7428..5372380bd 100644
--- a/Mastodon/Scene/Share/View/TableviewCell/PollTableViewCell.swift
+++ b/Mastodon/Scene/Share/View/TableviewCell/PollOptionTableViewCell.swift
@@ -1,5 +1,5 @@
//
-// PollTableViewCell.swift
+// PollOptionTableViewCell.swift
// Mastodon
//
// Created by MainasuK Cirno on 2021-2-25.
@@ -7,8 +7,11 @@
import UIKit
-final class PollTableViewCell: UITableViewCell {
+final class PollOptionTableViewCell: UITableViewCell {
+ static let height: CGFloat = optionHeight + 2 * verticalMargin
+ static let optionHeight: CGFloat = 44
+ static let verticalMargin: CGFloat = 5
static let checkmarkImageSize = CGSize(width: 26, height: 26)
let roundedBackgroundView = UIView()
@@ -57,9 +60,11 @@ final class PollTableViewCell: UITableViewCell {
}
-extension PollTableViewCell {
+extension PollOptionTableViewCell {
private func _init() {
+ selectionStyle = .none
+ backgroundColor = .clear
roundedBackgroundView.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
roundedBackgroundView.translatesAutoresizingMaskIntoConstraints = false
@@ -69,6 +74,7 @@ extension PollTableViewCell {
roundedBackgroundView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
roundedBackgroundView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
contentView.bottomAnchor.constraint(equalTo: roundedBackgroundView.bottomAnchor, constant: 5),
+ roundedBackgroundView.heightAnchor.constraint(equalToConstant: PollOptionTableViewCell.optionHeight).priority(.defaultHigh),
])
checkmarkBackgroundView.translatesAutoresizingMaskIntoConstraints = false
@@ -77,8 +83,8 @@ extension PollTableViewCell {
checkmarkBackgroundView.topAnchor.constraint(equalTo: roundedBackgroundView.topAnchor, constant: 9),
checkmarkBackgroundView.leadingAnchor.constraint(equalTo: roundedBackgroundView.leadingAnchor, constant: 9),
roundedBackgroundView.bottomAnchor.constraint(equalTo: checkmarkBackgroundView.bottomAnchor, constant: 9),
- checkmarkBackgroundView.widthAnchor.constraint(equalToConstant: PollTableViewCell.checkmarkImageSize.width).priority(.defaultHigh),
- checkmarkBackgroundView.heightAnchor.constraint(equalToConstant: PollTableViewCell.checkmarkImageSize.height).priority(.defaultHigh),
+ checkmarkBackgroundView.widthAnchor.constraint(equalToConstant: PollOptionTableViewCell.checkmarkImageSize.width).priority(.defaultHigh),
+ checkmarkBackgroundView.heightAnchor.constraint(equalToConstant: PollOptionTableViewCell.checkmarkImageSize.height).priority(.defaultHigh),
])
checkmarkImageView.translatesAutoresizingMaskIntoConstraints = false
@@ -104,6 +110,8 @@ extension PollTableViewCell {
roundedBackgroundView.trailingAnchor.constraint(equalTo: optionPercentageLabel.trailingAnchor, constant: 18),
optionPercentageLabel.centerYAnchor.constraint(equalTo: roundedBackgroundView.centerYAnchor),
])
+ optionPercentageLabel.setContentHuggingPriority(.required - 1, for: .horizontal)
+ optionPercentageLabel.setContentCompressionResistancePriority(.required - 1, for: .horizontal)
configureCheckmark(state: .none)
}
@@ -111,8 +119,12 @@ extension PollTableViewCell {
override func layoutSubviews() {
super.layoutSubviews()
+ updateCornerRadius()
+ }
+
+ private func updateCornerRadius() {
roundedBackgroundView.layer.masksToBounds = true
- roundedBackgroundView.layer.cornerRadius = roundedBackgroundView.bounds.height * 0.5
+ roundedBackgroundView.layer.cornerRadius = PollOptionTableViewCell.optionHeight * 0.5
roundedBackgroundView.layer.cornerCurve = .circular
checkmarkBackgroundView.layer.masksToBounds = true
@@ -122,7 +134,7 @@ extension PollTableViewCell {
}
-extension PollTableViewCell {
+extension PollOptionTableViewCell {
enum CheckmarkState {
case none
@@ -168,17 +180,17 @@ struct PollTableViewCell_Previews: PreviewProvider {
static var controls: some View {
Group {
UIViewPreview() {
- PollTableViewCell()
+ PollOptionTableViewCell()
}
.previewLayout(.fixed(width: 375, height: 44 + 10))
UIViewPreview() {
- let cell = PollTableViewCell()
+ let cell = PollOptionTableViewCell()
cell.configureCheckmark(state: .off)
return cell
}
.previewLayout(.fixed(width: 375, height: 44 + 10))
UIViewPreview() {
- let cell = PollTableViewCell()
+ let cell = PollOptionTableViewCell()
cell.configureCheckmark(state: .on)
return cell
}
diff --git a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift
index eb1a015b4..900094c57 100644
--- a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift
+++ b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift
@@ -10,7 +10,6 @@ import UIKit
import AVKit
import Combine
-
protocol StatusTableViewCellDelegate: class {
func statusTableViewCell(_ cell: StatusTableViewCell, actionToolbarContainer: ActionToolbarContainer, likeButtonDidPressed sender: UIButton)
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, contentWarningActionButtonPressed button: UIButton)