TM-SGNL-iOS/SignalServiceKit/Util/ImageQuality.swift
TeleMessage developers dde0620daf initial commit
2025-05-03 12:28:28 -07:00

139 lines
4.7 KiB
Swift

//
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
public enum ImageQualityLevel: UInt, Comparable {
case one = 1
case two = 2
case three = 3
public static let high: ImageQualityLevel = .three
// We calculate the "standard" media quality remotely
// based on country code. For some regions, we use
// a lower "standard" quality than others. High quality
// is always level three. If not remotely specified,
// standard uses quality level two.
public static func remoteDefault(localPhoneNumber: String?) -> ImageQualityLevel {
return RemoteConfig.current.standardMediaQualityLevel(localPhoneNumber: localPhoneNumber) ?? .two
}
public var startingTier: ImageQualityTier {
switch self {
case .one: return .four
case .two: return .five
case .three: return .seven
}
}
public var maxFileSize: UInt {
switch self {
case .one: // 1MiB
return 1024 * 1024
case .two: // 1.5MiB
return UInt(1.5 * 1024 * 1024)
case .three: // 3.0MiB
return 3 * 1024 * 1024
}
}
public var maxOriginalFileSize: UInt {
switch self {
case .one: // 200KiB
return 200 * 1024
case .two: // 300KiB
return 300 * 1024
case .three: // 400KiB
return 400 * 1024
}
}
public static var maximumForCurrentAppContext: ImageQualityLevel {
if CurrentAppContext().isMainApp {
return .three
} else {
// Outside of the main app (like in the share extension)
// we have very tight memory restrictions, and cannot
// allow sending high quality media.
return .one
}
}
private static let keyValueStore = KeyValueStore(collection: "ImageQualityLevel")
private static var userSelectedHighQualityKey: String { "defaultQuality" }
public static func resolvedQuality(tx: SDSAnyReadTransaction) -> ImageQualityLevel {
// If the max quality we allow is less than the stored preference,
// we have to restrict ourselves to the max allowed.
return min(_resolvedQuality(tx: tx), maximumForCurrentAppContext)
}
private static func _resolvedQuality(tx: SDSAnyReadTransaction) -> ImageQualityLevel {
let isHighQuality: Bool = {
// All that matters is "did the user choose high quality explicity?". If
// they didn't, we always fall back to the current server-provided value
// for standard quality. In the past, we stored low/medium values
// explicitly, but this was wrong.
guard let rawValue = keyValueStore.getUInt(userSelectedHighQualityKey, transaction: tx.asV2Read) else {
return false
}
return ImageQualityLevel(rawValue: rawValue) == .high
}()
if isHighQuality {
return .high
}
let tsAccountManager = DependenciesBridge.shared.tsAccountManager
let localPhoneNumber = tsAccountManager.localIdentifiers(tx: tx.asV2Read)?.phoneNumber
return remoteDefault(localPhoneNumber: localPhoneNumber)
}
public static func setUserSelectedHighQuality(_ isHighQuality: Bool, tx: SDSAnyWriteTransaction) {
if isHighQuality {
keyValueStore.setUInt(ImageQualityLevel.three.rawValue, key: userSelectedHighQualityKey, transaction: tx.asV2Write)
} else {
keyValueStore.removeValue(forKey: userSelectedHighQualityKey, transaction: tx.asV2Write)
}
}
public var localizedString: String {
switch self {
case .one, .two:
return OWSLocalizedString("SENT_MEDIA_QUALITY_STANDARD", comment: "String describing standard quality sent media")
case .three:
return OWSLocalizedString("SENT_MEDIA_QUALITY_HIGH", comment: "String describing high quality sent media")
}
}
public static func < (lhs: ImageQualityLevel, rhs: ImageQualityLevel) -> Bool {
return lhs.rawValue < rhs.rawValue
}
}
@objc
public enum ImageQualityTier: UInt {
case one = 1
case two = 2
case three = 3
case four = 4
case five = 5
case six = 6
case seven = 7
public var maxEdgeSize: CGFloat {
switch self {
case .one: return 512
case .two: return 768
case .three: return 1024
case .four: return 1600
case .five: return 2048
case .six: return 3072
case .seven: return 4096
}
}
public var reduced: ImageQualityTier? { .init(rawValue: rawValue - 1) }
public var increased: ImageQualityTier? { .init(rawValue: rawValue + 1) }
}