Final tweaking

This commit is contained in:
Ilya Yelagov 2022-11-27 23:10:23 +04:00
parent bfd81f6a0b
commit 8b1a78aa9d
24 changed files with 248 additions and 62 deletions

View File

@ -477,6 +477,35 @@ public final class StandaloneShimmerEffect {
self.updateLayer()
}
public func testUpdate(background: UIColor, foreground: UIColor) {
if self.background == background && self.foreground == foreground {
return
}
self.background = background
self.foreground = foreground
self.image = generateImage(CGSize(width: 320, height: 1), opaque: false, scale: 1.0, rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(background.cgColor)
context.fill(CGRect(origin: CGPoint(), size: size))
context.clip(to: CGRect(origin: CGPoint(), size: size))
let transparentColor = foreground.withAlphaComponent(0.0).cgColor
let peakColor = foreground.cgColor
var locations: [CGFloat] = [0.0, 0.44, 0.55, 1.0]
let colors: [CGColor] = [transparentColor, peakColor, peakColor, transparentColor]
let colorSpace = CGColorSpaceCreateDeviceRGB()
guard let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations) else { return }
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: 0.3), options: CGGradientDrawingOptions())
})
self.testUpdateLayer()
}
public func updateLayer() {
guard let layer = self.layer, let image = self.image else {
return
@ -495,4 +524,23 @@ public final class StandaloneShimmerEffect {
layer.add(animation, forKey: "shimmer")
}
}
private func testUpdateLayer() {
guard let layer = self.layer, let image = self.image else {
return
}
layer.contents = image.cgImage
if layer.animation(forKey: "shimmer") == nil {
let animation = CABasicAnimation(keyPath: "contentsRect.origin.x")
animation.fromValue = 1.0 as NSNumber
animation.toValue = -1.0 as NSNumber
animation.isAdditive = true
animation.repeatCount = .infinity
animation.duration = 0.8
animation.beginTime = layer.convertTime(1.0, from: nil)
layer.add(animation, forKey: "shimmer")
}
}
}

View File

