Propagate ThreadAssociatedData audioPlaybackRate down to CVComponentAudioAttachment

* Propagate ThreadAssociatedData audioPlaybackRate down to CVComponentAudioAttachment

* remove audioplaybackrate from component state; keep only on view state
This commit is contained in:
harry-signal 2022-08-04 15:53:11 -07:00 committed by GitHub
parent f305b4a2aa
commit 202c137ced
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 89 additions and 17 deletions

View File

@ -16,6 +16,8 @@ public protocol CVComponentDelegate {
func cvc_enqueueReload()
func cvc_enqueueReloadWithoutCaches()
// MARK: - Body Text Items
func cvc_didTapBodyTextItem(_ item: CVBodyTextLabel.ItemObject)

View File

@ -73,8 +73,11 @@ public class CVComponentAudioAttachment: CVComponentBase, CVComponent {
} else if let outgoingMessage = interaction as? TSOutgoingMessage {
audioMessageView.setViewed(!outgoingMessage.viewedRecipientAddresses().isEmpty, animated: false)
}
audioMessageView.configureForRendering(cellMeasurement: cellMeasurement,
conversationStyle: conversationStyle)
audioMessageView.configureForRendering(
cellMeasurement: cellMeasurement,
conversationStyle: conversationStyle,
audioPlaybackRate: itemViewState.audioPlaybackRate
)
componentView.audioMessageView = audioMessageView
stackView.configure(config: stackViewConfig,
cellMeasurement: cellMeasurement,
@ -108,11 +111,14 @@ public class CVComponentAudioAttachment: CVComponentBase, CVComponent {
measurementBuilder.setSize(key: Self.measurementKey_footerSize, size: footerSize)
}
let audioSize = AudioMessageView.measure(maxWidth: maxWidth,
audioAttachment: audioAttachment,
isIncoming: isIncoming,
conversationStyle: conversationStyle,
measurementBuilder: measurementBuilder).ceil
let audioSize = AudioMessageView.measure(
maxWidth: maxWidth,
audioAttachment: audioAttachment,
isIncoming: isIncoming,
conversationStyle: conversationStyle,
audioPlaybackRate: itemViewState.audioPlaybackRate,
measurementBuilder: measurementBuilder
).ceil
let audioInfo = audioSize.asManualSubviewInfo
let stackMeasurement = ManualStackView.measure(config: stackViewConfig,
measurementBuilder: measurementBuilder,

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
// Copyright (c) 2022 Open Whisper Systems. All rights reserved.
//
import Foundation
@ -11,6 +11,7 @@ import Foundation
public class CVItemModel: NSObject {
public let interaction: TSInteraction
public let thread: TSThread
public let threadAssociatedData: ThreadAssociatedData
// The item state loaded from the database.
public let componentState: CVComponentState
@ -35,12 +36,14 @@ public class CVItemModel: NSObject {
init(interaction: TSInteraction,
thread: TSThread,
threadAssociatedData: ThreadAssociatedData,
componentState: CVComponentState,
itemViewState: CVItemViewState,
coreState: CVCoreState) {
self.interaction = interaction
self.thread = thread
self.threadAssociatedData = threadAssociatedData
self.componentState = componentState
self.itemViewState = itemViewState
self.coreState = coreState

View File

@ -3,6 +3,7 @@
//
import Foundation
import SignalServiceKit
// CVItemViewState represents the transient, un-persisted values
// that may affect item appearance.
@ -27,6 +28,7 @@ public struct CVItemViewState: Equatable {
let bodyTextState: CVComponentBodyText.State?
let giftBadgeState: CVComponentGiftBadge.ViewState?
let nextAudioAttachment: AudioAttachment?
let audioPlaybackRate: Float
let uiMode: ConversationUIMode
let previousUIMode: ConversationUIMode
@ -47,6 +49,7 @@ public struct CVItemViewState: Equatable {
var bodyTextState: CVComponentBodyText.State?
var giftBadgeState: CVComponentGiftBadge.ViewState?
var nextAudioAttachment: AudioAttachment?
var audioPlaybackRate: Float = 1
var uiMode: ConversationUIMode = .normal
var previousUIMode: ConversationUIMode = .normal
@ -63,6 +66,7 @@ public struct CVItemViewState: Equatable {
bodyTextState: bodyTextState,
giftBadgeState: giftBadgeState,
nextAudioAttachment: nextAudioAttachment,
audioPlaybackRate: audioPlaybackRate,
uiMode: uiMode,
previousUIMode: previousUIMode)
}
@ -191,6 +195,7 @@ struct CVItemModelBuilder: CVItemBuilding, Dependencies {
public static func buildStandaloneItem(interaction: TSInteraction,
thread: TSThread,
threadAssociatedData: ThreadAssociatedData,
threadViewModel: ThreadViewModel,
itemBuildingContext: CVItemBuildingContext,
transaction: SDSAnyReadTransaction) -> CVItemModel? {
@ -200,6 +205,7 @@ struct CVItemModelBuilder: CVItemBuilding, Dependencies {
guard let itemBuilder = Self.itemBuilder(forInteraction: interaction,
thread: thread,
threadAssociatedData: threadAssociatedData,
itemBuildingContext: itemBuildingContext,
componentStateCache: ComponentStateCache()) else {
owsFailDebug("Could not create itemBuilder.")
@ -259,6 +265,8 @@ struct CVItemModelBuilder: CVItemBuilding, Dependencies {
itemViewState.giftBadgeState = CVComponentGiftBadge.buildViewState(giftBadge)
}
itemViewState.audioPlaybackRate = threadViewModel.associatedData.audioPlaybackRate
if interaction.interactionType == .dateHeader {
itemViewState.dateHeaderState = CVComponentDateHeader.buildState(interaction: interaction)
}
@ -501,6 +509,7 @@ struct CVItemModelBuilder: CVItemBuilding, Dependencies {
itemBuildingContext: itemBuildingContext)
let item = ItemBuilder(interaction: interaction,
thread: thread,
threadAssociatedData: threadAssociatedData,
componentState: componentState)
items.append(item)
}
@ -527,6 +536,7 @@ struct CVItemModelBuilder: CVItemBuilding, Dependencies {
itemBuildingContext: itemBuildingContext)
let item = ItemBuilder(interaction: interaction,
thread: thread,
threadAssociatedData: threadAssociatedData,
componentState: componentState)
items.append(item)
}
@ -571,6 +581,7 @@ struct CVItemModelBuilder: CVItemBuilding, Dependencies {
private mutating func addItem(interaction: TSInteraction) -> ItemBuilder? {
guard let item = Self.itemBuilder(forInteraction: interaction,
thread: thread,
threadAssociatedData: threadAssociatedData,
itemBuildingContext: itemBuildingContext,
componentStateCache: componentStateCache) else {
return nil
@ -603,6 +614,7 @@ struct CVItemModelBuilder: CVItemBuilding, Dependencies {
private static func itemBuilder(forInteraction interaction: TSInteraction,
thread: TSThread,
threadAssociatedData: ThreadAssociatedData,
itemBuildingContext: CVItemBuildingContext,
componentStateCache: ComponentStateCache) -> ItemBuilder? {
let componentState: CVComponentState
@ -617,6 +629,7 @@ struct CVItemModelBuilder: CVItemBuilding, Dependencies {
return ItemBuilder(interaction: interaction,
thread: thread,
threadAssociatedData: threadAssociatedData,
componentState: componentState)
}
@ -689,20 +702,24 @@ fileprivate extension CVMessageMapping {
private class ItemBuilder {
let interaction: TSInteraction
let thread: TSThread
let threadAssociatedData: ThreadAssociatedData
let componentState: CVComponentState
var itemViewState = CVItemViewState.Builder()
required init(interaction: TSInteraction,
thread: TSThread,
threadAssociatedData: ThreadAssociatedData,
componentState: CVComponentState) {
self.interaction = interaction
self.thread = thread
self.threadAssociatedData = threadAssociatedData
self.componentState = componentState
}
func build(coreState: CVCoreState) -> CVItemModel {
CVItemModel(interaction: interaction,
thread: thread,
threadAssociatedData: threadAssociatedData,
componentState: componentState,
itemViewState: itemViewState.build(),
coreState: coreState)

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
// Copyright (c) 2022 Open Whisper Systems. All rights reserved.
//
import Foundation
@ -85,6 +85,7 @@ extension CVItemBuilding {
// Convenience Accessors
var threadViewModel: ThreadViewModel { itemBuildingContext.threadViewModel }
var thread: TSThread { itemBuildingContext.thread }
var threadAssociatedData: ThreadAssociatedData { threadViewModel.associatedData }
var viewStateSnapshot: CVViewStateSnapshot { itemBuildingContext.viewStateSnapshot }
var conversationStyle: ConversationStyle { itemBuildingContext.conversationStyle }
var mediaCache: CVMediaCache { itemBuildingContext.mediaCache }

View File

@ -261,6 +261,7 @@ public class CVLoader: NSObject {
@objc
public static func buildStandaloneRenderItem(interaction: TSInteraction,
thread: TSThread,
threadAssociatedData: ThreadAssociatedData,
containerView: UIView,
transaction: SDSAnyReadTransaction) -> CVRenderItem? {
let chatColor = ChatColors.chatColorForRendering(thread: thread, transaction: transaction)
@ -274,6 +275,7 @@ public class CVLoader: NSObject {
mediaCache: CVMediaCache())
return CVLoader.buildStandaloneRenderItem(interaction: interaction,
thread: thread,
threadAssociatedData: threadAssociatedData,
coreState: coreState,
transaction: transaction)
}
@ -281,18 +283,21 @@ public class CVLoader: NSObject {
@objc
public static func buildStandaloneRenderItem(interaction: TSInteraction,
thread: TSThread,
threadAssociatedData: ThreadAssociatedData,
conversationStyle: ConversationStyle,
transaction: SDSAnyReadTransaction) -> CVRenderItem? {
let coreState = CVCoreState(conversationStyle: conversationStyle,
mediaCache: CVMediaCache())
return CVLoader.buildStandaloneRenderItem(interaction: interaction,
thread: thread,
threadAssociatedData: threadAssociatedData,
coreState: coreState,
transaction: transaction)
}
private static func buildStandaloneRenderItem(interaction: TSInteraction,
thread: TSThread,
threadAssociatedData: ThreadAssociatedData,
coreState: CVCoreState,
transaction: SDSAnyReadTransaction) -> CVRenderItem? {
AssertIsOnMainThread()
@ -308,6 +313,7 @@ public class CVLoader: NSObject {
avatarBuilder: avatarBuilder)
guard let itemModel = CVItemModelBuilder.buildStandaloneItem(interaction: interaction,
thread: thread,
threadAssociatedData: threadAssociatedData,
threadViewModel: threadViewModel,
itemBuildingContext: itemBuildingContext,
transaction: transaction) else {

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
// Copyright (c) 2022 Open Whisper Systems. All rights reserved.
//
import Foundation

View File

@ -60,8 +60,11 @@ class AudioMessageView: ManualStackView {
super.init(name: "AudioMessageView")
}
public func configureForRendering(cellMeasurement: CVCellMeasurement,
conversationStyle: ConversationStyle) {
public func configureForRendering(
cellMeasurement: CVCellMeasurement,
conversationStyle: ConversationStyle,
audioPlaybackRate: Float
) {
var outerSubviews = [UIView]()
@ -185,11 +188,14 @@ class AudioMessageView: ManualStackView {
private static let measurementKey_bottomInnerStack = "CVComponentAudioAttachment.measurementKey_bottomInnerStack"
private static let measurementKey_outerStack = "CVComponentAudioAttachment.measurementKey_outerStack"
public static func measure(maxWidth: CGFloat,
audioAttachment: AudioAttachment,
isIncoming: Bool,
conversationStyle: ConversationStyle,
measurementBuilder: CVCellMeasurement.Builder) -> CGSize {
public static func measure(
maxWidth: CGFloat,
audioAttachment: AudioAttachment,
isIncoming: Bool,
conversationStyle: ConversationStyle,
audioPlaybackRate: Float,
measurementBuilder: CVCellMeasurement.Builder
) -> CGSize {
owsAssertDebug(maxWidth > 0)
var outerSubviewInfos = [ManualStackSubviewInfo]()

View File

@ -19,6 +19,10 @@ extension ConversationViewController: CVComponentDelegate {
self.loadCoordinator.enqueueReload()
}
public func cvc_enqueueReloadWithoutCaches() {
self.loadCoordinator.enqueueReloadWithoutCaches()
}
// MARK: - Body Text Items
public func cvc_didTapBodyTextItem(_ item: CVBodyTextLabel.ItemObject) {

View File

@ -1950,11 +1950,13 @@ typedef NS_CLOSED_ENUM(NSUInteger, MessageContentType) {
isAttachmentDownloaded:YES
quotedMessage:nil
transaction:transaction];
ThreadAssociatedData *threadAssociatedData = [self createFakeThreadAssociatedData:thread];
OWSAssertDebug(messageToQuote);
UIView *containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
CVRenderItem *renderItem = [CVLoader buildStandaloneRenderItemWithInteraction:messageToQuote
thread:thread
threadAssociatedData:threadAssociatedData
containerView:containerView
transaction:transaction];
CVItemViewModelImpl *itemViewModel = [[CVItemViewModelImpl alloc] initWithRenderItem:renderItem];
@ -1975,10 +1977,12 @@ typedef NS_CLOSED_ENUM(NSUInteger, MessageContentType) {
messageSticker:nil
transaction:transaction];
OWSAssertDebug(messageToQuote);
ThreadAssociatedData *threadAssociatedData = [self createFakeThreadAssociatedData:thread];
UIView *containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
CVRenderItem *renderItem = [CVLoader buildStandaloneRenderItemWithInteraction:messageToQuote
thread:thread
threadAssociatedData:threadAssociatedData
containerView:containerView
transaction:transaction];
CVItemViewModelImpl *itemViewModel = [[CVItemViewModelImpl alloc] initWithRenderItem:renderItem];
@ -4467,6 +4471,15 @@ typedef OWSContact * (^OWSContactBlock)(SDSAnyWriteTransaction *transaction);
return label;
}
+ (ThreadAssociatedData *)createFakeThreadAssociatedData:(TSThread *)thread
{
return [[ThreadAssociatedData alloc] initWithThreadUniqueId:thread.uniqueId
isArchived:NO
isMarkedUnread:NO
mutedUntilTimestamp:0
audioPlaybackRate:1];
}
+ (TSOutgoingMessage *)createFakeOutgoingMessage:(TSThread *)thread
messageBody:(nullable NSString *)messageBody
fakeAssetLoader:(nullable DebugUIMessagesAssetLoader *)fakeAssetLoader

View File

@ -646,8 +646,11 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
owsFailDebug("Missing thread.")
return nil
}
let threadAssociatedData = ThreadAssociatedData.fetchOrDefault(for: thread,
transaction: transaction)
return CVLoader.buildStandaloneRenderItem(interaction: interaction,
thread: thread,
threadAssociatedData: threadAssociatedData,
containerView: self.view,
transaction: transaction)
}

View File

@ -205,6 +205,7 @@ class MessageDetailViewController: OWSTableViewController2 {
owsFailDebug("Missing thread.")
return nil
}
let threadAssociatedData = ThreadAssociatedData.fetchOrDefault(for: thread, transaction: transaction)
let chatColor = ChatColors.chatColorForRendering(thread: thread, transaction: transaction)
@ -220,6 +221,7 @@ class MessageDetailViewController: OWSTableViewController2 {
return CVLoader.buildStandaloneRenderItem(
interaction: interaction,
thread: thread,
threadAssociatedData: threadAssociatedData,
conversationStyle: conversationStyle,
transaction: transaction
)
@ -883,6 +885,10 @@ extension MessageDetailViewController: CVComponentDelegate {
self.refreshContent()
}
func cvc_enqueueReloadWithoutCaches() {
self.refreshContentForDatabaseUpdate()
}
// MARK: - Body Text Items
func cvc_didTapBodyTextItem(_ item: CVBodyTextLabel.ItemObject) {}

View File

@ -128,6 +128,7 @@ class MockConversationView: UIView {
isWallpaperPhoto: false,
chatColor: chatColor
)
let threadAssociatedData = ThreadAssociatedData.fetchOrDefault(for: thread, transaction: transaction)
for item in model.items {
let interaction: TSInteraction
switch item {
@ -142,6 +143,7 @@ class MockConversationView: UIView {
guard let renderItem = CVLoader.buildStandaloneRenderItem(
interaction: interaction,
thread: self.thread,
threadAssociatedData: threadAssociatedData,
conversationStyle: conversationStyle,
transaction: transaction
) else {
@ -273,6 +275,8 @@ extension MockConversationView: CVComponentDelegate {
func cvc_enqueueReload() {}
func cvc_enqueueReloadWithoutCaches() {}
func cvc_didTapBodyTextItem(_ item: CVBodyTextLabel.ItemObject) {}
func cvc_didLongPressBodyTextItem(_ item: CVBodyTextLabel.ItemObject) {}

View File

@ -126,6 +126,7 @@ public class ThreadAssociatedData: NSObject, Codable, FetchableRecord, Persistab
self.id = rowID
}
@objc
public init(
threadUniqueId: String,
isArchived: Bool,