Add auto-download settings for media.
This commit is contained in:
parent
b075aa2e8e
commit
5abf846809
@ -525,7 +525,7 @@ public enum CVComponentKey: CustomStringConvertible, CaseIterable {
|
||||
case unreadIndicator
|
||||
case typingIndicator
|
||||
case threadDetails
|
||||
case failedDownloads
|
||||
case failedOrPendingDownloads
|
||||
|
||||
public var description: String {
|
||||
switch self {
|
||||
@ -567,8 +567,8 @@ public enum CVComponentKey: CustomStringConvertible, CaseIterable {
|
||||
return ".typingIndicator"
|
||||
case .threadDetails:
|
||||
return ".threadDetails"
|
||||
case .failedDownloads:
|
||||
return ".failedDownloads"
|
||||
case .failedOrPendingDownloads:
|
||||
return ".failedOrPendingDownloads"
|
||||
case .sendFailureBadge:
|
||||
return ".sendFailureBadge"
|
||||
}
|
||||
|
||||
@ -216,10 +216,10 @@ public class CVComponentState: Equatable {
|
||||
}
|
||||
let bottomButtons: BottomButtons?
|
||||
|
||||
struct FailedDownloads: Equatable {
|
||||
struct FailedOrPendingDownloads: Equatable {
|
||||
let attachmentPointers: [TSAttachmentPointer]
|
||||
}
|
||||
let failedDownloads: FailedDownloads?
|
||||
let failedOrPendingDownloads: FailedOrPendingDownloads?
|
||||
|
||||
struct SendFailureBadge: Equatable {
|
||||
}
|
||||
@ -244,7 +244,7 @@ public class CVComponentState: Equatable {
|
||||
typingIndicator: TypingIndicator?,
|
||||
threadDetails: ThreadDetails?,
|
||||
bottomButtons: BottomButtons?,
|
||||
failedDownloads: FailedDownloads?,
|
||||
failedOrPendingDownloads: FailedOrPendingDownloads?,
|
||||
sendFailureBadge: SendFailureBadge?) {
|
||||
|
||||
self.messageCellType = messageCellType
|
||||
@ -266,7 +266,7 @@ public class CVComponentState: Equatable {
|
||||
self.typingIndicator = typingIndicator
|
||||
self.threadDetails = threadDetails
|
||||
self.bottomButtons = bottomButtons
|
||||
self.failedDownloads = failedDownloads
|
||||
self.failedOrPendingDownloads = failedOrPendingDownloads
|
||||
self.sendFailureBadge = sendFailureBadge
|
||||
}
|
||||
|
||||
@ -292,7 +292,7 @@ public class CVComponentState: Equatable {
|
||||
lhs.typingIndicator == rhs.typingIndicator &&
|
||||
lhs.threadDetails == rhs.threadDetails &&
|
||||
lhs.bottomButtons == rhs.bottomButtons &&
|
||||
lhs.failedDownloads == rhs.failedDownloads &&
|
||||
lhs.failedOrPendingDownloads == rhs.failedOrPendingDownloads &&
|
||||
lhs.sendFailureBadge == rhs.sendFailureBadge)
|
||||
}
|
||||
|
||||
@ -315,7 +315,7 @@ public class CVComponentState: Equatable {
|
||||
typealias UnreadIndicator = CVComponentState.UnreadIndicator
|
||||
typealias TypingIndicator = CVComponentState.TypingIndicator
|
||||
typealias ThreadDetails = CVComponentState.ThreadDetails
|
||||
typealias FailedDownloads = CVComponentState.FailedDownloads
|
||||
typealias FailedOrPendingDownloads = CVComponentState.FailedOrPendingDownloads
|
||||
typealias BottomButtons = CVComponentState.BottomButtons
|
||||
typealias SendFailureBadge = CVComponentState.SendFailureBadge
|
||||
|
||||
@ -339,7 +339,7 @@ public class CVComponentState: Equatable {
|
||||
var typingIndicator: TypingIndicator?
|
||||
var threadDetails: ThreadDetails?
|
||||
var reactions: Reactions?
|
||||
var failedDownloads: FailedDownloads?
|
||||
var failedOrPendingDownloads: FailedOrPendingDownloads?
|
||||
var sendFailureBadge: SendFailureBadge?
|
||||
|
||||
var bottomButtonsActions = [CVMessageAction]()
|
||||
@ -374,7 +374,7 @@ public class CVComponentState: Equatable {
|
||||
typingIndicator: typingIndicator,
|
||||
threadDetails: threadDetails,
|
||||
bottomButtons: bottomButtons,
|
||||
failedDownloads: failedDownloads,
|
||||
failedOrPendingDownloads: failedOrPendingDownloads,
|
||||
sendFailureBadge: sendFailureBadge)
|
||||
}
|
||||
|
||||
@ -501,8 +501,8 @@ public class CVComponentState: Equatable {
|
||||
if bottomButtons != nil {
|
||||
result.insert(.bottomButtons)
|
||||
}
|
||||
if failedDownloads != nil {
|
||||
result.insert(.failedDownloads)
|
||||
if failedOrPendingDownloads != nil {
|
||||
result.insert(.failedOrPendingDownloads)
|
||||
}
|
||||
if sendFailureBadge != nil {
|
||||
result.insert(.sendFailureBadge)
|
||||
@ -610,7 +610,7 @@ fileprivate extension CVComponentState.Builder {
|
||||
|
||||
self.senderAvatar = tryToBuildSenderAvatar()
|
||||
|
||||
self.failedDownloads = tryToBuildFailedDownloads()
|
||||
self.failedOrPendingDownloads = tryToBuildFailedOrPendingDownloads()
|
||||
|
||||
switch interaction.interactionType() {
|
||||
case .threadDetails:
|
||||
@ -668,15 +668,15 @@ fileprivate extension CVComponentState.Builder {
|
||||
return SenderAvatar(senderAvatar: avatar)
|
||||
}
|
||||
|
||||
private func tryToBuildFailedDownloads() -> FailedDownloads? {
|
||||
private func tryToBuildFailedOrPendingDownloads() -> FailedOrPendingDownloads? {
|
||||
guard let message = interaction as? TSMessage else {
|
||||
return nil
|
||||
}
|
||||
let failedAttachmentPointers = message.failedAttachments(transaction: transaction)
|
||||
guard !failedAttachmentPointers.isEmpty else {
|
||||
let attachmentPointers = message.failedOrPendingAttachments(transaction: transaction)
|
||||
guard !attachmentPointers.isEmpty else {
|
||||
return nil
|
||||
}
|
||||
return FailedDownloads(attachmentPointers: failedAttachmentPointers)
|
||||
return FailedOrPendingDownloads(attachmentPointers: attachmentPointers)
|
||||
}
|
||||
|
||||
mutating func populateAndBuild(message: TSMessage) throws -> CVComponentState {
|
||||
|
||||
@ -18,6 +18,10 @@ public class CVComponentBodyMedia: CVComponentBase, CVComponent {
|
||||
bodyMedia.mediaAlbumHasPendingAttachment
|
||||
}
|
||||
|
||||
var hasDownloadButton: Bool {
|
||||
mediaAlbumHasFailedAttachment || mediaAlbumHasPendingAttachment
|
||||
}
|
||||
|
||||
private let footerOverlay: CVComponent?
|
||||
|
||||
init(itemModel: CVItemModel, bodyMedia: CVComponentState.BodyMedia, footerOverlay: CVComponent?) {
|
||||
@ -115,6 +119,18 @@ public class CVComponentBodyMedia: CVComponentBase, CVComponent {
|
||||
let accessibilityDescription = NSLocalizedString("ACCESSIBILITY_LABEL_MEDIA",
|
||||
comment: "Accessibility label for media.")
|
||||
albumView.accessibilityLabel = accessibilityLabel(description: accessibilityDescription)
|
||||
|
||||
if hasDownloadButton {
|
||||
let iconView = UIImageView.withTemplateImageName("arrow-down-24",
|
||||
tintColor: UIColor.ows_white)
|
||||
iconView.autoSetDimensions(to: CGSize.square(16))
|
||||
let downloadButton = OWSLayerView.circleView(size: 44)
|
||||
downloadButton.backgroundColor = UIColor.ows_black
|
||||
downloadButton.addSubview(iconView)
|
||||
iconView.autoCenterInSuperview()
|
||||
componentView.rootView.addSubview(downloadButton)
|
||||
downloadButton.autoCenterInSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
public func bubbleViewPartner(componentView: CVComponentView) -> OWSBubbleViewPartner? {
|
||||
@ -174,7 +190,7 @@ public class CVComponentBodyMedia: CVComponentBase, CVComponent {
|
||||
owsFailDebug("Invalid interaction.")
|
||||
return false
|
||||
}
|
||||
if mediaAlbumHasPendingAttachment {
|
||||
if hasDownloadButton {
|
||||
componentDelegate.cvc_didTapFailedOrPendingDownloads(message)
|
||||
return true
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ public class CVComponentMessage: CVComponentBase, CVRootComponent {
|
||||
// We don't render sender avatars with a subcomponent.
|
||||
case .senderAvatar:
|
||||
return nil
|
||||
case .systemMessage, .dateHeader, .unreadIndicator, .typingIndicator, .threadDetails, .failedDownloads, .sendFailureBadge:
|
||||
case .systemMessage, .dateHeader, .unreadIndicator, .typingIndicator, .threadDetails, .failedOrPendingDownloads, .sendFailureBadge:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -887,7 +887,7 @@ public class CVComponentMessage: CVComponentBase, CVRootComponent {
|
||||
}
|
||||
|
||||
if let message = interaction as? TSMessage,
|
||||
nil != componentState.failedDownloads {
|
||||
nil != componentState.failedOrPendingDownloads {
|
||||
Logger.verbose("Retrying failed downloads.")
|
||||
componentDelegate.cvc_didTapFailedOrPendingDownloads(message)
|
||||
return true
|
||||
@ -1116,7 +1116,7 @@ public class CVComponentMessage: CVComponentBase, CVRootComponent {
|
||||
case .senderAvatar:
|
||||
owsFailDebug("Invalid component key: \(key)")
|
||||
return nil
|
||||
case .systemMessage, .dateHeader, .unreadIndicator, .typingIndicator, .threadDetails, .failedDownloads, .sendFailureBadge:
|
||||
case .systemMessage, .dateHeader, .unreadIndicator, .typingIndicator, .threadDetails, .failedOrPendingDownloads, .sendFailureBadge:
|
||||
owsFailDebug("Invalid component key: \(key)")
|
||||
return nil
|
||||
}
|
||||
@ -1154,7 +1154,7 @@ public class CVComponentMessage: CVComponentBase, CVRootComponent {
|
||||
// We don't render sender avatars with a subcomponent.
|
||||
case .senderAvatar:
|
||||
owsAssertDebug(subcomponentView == nil)
|
||||
case .systemMessage, .dateHeader, .unreadIndicator, .typingIndicator, .threadDetails, .failedDownloads, .sendFailureBadge:
|
||||
case .systemMessage, .dateHeader, .unreadIndicator, .typingIndicator, .threadDetails, .failedOrPendingDownloads, .sendFailureBadge:
|
||||
owsAssertDebug(subcomponentView == nil)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@ -31,6 +31,16 @@ open class OWSLayerView: UIView {
|
||||
super.init(coder: aDecoder)
|
||||
}
|
||||
|
||||
public static func circleView(size: CGFloat? = nil) -> OWSLayerView {
|
||||
let result = OWSLayerView(frame: .zero) { view in
|
||||
view.layer.cornerRadius = min(view.width, view.height) * 0.5
|
||||
}
|
||||
if let size = size {
|
||||
result.autoSetDimensions(to: CGSize.square(size))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public override var bounds: CGRect {
|
||||
didSet {
|
||||
if oldValue != bounds {
|
||||
|
||||
@ -517,6 +517,14 @@ public extension OWSAttachmentDownloads {
|
||||
}
|
||||
}
|
||||
|
||||
#if TESTABLE_BUILD
|
||||
struct DevFlags {
|
||||
static let forceFailure = false
|
||||
static let forceBlockedByPendingMessageRequest = false
|
||||
static let forceBlockedByAutoDownloadSettingsSettings = false
|
||||
}
|
||||
#endif
|
||||
|
||||
private func enqueueJobs(forAttachmentReferences attachmentReferences: [AttachmentReference],
|
||||
message: TSMessage?,
|
||||
downloadBehavior: AttachmentDownloadBehavior,
|
||||
@ -549,6 +557,13 @@ public extension OWSAttachmentDownloads {
|
||||
}
|
||||
|
||||
func isDownloadBlockedByPendingMessageRequest(_ attachmentPointer: TSAttachmentPointer) -> Bool {
|
||||
|
||||
#if TESTABLE_BUILD
|
||||
if DevFlags.forceBlockedByPendingMessageRequest {
|
||||
return true
|
||||
}
|
||||
#endif
|
||||
|
||||
guard attachmentPointer.isVisualMedia,
|
||||
hasPendingMessageRequest,
|
||||
let message = message,
|
||||
@ -561,6 +576,13 @@ public extension OWSAttachmentDownloads {
|
||||
|
||||
func isDownloadBlockedByAutoDownloadSettingsSettings(_ attachmentPointer: TSAttachmentPointer,
|
||||
category: AttachmentCategory) -> Bool {
|
||||
|
||||
#if TESTABLE_BUILD
|
||||
if DevFlags.forceBlockedByAutoDownloadSettingsSettings {
|
||||
return true
|
||||
}
|
||||
#endif
|
||||
|
||||
guard !downloadBehavior.bypassPendingManualDownload else {
|
||||
return false
|
||||
}
|
||||
@ -596,6 +618,19 @@ public extension OWSAttachmentDownloads {
|
||||
attachmentStreams.append(attachmentStream)
|
||||
}
|
||||
case .attachmentPointer(let attachmentPointer, let category):
|
||||
|
||||
#if TESTABLE_BUILD
|
||||
if DevFlags.forceFailure {
|
||||
Logger.info("Skipping media download for thread with pending message request.")
|
||||
Self.databaseStorage.write { transaction in
|
||||
attachmentPointer.updateAttachmentPointerState(from: .enqueued,
|
||||
to: .failed,
|
||||
transaction: transaction)
|
||||
}
|
||||
continue
|
||||
}
|
||||
#endif
|
||||
|
||||
if isDownloadBlockedByPendingMessageRequest(attachmentPointer) {
|
||||
Logger.info("Skipping media download for thread with pending message request.")
|
||||
Self.databaseStorage.write { transaction in
|
||||
|
||||
@ -16,20 +16,26 @@ public extension TSMessage {
|
||||
|
||||
func failedAttachments(transaction: SDSAnyReadTransaction) -> [TSAttachmentPointer] {
|
||||
let attachments: [TSAttachment] = allAttachments(with: transaction.unwrapGrdbRead)
|
||||
let states = Set([TSAttachmentPointerState.failed])
|
||||
return Self.onlyAttachmentPointers(attachments: attachments, withStateIn: states)
|
||||
let states: [TSAttachmentPointerState] = [.failed]
|
||||
return Self.onlyAttachmentPointers(attachments: attachments, withStateIn: Set(states))
|
||||
}
|
||||
|
||||
func failedOrPendingAttachments(transaction: SDSAnyReadTransaction) -> [TSAttachmentPointer] {
|
||||
let attachments: [TSAttachment] = allAttachments(with: transaction.unwrapGrdbRead)
|
||||
let states: [TSAttachmentPointerState] = [.failed, .pendingMessageRequest, .pendingManualDownload]
|
||||
return Self.onlyAttachmentPointers(attachments: attachments, withStateIn: Set(states))
|
||||
}
|
||||
|
||||
func failedBodyAttachments(transaction: SDSAnyReadTransaction) -> [TSAttachmentPointer] {
|
||||
let attachments: [TSAttachment] = bodyAttachments(with: transaction.unwrapGrdbRead)
|
||||
let states = Set([TSAttachmentPointerState.failed])
|
||||
return Self.onlyAttachmentPointers(attachments: attachments, withStateIn: states)
|
||||
let states: [TSAttachmentPointerState] = [.failed]
|
||||
return Self.onlyAttachmentPointers(attachments: attachments, withStateIn: Set(states))
|
||||
}
|
||||
|
||||
func pendingBodyAttachments(transaction: SDSAnyReadTransaction) -> [TSAttachmentPointer] {
|
||||
let attachments: [TSAttachment] = bodyAttachments(with: transaction.unwrapGrdbRead)
|
||||
let states = Set([TSAttachmentPointerState.pendingMessageRequest, TSAttachmentPointerState.pendingManualDownload ])
|
||||
return Self.onlyAttachmentPointers(attachments: attachments, withStateIn: states)
|
||||
let states: [TSAttachmentPointerState] = [.pendingMessageRequest, .pendingManualDownload]
|
||||
return Self.onlyAttachmentPointers(attachments: attachments, withStateIn: Set(states))
|
||||
}
|
||||
|
||||
private static func onlyAttachmentPointers(attachments: [TSAttachment],
|
||||
|
||||
Loading…
Reference in New Issue
Block a user