@ -785,12 +785,16 @@ public final class _MediaStreamComponent: CombinedComponent {
})
self.connectionDisposable = call.state.start(next: { [weak self] state in
let prev = self?.videoStalled
switch state.networkState {
case .connected:
self?.videoStalled = false
default:
self?.videoStalled = true
}
if prev != self?.videoStalled {
self?.updated(transition: .immediate)
}
})
let callPeer = call.accountContext.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: call.peerId))
@ -804,16 +808,14 @@ public final class _MediaStreamComponent: CombinedComponent {
var updated = false
// TODO: remove debug
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { _ in
strongSelf.infoThrottler.publish(/*members.totalCount*/Int.random(in: 0..<10000000)) { [weak strongSelf] latestCount in
strongSelf.infoThrottler.publish(members.totalCount/*Int.random(in: 0..<10000000)*/) { [weak strongSelf] latestCount in
guard let strongSelf = strongSelf else { return }
var updated = false
print(members)
let originInfo = OriginInfo(title: callPeer.debugDisplayTitle, memberCount: latestCount)
if strongSelf.originInfo != originInfo {
strongSelf.originInfo = originInfo
updated = true
}
//
}
if updated {
strongSelf.updated(transition: .immediate)
}
@ -1021,7 +1023,7 @@ public final class _MediaStreamComponent: CombinedComponent {
size: CGSize(width: 32.0, height: 32.0)
))),
AnyComponentWithIdentity(id: "a", component: AnyComponent(BundleIconComponent(
name: "Media Gallery/PictureInPictureButton",
name: "Call/pip",
tintColor: .white
)))
]
@ -1383,17 +1385,16 @@ public final class _MediaStreamComponent: CombinedComponent {
).minSize(CGSize(width: 65, height: 80))),
// TODO: disable button instead of hiding
rightItem: AnyComponent(Button(
content: AnyComponent(RoundGradientButtonComponent(// BundleIconComponent(
content: AnyComponent(RoundGradientButtonComponent(
gradientColors: [UIColor(red: 0.44, green: 0.18, blue: 0.22, alpha: 1).cgColor, UIColor(red: 0.44, green: 0.18, blue: 0.22, alpha: 1).cgColor],
image: generateImage(CGSize(width: 44.0, height: 44), opaque: false, rotatedContext: { size, context in
context.translateBy(x: size.width / 2, y: size.height / 2)
context.scaleBy(x: 0.4, y: 0.4)
context.translateBy(x: -size.width / 2, y: -size.height / 2)
// context.translateBy(x: size.width * 0.66, y: size.height * 0.66)
let imageColor = UIColor.white
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
let lineWidth: CGFloat = size.width / 6
let lineWidth: CGFloat = size.width / 7
context.setLineWidth(lineWidth - UIScreenPixel)
context.setLineCap(.round)
context.setStrokeColor(imageColor.cgColor)
@ -1406,10 +1407,8 @@ public final class _MediaStreamComponent: CombinedComponent {
context.addLine(to: CGPoint(x: lineWidth / 2 + UIScreenPixel, y: size.height - lineWidth / 2 - UIScreenPixel))
context.strokePath()
}),
title:
// TODO: localize
"leave"
)),
title: "leave"
)),
action: { [weak call] in
let _ = call?.leave(terminateIfPossible: false)
}
@ -1423,34 +1422,34 @@ public final class _MediaStreamComponent: CombinedComponent {
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
context.setLineWidth(2.7 - UIScreenPixel)
context.setLineWidth(2.4 - UIScreenPixel)
context.setLineCap(.round)
context.setStrokeColor(imageColor.cgColor)
// context.setLineJoin(.round)
let lineSide = size.width / 5
let centerOffset = size.width / 16
context.move(to: CGPoint(x: size.width / 2 + lineSide, y: size.height / 2 - centerOffset))
let centerOffset = size.width / 20
context.move(to: CGPoint(x: size.width / 2 + lineSide, y: size.height / 2 - centerOffset / 2))
context.addLine(to: CGPoint(x: size.width / 2 + lineSide, y: size.height / 2 - lineSide))
context.addLine(to: CGPoint(x: size.width / 2 + centerOffset, y: size.height / 2 - lineSide))
context.addLine(to: CGPoint(x: size.width / 2 + centerOffset / 2, y: size.height / 2 - lineSide))
context.move(to: CGPoint(x: size.width / 2 + lineSide, y: size.height / 2 - lineSide))
context.addLine(to: CGPoint(x: size.width / 2 + centerOffset, y: size.height / 2 - centerOffset))
context.strokePath()
context.move(to: CGPoint(x: size.width / 2 - lineSide, y: size.height / 2 + centerOffset))
context.move(to: CGPoint(x: size.width / 2 - lineSide, y: size.height / 2 + centerOffset / 2))
context.addLine(to: CGPoint(x: size.width / 2 - lineSide, y: size.height / 2 + lineSide))
context.addLine(to: CGPoint(x: size.width / 2 - centerOffset, y: size.height / 2 + lineSide))
context.addLine(to: CGPoint(x: size.width / 2 - centerOffset / 2, y: size.height / 2 + lineSide))
context.move(to: CGPoint(x: size.width / 2 - lineSide, y: size.height / 2 + lineSide))
context.addLine(to: CGPoint(x: size.width / 2 - centerOffset, y: size.height / 2 + centerOffset))
context.strokePath()
//context.move(to: CGPoint(x: 26.0 - UIScreenPixel, y: 2.0 + UIScreenPixel))
//context.addLine(to: CGPoint(x: 2.0 + UIScreenPixel, y: 26.0 - UIScreenPixel))
// context.strokePath()
}),
title: "expand"
)),
action: {
guard state.hasVideo else { return }
guard state.hasVideo else {
state.isFullscreen = false
return
}
if let controller = controller() as? MediaStreamComponentController {
guard let size = state.videoSize else { return }
state.isFullscreen.toggle()
@ -1669,10 +1668,10 @@ public final class _MediaStreamComponentController: ViewControllerComponentConta
self.onViewDidDisappear?()
}
if let initialOrientation = self.initialOrientation {
self.initialOrientation = nil
self.call.accountContext.sharedContext.applicationBindings.forceOrientation(initialOrientation)
}
// if let initialOrientation = self.initialOrientation {
// self.initialOrientation = nil
// self.call.accountContext.sharedContext.applicationBindings.forceOrientation(initialOrientation)
// }
}
override public func viewDidLoad() {

View File

@ -6,6 +6,7 @@ import AccountContext
import AVKit
import MultilineTextComponent
import Display
import ShimmerEffect
import TelegramCore
@ -103,7 +104,7 @@ final class _MediaStreamVideoComponent: Component {
private var videoPlaceholderView: UIView?
private var noSignalView: ComponentHostView<Empty>?
private let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
private let loadingBlurView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
private let shimmerOverlayView = CALayer()
private var pictureInPictureController: AVPictureInPictureController?
@ -122,7 +123,6 @@ final class _MediaStreamVideoComponent: Component {
self.blurTintView.backgroundColor = UIColor(white: 0.0, alpha: 0.55)
super.init(frame: frame)
// self.backgroundColor = UIColor.green.withAlphaComponent(0.4)
self.isUserInteractionEnabled = false
self.clipsToBounds = true
@ -148,43 +148,65 @@ final class _MediaStreamVideoComponent: Component {
}
let maskGradientLayer = CAGradientLayer()
private var wasVisible = true
let shimmer = StandaloneShimmerEffect()
let borderShimmer = StandaloneShimmerEffect()
let shimmerOverlayLayer = CALayer()
let shimmerBorderLayer = CALayer()
func update(component: _MediaStreamVideoComponent, availableSize: CGSize, state: State, transition: Transition) -> CGSize {
self.state = state
/*let groupPeer = component.call.accountContext.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: component.call.peerId))
let _ = groupPeer.start(next: { peer in
switch peer {
case let .channel(channel):
let photo = channel.photo
photo[0].resource.
print(photo)
default: break
if component.videoLoading {
if loadingBlurView.superview == nil {
addSubview(loadingBlurView)
}
let tileShimmer = VoiceChatTileShimmeringNode(account: component.call.account, peer: peer!._asPeer())
})*/
if shimmerOverlayLayer.superlayer == nil {
loadingBlurView.layer.addSublayer(shimmerOverlayLayer)
loadingBlurView.layer.addSublayer(shimmerBorderLayer)
}
loadingBlurView.clipsToBounds = true
shimmer.layer = shimmerOverlayLayer
shimmerOverlayView.compositingFilter = "softLightBlendMode"
shimmer.testUpdate(background: .clear, foreground: .white.withAlphaComponent(0.4))
loadingBlurView.layer.cornerRadius = 10
shimmerOverlayLayer.opacity = 0.6
shimmerBorderLayer.cornerRadius = 10
shimmerBorderLayer.masksToBounds = true
shimmerBorderLayer.compositingFilter = "softLightBlendMode"
shimmerBorderLayer.borderWidth = 2
shimmerBorderLayer.borderColor = UIColor.white.cgColor
let borderMask = CALayer()
shimmerBorderLayer.mask = borderMask
borderShimmer.layer = borderMask
borderShimmer.testUpdate(background: .clear, foreground: .white)
} else {
loadingBlurView.removeFromSuperview()
}
if component.hasVideo, self.videoView == nil {
// self.addSubview(sheetBackdropView)
// self.addSubview(sheetView)
if let input = component.call.video(endpointId: "unified") {
if let videoBlurView = self.videoRenderingContext.makeView(input: input, blur: true) {
self.videoBlurView = videoBlurView
self.insertSubview(videoBlurView, belowSubview: self.blurTintView)
videoBlurView.alpha = 0
UIView.animate(withDuration: 0.3) {
videoBlurView.alpha = 1
}
self.maskGradientLayer.type = .radial
self.maskGradientLayer.colors = [UIColor(rgb: 0x000000, alpha: 0.5).cgColor, UIColor(rgb: 0xffffff, alpha: 0.0).cgColor]
self.maskGradientLayer.startPoint = CGPoint(x: 0.5, y: 0.5)
self.maskGradientLayer.endPoint = CGPoint(x: 1.0, y: 1.0)
// self.maskGradientLayer.transform = CATransform3DMakeScale(0.3, 0.3, 1.0)
// self.maskGradientLayer.isHidden = true
}
if let videoView = self.videoRenderingContext.makeView(input: input, blur: false, forceSampleBufferDisplayLayer: true) {
self.videoView = videoView
self.addSubview(videoView)
videoView.alpha = 0
UIView.animate(withDuration: 0.3) {
videoView.alpha = 1
}
if let sampleBufferVideoView = videoView as? SampleBufferVideoRenderingView {
if #available(iOS 13.0, *) {
sampleBufferVideoView.sampleBufferLayer.preventsDisplaySleepDuringVideoPlayback = true
@ -345,10 +367,20 @@ final class _MediaStreamVideoComponent: Component {
videoBlurView.layer.mask = nil
}
self.maskGradientLayer.frame = videoBlurView.bounds// CGRect(x: videoBlurView.bounds.midX, y: videoBlurView.bounds.midY, width: videoBlurView.bounds.width, height: videoBlurView.bounds.height)
self.maskGradientLayer.frame = videoBlurView.bounds
}
}
let videoSize = CGSize(width: 16 / 9 * 100.0, height: 100.0).aspectFitted(.init(width: availableSize.width - videoInset * 2, height: availableSize.height))
loadingBlurView.frame = CGRect(origin: CGPoint(x: floor((availableSize.width - videoSize.width) / 2.0), y: floor((availableSize.height - videoSize.height) / 2.0)), size: videoSize)
loadingBlurView.layer.cornerRadius = 10
shimmerOverlayLayer.frame = loadingBlurView.bounds
shimmerBorderLayer.frame = loadingBlurView.bounds
shimmerBorderLayer.mask?.frame = loadingBlurView.bounds
if component.isFullscreen {
loadingBlurView.removeFromSuperview()
}
if !self.hadVideo {
// TODO: hide fullscreen button without video
let aspect: CGFloat = 16.0 / 9

View File

@ -189,18 +189,9 @@ final class StreamSheetComponent: CombinedComponent {
context.add(bottomButtonsRow
.position(CGPoint(x: bottomButtonsRow.size.width / 2, y: context.component.sheetHeight - 50 / 2 + topOffset - context.component.bottomPadding))
)
(context.view as? StreamSheetComponent.View)?.overlayComponentsFrames.append(.init(x: 0, y: context.component.sheetHeight - 50 + topOffset - context.component.bottomPadding, width: bottomButtonsRow.size.width, height: bottomButtonsRow.size.height))
(context.view as? StreamSheetComponent.View)?.overlayComponentsFrames.append(.init(x: 0, y: context.component.sheetHeight - 50 - 20 + topOffset - context.component.bottomPadding, width: bottomButtonsRow.size.width, height: bottomButtonsRow.size.height ))
}
/*if let leftItem = leftItem {
print(leftItem)
context.add(leftItem
.position(CGPoint(x: leftItem.size.width / 2.0, y: contentHeight / 2.0))
)
(context.view as? StreamSheetComponent.View)?.overlayComponentsFrames = [
.init(x: 0, y: 0, width: leftItem.size.width, height: leftItem.size.height)
]
}*/
return size
}
}
@ -486,12 +477,13 @@ class AnimatedCountLabel: UILabel {
fatalError("init(coder:) has not been implemented")
}
var itemWidth: CGFloat { 36 }
var commaWidth: CGFloat { 8 }
override func layoutSubviews() {
super.layoutSubviews()
let interItemSpacing: CGFloat = 0
let countWidth = chars.reduce(0) {
if $1.attributedText?.string == "," {
return $0 + 12
return $0 + commaWidth
}
return $0 + itemWidth + interItemSpacing
} - interItemSpacing
@ -500,7 +492,7 @@ class AnimatedCountLabel: UILabel {
chars.enumerated().forEach { (index, char) in
let offset = chars[0..<index].reduce(0) {
if $1.attributedText?.string == "," {
return $0 + 12
return $0 + commaWidth
}
return $0 + itemWidth + interItemSpacing
}
@ -615,7 +607,7 @@ class AnimatedCountLabel: UILabel {
newLayer.attributedText = newChars[newCharIndex]
let offset = newChars[0..<newCharIndex].reduce(0) {
if $1.string == "," {
return $0 + 12
return $0 + commaWidth
}
return $0 + itemWidth + interItemSpacing
}
@ -648,7 +640,7 @@ class AnimatedCountLabel: UILabel {
let offset = newChars[0..<newCharIndex].reduce(0) {
if $1.string == "," {
return $0 + 12
return $0 + commaWidth
}
return $0 + itemWidth + interItemSpacing
}
@ -663,7 +655,7 @@ class AnimatedCountLabel: UILabel {
let countWidth = newChars.reduce(-interItemSpacing) {
if $1.string == "," {
return $0 + 12
return $0 + commaWidth
}
return $0 + itemWidth + interItemSpacing
}

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "close.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "close@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "close@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "expand.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "expand@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "expand@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "more.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "more@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "more@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "pip.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "pip@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "pip@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 504 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 590 B

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "share.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "share@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "share@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 504 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 959 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB