Various improvements

This commit is contained in:
Ilya Laktyushin
2023-11-25 14:10:36 +04:00
parent 3aaa0ad17b
commit 9cd6344b53
84 changed files with 3895 additions and 3057 deletions

View File

@@ -12,21 +12,104 @@ import ContextUI
import ReactionButtonListComponent
import TelegramCore
private class ButtonIcon: Equatable {
enum IconType: Equatable {
case none
case send
case apply
case removeVideoInput
case delete
case attach
case forward
case like
case repost
}
let icon: IconType
init(icon: IconType) {
self.icon = icon
}
var image: UIImage? {
switch icon {
case .delete:
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: .white)
case .attach:
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Text/IconAttachment"), color: .white)
case .forward:
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Text/IconForwardSend"), color: .white)
case .like:
return generateTintedImage(image: UIImage(bundleImageName: "Stories/InputLikeOff"), color: .white)
case .removeVideoInput:
return generateTintedImage(image: UIImage(bundleImageName: "Media Editor/RemoveRecordedVideo"), color: .white)
case .repost:
return generateTintedImage(image: UIImage(bundleImageName: "Stories/InputRepost"), color: .white)
case .apply:
return generateImage(CGSize(width: 33.0, height: 33.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(UIColor.white.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
if let image = UIImage(bundleImageName: "Media Editor/Apply"), let cgImage = image.cgImage {
context.setBlendMode(.copy)
context.setFillColor(UIColor(rgb: 0x000000, alpha: 0.35).cgColor)
context.clip(to: CGRect(origin: CGPoint(x: -4.0 + UIScreenPixel, y: -3.0 - UIScreenPixel), size: CGSize(width: 40.0, height: 40.0)), mask: cgImage)
context.fill(CGRect(origin: .zero, size: size))
}
})
case .send:
return generateImage(CGSize(width: 33.0, height: 33.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(UIColor.white.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
context.setBlendMode(.copy)
context.setStrokeColor(UIColor.clear.cgColor)
context.setLineWidth(2.0)
context.setLineCap(.round)
context.setLineJoin(.round)
context.translateBy(x: 5.45, y: 4.0)
context.saveGState()
context.translateBy(x: 4.0, y: 4.0)
let _ = try? drawSvgPath(context, path: "M1,7 L7,1 L13,7 S ")
context.restoreGState()
context.saveGState()
context.translateBy(x: 10.0, y: 4.0)
let _ = try? drawSvgPath(context, path: "M1,16 V1 S ")
context.restoreGState()
})
case .none:
return nil
}
}
static func == (lhs: ButtonIcon, rhs: ButtonIcon) -> Bool {
return lhs.icon == rhs.icon
}
}
private extension MessageInputActionButtonComponent.Mode {
var iconName: String? {
var icon: ButtonIcon? {
switch self {
case .delete:
return "Chat/Context Menu/Delete"
return ButtonIcon(icon: .delete)
case .attach:
return "Chat/Input/Text/IconAttachment"
return ButtonIcon(icon: .attach)
case .forward:
return "Chat/Input/Text/IconForwardSend"
return ButtonIcon(icon: .forward)
case .like:
return "Stories/InputLikeOff"
return ButtonIcon(icon: .like)
case .removeVideoInput:
return "Media Editor/RemoveRecordedVideo"
return ButtonIcon(icon: .removeVideoInput)
case .repost:
return "Stories/InputRepost"
return ButtonIcon(icon: .repost)
case .apply:
return ButtonIcon(icon: .apply)
case .send:
return ButtonIcon(icon: .send)
default:
return nil
}
@@ -70,6 +153,7 @@ public final class MessageInputActionButtonComponent: Component {
public let presentController: (ViewController) -> Void
public let audioRecorder: ManagedAudioRecorder?
public let videoRecordingStatus: InstantVideoControllerRecordingStatus?
public let hasShadow: Bool
public init(
mode: Mode,
@@ -86,7 +170,8 @@ public final class MessageInputActionButtonComponent: Component {
strings: PresentationStrings,
presentController: @escaping (ViewController) -> Void,
audioRecorder: ManagedAudioRecorder?,
videoRecordingStatus: InstantVideoControllerRecordingStatus?
videoRecordingStatus: InstantVideoControllerRecordingStatus?,
hasShadow: Bool = false
) {
self.mode = mode
self.storyId = storyId
@@ -103,6 +188,7 @@ public final class MessageInputActionButtonComponent: Component {
self.presentController = presentController
self.audioRecorder = audioRecorder
self.videoRecordingStatus = videoRecordingStatus
self.hasShadow = hasShadow
}
public static func ==(lhs: MessageInputActionButtonComponent, rhs: MessageInputActionButtonComponent) -> Bool {
@@ -127,6 +213,9 @@ public final class MessageInputActionButtonComponent: Component {
if lhs.videoRecordingStatus !== rhs.videoRecordingStatus {
return false
}
if lhs.hasShadow != rhs.hasShadow {
return false
}
return true
}
@@ -220,12 +309,7 @@ public final class MessageInputActionButtonComponent: Component {
}
component.action(component.mode, .up, false)
}
// public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
// let result = super.hitTest(point, with: event)
// return result
// }
func update(component: MessageInputActionButtonComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
let previousComponent = self.component
self.component = component
@@ -355,63 +439,37 @@ public final class MessageInputActionButtonComponent: Component {
microphoneAlpha = 0.4
}
if self.sendIconView.image == nil || previousComponent?.mode.iconName != component.mode.iconName {
if let iconName = component.mode.iconName {
let tintColor: UIColor = .white
self.sendIconView.image = generateTintedImage(image: UIImage(bundleImageName: iconName), color: tintColor)
} else if case .apply = component.mode {
self.sendIconView.image = generateImage(CGSize(width: 33.0, height: 33.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(UIColor.white.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
if let image = UIImage(bundleImageName: "Media Editor/Apply"), let cgImage = image.cgImage {
context.setBlendMode(.copy)
context.setFillColor(UIColor(rgb: 0x000000, alpha: 0.35).cgColor)
context.clip(to: CGRect(origin: CGPoint(x: -4.0 + UIScreenPixel, y: -3.0 - UIScreenPixel), size: CGSize(width: 40.0, height: 40.0)), mask: cgImage)
context.fill(CGRect(origin: .zero, size: size))
}
})
} else if case .none = component.mode {
self.sendIconView.image = nil
} else {
if !transition.animation.isImmediate {
if let snapshotView = self.sendIconView.snapshotView(afterScreenUpdates: false) {
snapshotView.frame = self.sendIconView.frame
self.addSubview(snapshotView)
transition.setAlpha(view: snapshotView, alpha: 0.0, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview()
})
transition.setScale(view: snapshotView, scale: 0.01)
self.sendIconView.alpha = 0.0
transition.animateAlpha(view: self.sendIconView, from: 0.0, to: sendAlpha)
transition.animateScale(view: self.sendIconView, from: 0.01, to: 1.0)
if self.sendIconView.image == nil || previousComponent?.mode.icon != component.mode.icon {
if let image = component.mode.icon?.image {
if case .send = component.mode {
if !transition.animation.isImmediate {
if let snapshotView = self.sendIconView.snapshotView(afterScreenUpdates: false) {
snapshotView.frame = self.sendIconView.frame
self.addSubview(snapshotView)
transition.setAlpha(view: snapshotView, alpha: 0.0, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview()
})
transition.setScale(view: snapshotView, scale: 0.01)
self.sendIconView.alpha = 0.0
transition.animateAlpha(view: self.sendIconView, from: 0.0, to: sendAlpha)
transition.animateScale(view: self.sendIconView, from: 0.01, to: 1.0)
}
}
}
self.sendIconView.image = generateImage(CGSize(width: 33.0, height: 33.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(UIColor.white.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
context.setBlendMode(.copy)
context.setStrokeColor(UIColor.clear.cgColor)
context.setLineWidth(2.0)
context.setLineCap(.round)
context.setLineJoin(.round)
context.translateBy(x: 5.45, y: 4.0)
context.saveGState()
context.translateBy(x: 4.0, y: 4.0)
let _ = try? drawSvgPath(context, path: "M1,7 L7,1 L13,7 S ")
context.restoreGState()
context.saveGState()
context.translateBy(x: 10.0, y: 4.0)
let _ = try? drawSvgPath(context, path: "M1,16 V1 S ")
context.restoreGState()
})
self.sendIconView.image = image
} else {
self.sendIconView.image = nil
}
if case .removeVideoInput = component.mode, component.hasShadow {
self.sendIconView.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
self.sendIconView.layer.shadowRadius = 2.0
self.sendIconView.layer.shadowColor = UIColor.black.cgColor
self.sendIconView.layer.shadowOpacity = 0.35
} else {
self.sendIconView.layer.shadowColor = UIColor.clear.cgColor
self.sendIconView.layer.shadowOpacity = 0.0
}
}
@@ -540,6 +598,8 @@ public final class MessageInputActionButtonComponent: Component {
}
if let micButton = self.micButton {
micButton.hasShadow = component.hasShadow
if themeUpdated {
micButton.updateTheme(theme: defaultDarkPresentationTheme)
}