mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-02 00:17:02 +00:00
Story weather display
This commit is contained in:
parent
a6c7e92d6f
commit
f4cc9d1aad
@ -8,6 +8,7 @@ import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
import StickerResources
|
||||
import MediaEditor
|
||||
import TelegramStringFormatting
|
||||
|
||||
private func generateIcon(style: DrawingWeatherEntity.Style) -> UIImage? {
|
||||
guard let image = UIImage(bundleImageName: "Chat/Attach Menu/Location") else {
|
||||
@ -50,7 +51,6 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega
|
||||
}
|
||||
|
||||
let backgroundView: UIView
|
||||
let blurredBackgroundView: BlurredBackgroundView
|
||||
|
||||
let textView: DrawingTextView
|
||||
let iconView: UIImageView
|
||||
@ -61,13 +61,14 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega
|
||||
private let stickerFetchedDisposable = MetaDisposable()
|
||||
private let cachedDisposable = MetaDisposable()
|
||||
|
||||
let temperature: String
|
||||
|
||||
init(context: AccountContext, entity: DrawingWeatherEntity) {
|
||||
self.temperature = stringForTemperature(entity.temperature)
|
||||
|
||||
self.backgroundView = UIView()
|
||||
self.backgroundView.clipsToBounds = true
|
||||
|
||||
self.blurredBackgroundView = BlurredBackgroundView(color: UIColor(white: 0.0, alpha: 0.25), enableBlur: true)
|
||||
self.blurredBackgroundView.clipsToBounds = true
|
||||
|
||||
self.textView = DrawingTextView(frame: .zero)
|
||||
self.textView.clipsToBounds = false
|
||||
|
||||
@ -95,7 +96,6 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega
|
||||
|
||||
self.textView.delegate = self
|
||||
self.addSubview(self.backgroundView)
|
||||
self.addSubview(self.blurredBackgroundView)
|
||||
self.addSubview(self.textView)
|
||||
self.addSubview(self.iconView)
|
||||
|
||||
@ -138,7 +138,7 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega
|
||||
self.imageNode.frame = self.iconView.frame.offsetBy(dx: 0.0, dy: 2.0)
|
||||
|
||||
if let animationNode = self.animationNode {
|
||||
animationNode.frame = self.iconView.frame.offsetBy(dx: 0.0, dy: 2.0)
|
||||
animationNode.frame = self.iconView.frame
|
||||
animationNode.updateLayout(size: self.iconView.frame.size)
|
||||
}
|
||||
|
||||
@ -147,8 +147,6 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega
|
||||
|
||||
self.textView.frame = CGRect(origin: CGPoint(x: self.bounds.width - self.textSize.width - 6.0, y: floorToScreenPixels((self.bounds.height - self.textSize.height) / 2.0)), size: self.textSize)
|
||||
self.backgroundView.frame = self.bounds
|
||||
self.blurredBackgroundView.frame = self.bounds
|
||||
self.blurredBackgroundView.update(size: self.bounds.size, transition: .immediate)
|
||||
}
|
||||
|
||||
override func selectedTapAction() -> Bool {
|
||||
@ -161,16 +159,6 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega
|
||||
case .white:
|
||||
updatedStyle = .black
|
||||
case .black:
|
||||
updatedStyle = .transparent
|
||||
case .transparent:
|
||||
if self.weatherEntity.hasCustomColor {
|
||||
updatedStyle = .custom
|
||||
} else {
|
||||
updatedStyle = .white
|
||||
}
|
||||
case .custom:
|
||||
updatedStyle = .white
|
||||
case .blur:
|
||||
updatedStyle = .white
|
||||
}
|
||||
self.weatherEntity.style = updatedStyle
|
||||
@ -182,7 +170,7 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega
|
||||
|
||||
private var displayFontSize: CGFloat {
|
||||
var textFontSize: CGFloat = 0.07
|
||||
let textLength = self.weatherEntity.temperature.count
|
||||
let textLength = self.temperature.count
|
||||
if textLength > 10 {
|
||||
textFontSize = max(0.01, 0.07 - CGFloat(textLength - 10) / 100.0)
|
||||
}
|
||||
@ -194,7 +182,7 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega
|
||||
}
|
||||
|
||||
private func updateText() {
|
||||
let text = NSMutableAttributedString(string: self.weatherEntity.temperature.uppercased())
|
||||
let text = NSMutableAttributedString(string: self.temperature.uppercased())
|
||||
let range = NSMakeRange(0, text.length)
|
||||
let fontSize = self.displayFontSize
|
||||
|
||||
@ -213,15 +201,8 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega
|
||||
switch self.weatherEntity.style {
|
||||
case .white:
|
||||
textColor = .black
|
||||
case .black, .transparent, .blur:
|
||||
case .black:
|
||||
textColor = .white
|
||||
case .custom:
|
||||
let color = self.weatherEntity.color.toUIColor()
|
||||
if color.lightness > 0.705 {
|
||||
textColor = .black
|
||||
} else {
|
||||
textColor = .white
|
||||
}
|
||||
}
|
||||
|
||||
text.addAttribute(.foregroundColor, value: textColor, range: range)
|
||||
@ -241,34 +222,10 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega
|
||||
self.textView.textColor = .black
|
||||
self.backgroundView.backgroundColor = .white
|
||||
self.backgroundView.isHidden = false
|
||||
self.blurredBackgroundView.isHidden = true
|
||||
case .black:
|
||||
self.textView.textColor = .white
|
||||
self.backgroundView.backgroundColor = .black
|
||||
self.backgroundView.isHidden = false
|
||||
self.blurredBackgroundView.isHidden = true
|
||||
case .transparent:
|
||||
self.textView.textColor = .white
|
||||
self.backgroundView.backgroundColor = UIColor(rgb: 0x000000, alpha: 0.2)
|
||||
self.backgroundView.isHidden = false
|
||||
self.blurredBackgroundView.isHidden = true
|
||||
case .custom:
|
||||
let color = self.weatherEntity.color.toUIColor()
|
||||
let textColor: UIColor
|
||||
if color.lightness > 0.705 {
|
||||
textColor = .black
|
||||
} else {
|
||||
textColor = .white
|
||||
}
|
||||
self.textView.textColor = textColor
|
||||
self.backgroundView.backgroundColor = color
|
||||
self.backgroundView.isHidden = false
|
||||
self.blurredBackgroundView.isHidden = true
|
||||
case .blur:
|
||||
self.textView.textColor = .white
|
||||
self.backgroundView.isHidden = true
|
||||
self.backgroundView.backgroundColor = UIColor(rgb: 0xffffff)
|
||||
self.blurredBackgroundView.isHidden = false
|
||||
}
|
||||
self.textView.textAlignment = .left
|
||||
|
||||
@ -282,10 +239,8 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega
|
||||
}
|
||||
|
||||
self.backgroundView.layer.cornerRadius = self.textSize.height * 0.2
|
||||
self.blurredBackgroundView.layer.cornerRadius = self.backgroundView.layer.cornerRadius
|
||||
if #available(iOS 13.0, *) {
|
||||
self.backgroundView.layer.cornerCurve = .continuous
|
||||
self.blurredBackgroundView.layer.cornerCurve = .continuous
|
||||
}
|
||||
|
||||
super.update(animated: animated)
|
||||
|
@ -249,7 +249,7 @@ public enum MediaArea: Codable, Equatable {
|
||||
try container.encode(coordinates, forKey: .coordinates)
|
||||
try container.encode(url, forKey: .value)
|
||||
case let .weather(coordinates, emoji, temperature, flags):
|
||||
try container.encode(MediaAreaType.link.rawValue, forKey: .type)
|
||||
try container.encode(MediaAreaType.weather.rawValue, forKey: .type)
|
||||
try container.encode(coordinates, forKey: .coordinates)
|
||||
try container.encode(emoji, forKey: .value)
|
||||
try container.encode(temperature, forKey: .temperature)
|
||||
|
@ -120,7 +120,7 @@ public enum CodableDrawingEntity: Equatable {
|
||||
rotation = entity.rotation
|
||||
scale = entity.scale
|
||||
if let size {
|
||||
cornerRadius = 10.0 / (size.width * entity.scale)
|
||||
cornerRadius = (size.height * 0.17) / size.width
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
@ -191,6 +191,17 @@ public enum CodableDrawingEntity: Equatable {
|
||||
coordinates: coordinates,
|
||||
url: url
|
||||
)
|
||||
case let .weather(entity):
|
||||
var flags: MediaArea.WeatherFlags = []
|
||||
if entity.style == .black {
|
||||
flags.insert(.isDark)
|
||||
}
|
||||
return .weather(
|
||||
coordinates: coordinates,
|
||||
emoji: entity.emoji,
|
||||
temperature: entity.temperature,
|
||||
flags: flags
|
||||
)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ public final class DrawingWeatherEntity: DrawingEntity, Codable {
|
||||
case uuid
|
||||
case style
|
||||
case color
|
||||
case hasCustomColor
|
||||
case emoji
|
||||
case temperature
|
||||
case icon
|
||||
case referenceDrawingSize
|
||||
@ -25,9 +25,6 @@ public final class DrawingWeatherEntity: DrawingEntity, Codable {
|
||||
public enum Style: Codable, Equatable {
|
||||
case white
|
||||
case black
|
||||
case transparent
|
||||
case custom
|
||||
case blur
|
||||
}
|
||||
|
||||
public var uuid: UUID
|
||||
@ -37,20 +34,11 @@ public final class DrawingWeatherEntity: DrawingEntity, Codable {
|
||||
|
||||
|
||||
public var style: Style
|
||||
public var temperature: String
|
||||
public var icon: TelegramMediaFile?
|
||||
public var color: DrawingColor = DrawingColor(color: .white) {
|
||||
didSet {
|
||||
if self.color.toUIColor().argb == UIColor.white.argb {
|
||||
self.style = .white
|
||||
self.hasCustomColor = false
|
||||
} else {
|
||||
self.style = .custom
|
||||
self.hasCustomColor = true
|
||||
}
|
||||
}
|
||||
}
|
||||
public var hasCustomColor = false
|
||||
public var emoji: String
|
||||
public var temperature: Double
|
||||
|
||||
public var color: DrawingColor = DrawingColor.clear
|
||||
public var lineWidth: CGFloat = 0.0
|
||||
|
||||
public var referenceDrawingSize: CGSize
|
||||
@ -74,13 +62,14 @@ public final class DrawingWeatherEntity: DrawingEntity, Codable {
|
||||
return false
|
||||
}
|
||||
|
||||
public init(temperature: String, style: Style, icon: TelegramMediaFile?) {
|
||||
public init(emoji: String, emojiFile: TelegramMediaFile?, temperature: Double, style: Style) {
|
||||
self.uuid = UUID()
|
||||
|
||||
self.emoji = emoji
|
||||
self.icon = emojiFile
|
||||
self.temperature = temperature
|
||||
self.style = style
|
||||
self.icon = icon
|
||||
|
||||
|
||||
self.referenceDrawingSize = .zero
|
||||
self.position = .zero
|
||||
self.width = 100.0
|
||||
@ -91,10 +80,9 @@ public final class DrawingWeatherEntity: DrawingEntity, Codable {
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
self.uuid = try container.decode(UUID.self, forKey: .uuid)
|
||||
self.temperature = try container.decode(String.self, forKey: .temperature)
|
||||
self.emoji = try container.decode(String.self, forKey: .emoji)
|
||||
self.temperature = try container.decode(Double.self, forKey: .temperature)
|
||||
self.style = try container.decode(Style.self, forKey: .style)
|
||||
self.color = try container.decodeIfPresent(DrawingColor.self, forKey: .color) ?? DrawingColor(color: .white)
|
||||
self.hasCustomColor = try container.decodeIfPresent(Bool.self, forKey: .hasCustomColor) ?? false
|
||||
|
||||
if let iconData = try container.decodeIfPresent(Data.self, forKey: .icon) {
|
||||
self.icon = PostboxDecoder(buffer: MemoryBuffer(data: iconData)).decodeRootObject() as? TelegramMediaFile
|
||||
@ -113,10 +101,9 @@ public final class DrawingWeatherEntity: DrawingEntity, Codable {
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(self.uuid, forKey: .uuid)
|
||||
try container.encode(self.emoji, forKey: .emoji)
|
||||
try container.encode(self.temperature, forKey: .temperature)
|
||||
try container.encode(self.style, forKey: .style)
|
||||
try container.encode(self.color, forKey: .color)
|
||||
try container.encode(self.hasCustomColor, forKey: .hasCustomColor)
|
||||
|
||||
var encoder = PostboxEncoder()
|
||||
if let icon = self.icon {
|
||||
@ -137,7 +124,7 @@ public final class DrawingWeatherEntity: DrawingEntity, Codable {
|
||||
}
|
||||
|
||||
public func duplicate(copy: Bool) -> DrawingEntity {
|
||||
let newEntity = DrawingWeatherEntity(temperature: self.temperature, style: self.style, icon: self.icon)
|
||||
let newEntity = DrawingWeatherEntity(emoji: self.emoji, emojiFile: self.icon, temperature: self.temperature, style: self.style)
|
||||
if copy {
|
||||
newEntity.uuid = self.uuid
|
||||
}
|
||||
@ -156,6 +143,9 @@ public final class DrawingWeatherEntity: DrawingEntity, Codable {
|
||||
if self.uuid != other.uuid {
|
||||
return false
|
||||
}
|
||||
if self.emoji != other.emoji {
|
||||
return false
|
||||
}
|
||||
if self.temperature != other.temperature {
|
||||
return false
|
||||
}
|
||||
|
@ -70,7 +70,9 @@ private func prerenderTextTransformations(entity: DrawingEntity, image: UIImage,
|
||||
}
|
||||
|
||||
func composerEntitiesForDrawingEntity(postbox: Postbox, textScale: CGFloat, entity: DrawingEntity, colorSpace: CGColorSpace, tintColor: UIColor? = nil) -> [MediaEditorComposerEntity] {
|
||||
if let entity = entity as? DrawingStickerEntity {
|
||||
if entity is DrawingWeatherEntity {
|
||||
return []
|
||||
} else if let entity = entity as? DrawingStickerEntity {
|
||||
if case let .file(_, type) = entity.content, case .reaction = type {
|
||||
return []
|
||||
} else {
|
||||
@ -126,10 +128,10 @@ func composerEntitiesForDrawingEntity(postbox: Postbox, textScale: CGFloat, enti
|
||||
return entities
|
||||
} else if let entity = entity as? DrawingLocationEntity {
|
||||
return [prerenderTextTransformations(entity: entity, image: renderImage, textScale: textScale, colorSpace: colorSpace)]
|
||||
} else if let entity = entity as? DrawingWeatherEntity {
|
||||
return [prerenderTextTransformations(entity: entity, image: renderImage, textScale: textScale, colorSpace: colorSpace)]
|
||||
} else if let entity = entity as? DrawingLinkEntity {
|
||||
return [prerenderTextTransformations(entity: entity, image: renderImage, textScale: textScale, colorSpace: colorSpace)]
|
||||
} else if let entity = entity as? DrawingWeatherEntity {
|
||||
return [prerenderTextTransformations(entity: entity, image: renderImage, textScale: textScale, colorSpace: colorSpace)]
|
||||
}
|
||||
}
|
||||
return []
|
||||
|
@ -4583,11 +4583,24 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
}
|
||||
|
||||
func addWeather(_ weather: StickerPickerScreen.Weather.LoadedWeather) {
|
||||
let maxWeatherCount = 3
|
||||
var currentWeatherCount = 0
|
||||
self.entitiesView.eachView { entityView in
|
||||
if entityView.entity is DrawingWeatherEntity {
|
||||
currentWeatherCount += 1
|
||||
}
|
||||
}
|
||||
if currentWeatherCount >= maxWeatherCount {
|
||||
self.controller?.hapticFeedback.error()
|
||||
return
|
||||
}
|
||||
|
||||
self.interaction?.insertEntity(
|
||||
DrawingWeatherEntity(
|
||||
temperature: stringForTemperature(weather.temperature),
|
||||
style: .white,
|
||||
icon: weather.emojiFile
|
||||
emoji: weather.emoji,
|
||||
emojiFile: weather.emojiFile,
|
||||
temperature: weather.temperature,
|
||||
style: .white
|
||||
),
|
||||
scale: nil,
|
||||
position: nil
|
||||
@ -6061,7 +6074,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
})
|
||||
self.present(controller, in: .window(.root))
|
||||
}
|
||||
|
||||
|
||||
func maybePresentDiscardAlert() {
|
||||
self.hapticFeedback.impact(.light)
|
||||
if !self.isEligibleForDraft() {
|
||||
|
@ -58,18 +58,14 @@ func getWeather(context: AccountContext) -> Signal<StickerPickerScreen.Weather,
|
||||
return getWeatherData(context: context, location: location)
|
||||
|> mapToSignal { weather in
|
||||
if let weather {
|
||||
return context.animatedEmojiStickers
|
||||
|> take(1)
|
||||
|> mapToSignal { result in
|
||||
if let match = result[weather.emoji.strippedEmoji]?.first {
|
||||
return .single(.loaded(StickerPickerScreen.Weather.LoadedWeather(
|
||||
emoji: weather.emoji.strippedEmoji,
|
||||
emojiFile: match.file,
|
||||
temperature: weather.temperature
|
||||
)))
|
||||
} else {
|
||||
return .single(.none)
|
||||
}
|
||||
if let match = context.animatedEmojiStickersValue[weather.emoji.strippedEmoji]?.first {
|
||||
return .single(.loaded(StickerPickerScreen.Weather.LoadedWeather(
|
||||
emoji: weather.emoji.strippedEmoji,
|
||||
emojiFile: match.file,
|
||||
temperature: weather.temperature
|
||||
)))
|
||||
} else {
|
||||
return .single(.none)
|
||||
}
|
||||
} else {
|
||||
return .single(.none)
|
||||
|
@ -20,6 +20,7 @@ import LottieComponent
|
||||
import LottieComponentResourceContent
|
||||
import StickerResources
|
||||
import AnimationCache
|
||||
import TelegramStringFormatting
|
||||
|
||||
private let shadowImage: UIImage = {
|
||||
return UIImage(bundleImageName: "Stories/ReactionShadow")!
|
||||
@ -224,12 +225,16 @@ public func storyPreviewWithAddedReactions(
|
||||
}
|
||||
}
|
||||
|
||||
private protocol ItemView: UIView {
|
||||
|
||||
}
|
||||
|
||||
final class StoryItemOverlaysView: UIView {
|
||||
static let counterFont: UIFont = {
|
||||
return Font.with(size: 17.0, design: .camera, weight: .semibold, traits: .monospacedNumbers)
|
||||
}()
|
||||
|
||||
private final class ItemView: HighlightTrackingButton {
|
||||
private final class ReactionView: HighlightTrackingButton, ItemView {
|
||||
private let shadowView: UIImageView
|
||||
private let coverView: UIImageView
|
||||
|
||||
@ -524,6 +529,120 @@ final class StoryItemOverlaysView: UIView {
|
||||
}
|
||||
}
|
||||
|
||||
private final class WeatherView: UIView, ItemView {
|
||||
private let backgroundView = UIView()
|
||||
private let directStickerView = ComponentView<Empty>()
|
||||
private let text = ComponentView<Empty>()
|
||||
|
||||
private var file: TelegramMediaFile?
|
||||
private var textFont: UIFont?
|
||||
|
||||
private var customEmojiLoadDisposable: Disposable?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
self.backgroundView.clipsToBounds = true
|
||||
if #available(iOS 13.0, *) {
|
||||
self.backgroundView.layer.cornerCurve = .continuous
|
||||
}
|
||||
self.addSubview(self.backgroundView)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.customEmojiLoadDisposable?.dispose()
|
||||
}
|
||||
|
||||
func update(
|
||||
context: AccountContext,
|
||||
emoji: String,
|
||||
emojiFile: TelegramMediaFile?,
|
||||
temperature: Double,
|
||||
flags: MediaArea.WeatherFlags,
|
||||
synchronous: Bool,
|
||||
size: CGSize,
|
||||
cornerRadius: CGFloat,
|
||||
isActive: Bool
|
||||
) {
|
||||
self.backgroundView.backgroundColor = flags.contains(.isDark) ? UIColor(rgb: 0x000000) : UIColor(rgb: 0xffffff)
|
||||
self.backgroundView.frame = CGRect(origin: .zero, size: size)
|
||||
self.backgroundView.layer.cornerRadius = cornerRadius
|
||||
|
||||
let itemSize = CGSize(width: floor(size.height * 0.71), height: floor(size.height * 0.71))
|
||||
|
||||
if self.file?.fileId != emojiFile?.fileId, let file = emojiFile {
|
||||
self.file = file
|
||||
|
||||
self.customEmojiLoadDisposable?.dispose()
|
||||
self.customEmojiLoadDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .other, userContentType: .sticker, reference: .standalone(resource: file.resource)).start()
|
||||
|
||||
let placeholderColor = flags.contains(.isDark) ? UIColor(white: 1.0, alpha: 0.1) : UIColor(white: 0.0, alpha: 0.1)
|
||||
let _ = self.directStickerView.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(LottieComponent(
|
||||
content: LottieComponent.ResourceContent(context: context, file: file, attemptSynchronously: synchronous, providesPlaceholder: true),
|
||||
placeholderColor: placeholderColor,
|
||||
renderingScale: 2.0,
|
||||
loop: true
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: itemSize
|
||||
)
|
||||
}
|
||||
|
||||
let textFont: UIFont
|
||||
if let current = self.textFont {
|
||||
textFont = current
|
||||
} else {
|
||||
textFont = Font.with(size: floorToScreenPixels(size.height * 0.69), design: .camera, weight: .semibold, traits: .monospacedNumbers)
|
||||
self.textFont = textFont
|
||||
}
|
||||
|
||||
let string = NSMutableAttributedString(
|
||||
string: stringForTemperature(temperature),
|
||||
font: textFont,
|
||||
textColor: flags.contains(.isDark) ? UIColor(rgb: 0xffffff) : UIColor(rgb: 0x000000)
|
||||
)
|
||||
string.addAttribute(.kern, value: -(size.height / 38.0) as NSNumber, range: NSMakeRange(0, string.length))
|
||||
|
||||
let textSize = self.text.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(
|
||||
MultilineTextComponent(text: .plain(string))
|
||||
),
|
||||
environment: {},
|
||||
containerSize: size
|
||||
)
|
||||
|
||||
if let view = self.text.view {
|
||||
if view.superview == nil {
|
||||
self.addSubview(view)
|
||||
}
|
||||
let textFrame = CGRect(origin: CGPoint(x: size.width - textSize.width - size.height * 0.2, y: floorToScreenPixels((size.height - textSize.height) / 2.0)), size: textSize)
|
||||
let textTransition = ComponentTransition.immediate
|
||||
textTransition.setFrame(view: view, frame: textFrame)
|
||||
}
|
||||
|
||||
if let directStickerView = self.directStickerView.view as? LottieComponent.View {
|
||||
if directStickerView.superview == nil {
|
||||
self.addSubview(directStickerView)
|
||||
}
|
||||
|
||||
let stickerFrame = itemSize.centered(around: CGPoint(x: size.height * 0.5 + size.height * 0.058, y: size.height * 0.5))
|
||||
|
||||
let stickerTransition = ComponentTransition.immediate
|
||||
stickerTransition.setPosition(view: directStickerView, position: stickerFrame.center)
|
||||
stickerTransition.setBounds(view: directStickerView, bounds: CGRect(origin: CGPoint(), size: stickerFrame.size))
|
||||
|
||||
directStickerView.externalShouldPlay = isActive
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var itemViews: [Int: ItemView] = [:]
|
||||
var activate: ((UIView, MessageReaction.Reaction) -> Void)?
|
||||
var requestUpdate: (() -> Void)?
|
||||
@ -561,25 +680,37 @@ final class StoryItemOverlaysView: UIView {
|
||||
isActive: Bool,
|
||||
transition: ComponentTransition
|
||||
) {
|
||||
func getFrameAndRotation(coordinates: MediaArea.Coordinates, scale: CGFloat = 1.0) -> (frame: CGRect, rotation: CGFloat, cornerRadius: CGFloat)? {
|
||||
let referenceSize = size
|
||||
var areaSize = CGSize(width: coordinates.width / 100.0 * referenceSize.width, height: coordinates.height / 100.0 * referenceSize.height)
|
||||
areaSize.width *= scale
|
||||
areaSize.height *= scale
|
||||
let targetFrame = CGRect(x: coordinates.x / 100.0 * referenceSize.width - areaSize.width * 0.5, y: coordinates.y / 100.0 * referenceSize.height - areaSize.height * 0.5, width: areaSize.width, height: areaSize.height)
|
||||
if targetFrame.width < 5.0 || targetFrame.height < 5.0 {
|
||||
return nil
|
||||
}
|
||||
var cornerRadius: CGFloat = 0.0
|
||||
if let radius = coordinates.cornerRadius {
|
||||
cornerRadius = radius / 100.0 * areaSize.width
|
||||
}
|
||||
|
||||
return (targetFrame, coordinates.rotation * (CGFloat.pi / 180.0), cornerRadius)
|
||||
}
|
||||
|
||||
var nextId = 0
|
||||
for mediaArea in story.mediaAreas {
|
||||
switch mediaArea {
|
||||
case let .reaction(coordinates, reaction, flags):
|
||||
let referenceSize = size
|
||||
var areaSize = CGSize(width: coordinates.width / 100.0 * referenceSize.width, height: coordinates.height / 100.0 * referenceSize.height)
|
||||
areaSize.width *= 0.97
|
||||
areaSize.height *= 0.97
|
||||
let targetFrame = CGRect(x: coordinates.x / 100.0 * referenceSize.width - areaSize.width * 0.5, y: coordinates.y / 100.0 * referenceSize.height - areaSize.height * 0.5, width: areaSize.width, height: areaSize.height)
|
||||
if targetFrame.width < 5.0 || targetFrame.height < 5.0 {
|
||||
guard let (itemFrame, itemRotation, _) = getFrameAndRotation(coordinates: coordinates, scale: 0.97) else {
|
||||
continue
|
||||
}
|
||||
|
||||
let itemView: ItemView
|
||||
let itemView: ReactionView
|
||||
let itemId = nextId
|
||||
if let current = self.itemViews[itemId] {
|
||||
if let current = self.itemViews[itemId] as? ReactionView {
|
||||
itemView = current
|
||||
} else {
|
||||
itemView = ItemView(frame: CGRect())
|
||||
itemView = ReactionView(frame: CGRect())
|
||||
itemView.activate = { [weak self] view, reaction in
|
||||
self?.activate?(view, reaction)
|
||||
}
|
||||
@ -590,9 +721,9 @@ final class StoryItemOverlaysView: UIView {
|
||||
self.addSubview(itemView)
|
||||
}
|
||||
|
||||
transition.setPosition(view: itemView, position: targetFrame.center)
|
||||
transition.setBounds(view: itemView, bounds: CGRect(origin: CGPoint(), size: targetFrame.size))
|
||||
transition.setTransform(view: itemView, transform: CATransform3DMakeRotation(coordinates.rotation * (CGFloat.pi / 180.0), 0.0, 0.0, 1.0))
|
||||
transition.setPosition(view: itemView, position: itemFrame.center)
|
||||
transition.setBounds(view: itemView, bounds: CGRect(origin: CGPoint(), size: itemFrame.size))
|
||||
transition.setTransform(view: itemView, transform: CATransform3DMakeRotation(itemRotation, 0.0, 0.0, 1.0))
|
||||
|
||||
var counter = 0
|
||||
if let reactionData = story.views?.reactions.first(where: { $0.value == reaction }) {
|
||||
@ -607,7 +738,39 @@ final class StoryItemOverlaysView: UIView {
|
||||
availableReactions: availableReactions,
|
||||
entityFiles: entityFiles,
|
||||
synchronous: attemptSynchronous,
|
||||
size: targetFrame.size,
|
||||
size: itemFrame.size,
|
||||
isActive: isActive
|
||||
)
|
||||
|
||||
nextId += 1
|
||||
case let .weather(coordinates, emoji, temperature, flags):
|
||||
guard let (itemFrame, itemRotation, cornerRadius) = getFrameAndRotation(coordinates: coordinates) else {
|
||||
continue
|
||||
}
|
||||
|
||||
let itemView: WeatherView
|
||||
let itemId = nextId
|
||||
if let current = self.itemViews[itemId] as? WeatherView {
|
||||
itemView = current
|
||||
} else {
|
||||
itemView = WeatherView(frame: CGRect())
|
||||
self.itemViews[itemId] = itemView
|
||||
self.addSubview(itemView)
|
||||
}
|
||||
|
||||
transition.setPosition(view: itemView, position: itemFrame.center)
|
||||
transition.setBounds(view: itemView, bounds: CGRect(origin: CGPoint(), size: itemFrame.size))
|
||||
transition.setTransform(view: itemView, transform: CATransform3DMakeRotation(itemRotation, 0.0, 0.0, 1.0))
|
||||
|
||||
itemView.update(
|
||||
context: context,
|
||||
emoji: emoji,
|
||||
emojiFile: context.animatedEmojiStickersValue[emoji]?.first?.file,
|
||||
temperature: temperature,
|
||||
flags: flags,
|
||||
synchronous: attemptSynchronous,
|
||||
size: itemFrame.size,
|
||||
cornerRadius: cornerRadius,
|
||||
isActive: isActive
|
||||
)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user