mirror of
https://github.com/metabolist/metatext.git
synced 2024-11-22 00:01:00 +00:00
Conversation unread state
This commit is contained in:
parent
63f9b59135
commit
6294b1c52f
6 changed files with 60 additions and 0 deletions
|
@ -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";
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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))))
|
||||||
|
|
|
@ -33,3 +33,7 @@ public final class ConversationViewModel: ObservableObject {
|
||||||
self.identityContext = identityContext
|
self.identityContext = identityContext
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public extension ConversationViewModel {
|
||||||
|
var isUnread: Bool { conversationService.conversation.unread }
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue