Conversation unread state

This commit is contained in:
Justin Mazzocchi 2021-02-19 17:42:45 -08:00
parent 63f9b59135
commit 6294b1c52f
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
6 changed files with 60 additions and 0 deletions

View file

@ -107,6 +107,7 @@
"compose.visibility-button.accessibility-label-%@" = "Privacy: %@"; "compose.visibility-button.accessibility-label-%@" = "Privacy: %@";
"compose-button.accessibility-label.post" = "Compose Post"; "compose-button.accessibility-label.post" = "Compose Post";
"compose-button.accessibility-label.toot" = "Compose Toot"; "compose-button.accessibility-label.toot" = "Compose Toot";
"conversation.unread" = "Unread";
"emoji.custom" = "Custom"; "emoji.custom" = "Custom";
"emoji.default-skin-tone" = "Default skin tone"; "emoji.default-skin-tone" = "Default skin tone";
"emoji.default-skin-tone-button.accessibility-label" = "Select default skin tone"; "emoji.default-skin-tone-button.accessibility-label" = "Select default skin tone";

View file

@ -0,0 +1,31 @@
// Copyright © 2020 Metabolist. All rights reserved.
import Foundation
import HTTP
import Mastodon
public enum ConversationEndpoint {
case read(id: Conversation.Id)
}
extension ConversationEndpoint: Endpoint {
public typealias ResultType = Conversation
public var context: [String] {
defaultContext + ["conversations"]
}
public var pathComponentsInContext: [String] {
switch self {
case let .read(id):
return [id, "read"]
}
}
public var method: HTTPMethod {
switch self {
case .read:
return .post
}
}
}

View file

@ -26,6 +26,14 @@ public struct ConversationsService {
} }
} }
public extension ConversationsService {
func markConversationAsRead(id: Conversation.Id) -> AnyPublisher<Never, Error> {
mastodonAPIClient.request(ConversationEndpoint.read(id: id))
.flatMap { contentDatabase.insert(conversations: [$0]) }
.eraseToAnyPublisher()
}
}
extension ConversationsService: CollectionService { extension ConversationsService: CollectionService {
public func request(maxId: String?, minId: String?, search: Search?) -> AnyPublisher<Never, Error> { public func request(maxId: String?, minId: String?, search: Search?) -> AnyPublisher<Never, Error> {
mastodonAPIClient.pagedRequest(ConversationsEndpoint.conversations, maxId: maxId, minId: minId) mastodonAPIClient.pagedRequest(ConversationsEndpoint.conversations, maxId: maxId, minId: minId)

View file

@ -149,6 +149,10 @@ extension CollectionItemsViewModel: CollectionViewModel {
case let .conversation(conversation): case let .conversation(conversation):
guard let status = conversation.lastStatus else { break } guard let status = conversation.lastStatus else { break }
(collectionService as? ConversationsService)?.markConversationAsRead(id: conversation.id)
.sink { _ in } receiveValue: { _ in }
.store(in: &cancellables)
send(event: .navigation(.collection(collectionService send(event: .navigation(.collection(collectionService
.navigationService .navigationService
.contextService(id: status.displayStatus.id)))) .contextService(id: status.displayStatus.id))))

View file

@ -33,3 +33,7 @@ public final class ConversationViewModel: ObservableObject {
self.identityContext = identityContext self.identityContext = identityContext
} }
} }
public extension ConversationViewModel {
var isUnread: Bool { conversationService.conversation.unread }
}

View file

@ -7,6 +7,9 @@ import ViewModels
final class ConversationView: UIView { final class ConversationView: UIView {
let avatarsView = ConversationAvatarsView() let avatarsView = ConversationAvatarsView()
let displayNamesLabel = UILabel() let displayNamesLabel = UILabel()
let unreadIndicator = UIImageView(image: UIImage(
systemName: "circlebadge.fill",
withConfiguration: UIImage.SymbolConfiguration(scale: .small)))
let timeLabel = UILabel() let timeLabel = UILabel()
let statusBodyView = StatusBodyView() let statusBodyView = StatusBodyView()
@ -78,6 +81,7 @@ private extension ConversationView {
namesTimeStackView.spacing = .compactSpacing namesTimeStackView.spacing = .compactSpacing
namesTimeStackView.alignment = .top namesTimeStackView.alignment = .top
namesTimeStackView.addArrangedSubview(displayNamesLabel) namesTimeStackView.addArrangedSubview(displayNamesLabel)
namesTimeStackView.addArrangedSubview(unreadIndicator)
namesTimeStackView.addArrangedSubview(timeLabel) namesTimeStackView.addArrangedSubview(timeLabel)
mainStackView.axis = .vertical mainStackView.axis = .vertical
@ -90,6 +94,9 @@ private extension ConversationView {
displayNamesLabel.adjustsFontForContentSizeCategory = true displayNamesLabel.adjustsFontForContentSizeCategory = true
displayNamesLabel.numberOfLines = 0 displayNamesLabel.numberOfLines = 0
unreadIndicator.contentMode = .scaleAspectFit
unreadIndicator.setContentHuggingPriority(.required, for: .horizontal)
timeLabel.font = .preferredFont(forTextStyle: .subheadline) timeLabel.font = .preferredFont(forTextStyle: .subheadline)
timeLabel.adjustsFontForContentSizeCategory = true timeLabel.adjustsFontForContentSizeCategory = true
timeLabel.textColor = .secondaryLabel timeLabel.textColor = .secondaryLabel
@ -126,6 +133,7 @@ private extension ConversationView {
view: displayNamesLabel) view: displayNamesLabel)
mutableDisplayNames.resizeAttachments(toLineHeight: displayNamesLabel.font.lineHeight) mutableDisplayNames.resizeAttachments(toLineHeight: displayNamesLabel.font.lineHeight)
unreadIndicator.isHidden = !viewModel.isUnread
displayNamesLabel.attributedText = mutableDisplayNames displayNamesLabel.attributedText = mutableDisplayNames
timeLabel.text = viewModel.statusViewModel?.time timeLabel.text = viewModel.statusViewModel?.time
timeLabel.accessibilityLabel = viewModel.statusViewModel?.accessibilityTime timeLabel.accessibilityLabel = viewModel.statusViewModel?.accessibilityTime
@ -134,6 +142,10 @@ private extension ConversationView {
let accessibilityAttributedLabel = NSMutableAttributedString(attributedString: mutableDisplayNames) let accessibilityAttributedLabel = NSMutableAttributedString(attributedString: mutableDisplayNames)
if viewModel.isUnread {
accessibilityAttributedLabel.appendWithSeparator(NSLocalizedString("conversation.unread", comment: ""))
}
if let statusBodyAccessibilityAttributedLabel = statusBodyView.accessibilityAttributedLabel { if let statusBodyAccessibilityAttributedLabel = statusBodyView.accessibilityAttributedLabel {
accessibilityAttributedLabel.appendWithSeparator(statusBodyAccessibilityAttributedLabel) accessibilityAttributedLabel.appendWithSeparator(statusBodyAccessibilityAttributedLabel)
} }