mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various fixes
This commit is contained in:
parent
0d69b86b92
commit
5ad9671d70
@ -161,6 +161,7 @@ private final class CameraContext {
|
||||
self.secondaryPreviewView = secondaryPreviewView
|
||||
|
||||
self.positionValue = configuration.position
|
||||
self._positionPromise = ValuePromise<Camera.Position>(configuration.position)
|
||||
|
||||
self.mainDeviceContext = CameraDeviceContext(session: session, exclusive: true, additional: false)
|
||||
self.configure {
|
||||
@ -251,14 +252,14 @@ private final class CameraContext {
|
||||
}
|
||||
}
|
||||
|
||||
private var _positionPromise = ValuePromise<Camera.Position>(.unspecified)
|
||||
private var _positionPromise: ValuePromise<Camera.Position>
|
||||
var position: Signal<Camera.Position, NoError> {
|
||||
return self._positionPromise.get()
|
||||
}
|
||||
|
||||
private var positionValue: Camera.Position = .back
|
||||
func togglePosition() {
|
||||
if self.isDualCamEnabled {
|
||||
if self.isDualCameraEnabled {
|
||||
let targetPosition: Camera.Position
|
||||
if case .back = self.positionValue {
|
||||
targetPosition = .front
|
||||
@ -308,12 +309,12 @@ private final class CameraContext {
|
||||
}
|
||||
}
|
||||
|
||||
private var isDualCamEnabled = false
|
||||
public func setDualCamEnabled(_ enabled: Bool) {
|
||||
guard enabled != self.isDualCamEnabled else {
|
||||
private var isDualCameraEnabled = false
|
||||
public func setDualCameraEnabled(_ enabled: Bool) {
|
||||
guard enabled != self.isDualCameraEnabled else {
|
||||
return
|
||||
}
|
||||
self.isDualCamEnabled = enabled
|
||||
self.isDualCameraEnabled = enabled
|
||||
|
||||
self.modeChange = .dualCamera
|
||||
if enabled {
|
||||
@ -659,10 +660,10 @@ public final class Camera {
|
||||
}
|
||||
}
|
||||
|
||||
public func setDualCamEnabled(_ enabled: Bool) {
|
||||
public func setDualCameraEnabled(_ enabled: Bool) {
|
||||
self.queue.async {
|
||||
if let context = self.contextRef?.takeUnretainedValue() {
|
||||
context.setDualCamEnabled(enabled)
|
||||
context.setDualCameraEnabled(enabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2568,16 +2568,41 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
switch self.storyPostingAvailability {
|
||||
case .premium:
|
||||
guard self.isPremium else {
|
||||
let context = self.context
|
||||
var replaceImpl: ((ViewController) -> Void)?
|
||||
let controller = context.sharedContext.makePremiumDemoController(context: self.context, subject: .stories, action: {
|
||||
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .stories)
|
||||
replaceImpl?(controller)
|
||||
})
|
||||
replaceImpl = { [weak controller] c in
|
||||
controller?.replace(with: c)
|
||||
if let componentView = self.chatListHeaderView() {
|
||||
var sourceFrame: CGRect?
|
||||
if fromList {
|
||||
if let (transitionView, _) = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
|
||||
sourceFrame = transitionView.convert(transitionView.bounds, to: nil).offsetBy(dx: 18.0 - UIScreenPixel, dy: 1.0)
|
||||
}
|
||||
} else {
|
||||
if let rightButtonView = componentView.rightButtonViews["story"] {
|
||||
sourceFrame = rightButtonView.convert(rightButtonView.bounds, to: nil).offsetBy(dx: 5.0, dy: -8.0)
|
||||
}
|
||||
}
|
||||
if let sourceFrame {
|
||||
let context = self.context
|
||||
let location = CGRect(origin: CGPoint(x: sourceFrame.midX, y: sourceFrame.maxY), size: CGSize())
|
||||
let tooltipController = TooltipScreen(
|
||||
context: context,
|
||||
account: context.account,
|
||||
sharedContext: context.sharedContext,
|
||||
text: .markdown(text: "Posting stories is currently available only to subscribers of [Telegram Premium]()."),
|
||||
style: .customBlur(UIColor(rgb: 0x2a2a2a), 2.0),
|
||||
icon: .none,
|
||||
location: .point(location, .top),
|
||||
shouldDismissOnTouch: { [weak self] point, containerFrame in
|
||||
if containerFrame.contains(point) {
|
||||
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .stories)
|
||||
self?.push(controller)
|
||||
return .dismiss(consume: true)
|
||||
} else {
|
||||
return .dismiss(consume: false)
|
||||
}
|
||||
}
|
||||
)
|
||||
self.present(tooltipController, in: .window(.root))
|
||||
}
|
||||
}
|
||||
self.push(controller)
|
||||
return
|
||||
}
|
||||
case .disabled:
|
||||
|
@ -12,6 +12,186 @@ private let imageManager: PHCachingImageManager = {
|
||||
|
||||
private let assetsQueue = Queue()
|
||||
|
||||
final class AssetDownloadManager {
|
||||
private final class DownloadingAssetContext {
|
||||
let identifier: String
|
||||
let updated: () -> Void
|
||||
|
||||
var status: AssetDownloadStatus = .progress(0.0)
|
||||
var disposable: Disposable?
|
||||
|
||||
init(identifier: String, updated: @escaping () -> Void) {
|
||||
self.identifier = identifier
|
||||
self.updated = updated
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.disposable?.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
private let queue = Queue()
|
||||
private var currentAssetContext: DownloadingAssetContext?
|
||||
|
||||
init() {
|
||||
}
|
||||
|
||||
deinit {
|
||||
}
|
||||
|
||||
func download(asset: PHAsset) {
|
||||
if let currentAssetContext = self.currentAssetContext {
|
||||
currentAssetContext.disposable?.dispose()
|
||||
}
|
||||
|
||||
let queue = self.queue
|
||||
let identifier = asset.localIdentifier
|
||||
|
||||
let assetContext = DownloadingAssetContext(identifier: identifier, updated: { [weak self] in
|
||||
queue.async {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let currentAssetContext = self.currentAssetContext, currentAssetContext.identifier == identifier, let bag = self.progressObserverContexts[identifier] {
|
||||
for f in bag.copyItems() {
|
||||
f(currentAssetContext.status)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
assetContext.disposable = (downloadAssetMediaData(asset)
|
||||
|> deliverOn(queue)).start(next: { [weak self] status in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let currentAssetContext = self.currentAssetContext, currentAssetContext.identifier == identifier {
|
||||
currentAssetContext.status = status
|
||||
currentAssetContext.updated()
|
||||
}
|
||||
})
|
||||
self.currentAssetContext = assetContext
|
||||
}
|
||||
|
||||
func cancel(identifier: String) {
|
||||
if let currentAssetContext = self.currentAssetContext, currentAssetContext.identifier == identifier {
|
||||
currentAssetContext.disposable?.dispose()
|
||||
self.currentAssetContext = nil
|
||||
}
|
||||
}
|
||||
|
||||
private var progressObserverContexts: [String: Bag<(AssetDownloadStatus) -> Void>] = [:]
|
||||
private func downloadProgress(identifier: String, next: @escaping (AssetDownloadStatus) -> Void) -> Disposable {
|
||||
let bag: Bag<(AssetDownloadStatus) -> Void>
|
||||
if let current = self.progressObserverContexts[identifier] {
|
||||
bag = current
|
||||
} else {
|
||||
bag = Bag()
|
||||
self.progressObserverContexts[identifier] = bag
|
||||
}
|
||||
|
||||
let index = bag.add(next)
|
||||
if let currentAssetContext = self.currentAssetContext, currentAssetContext.identifier == identifier {
|
||||
next(currentAssetContext.status)
|
||||
} else {
|
||||
next(.progress(0.0))
|
||||
}
|
||||
|
||||
let queue = self.queue
|
||||
return ActionDisposable { [weak self, weak bag] in
|
||||
queue.async {
|
||||
guard let `self` = self else {
|
||||
return
|
||||
}
|
||||
if let bag = bag, let listBag = self.progressObserverContexts[identifier], listBag === bag {
|
||||
bag.remove(index)
|
||||
if bag.isEmpty {
|
||||
self.progressObserverContexts.removeValue(forKey: identifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func downloadProgress(identifier: String) -> Signal<AssetDownloadStatus, NoError> {
|
||||
return Signal { [weak self] subscriber in
|
||||
if let self {
|
||||
return self.downloadProgress(identifier: identifier, next: { status in
|
||||
subscriber.putNext(status)
|
||||
if case .completed = status {
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return EmptyDisposable
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func checkIfAssetIsLocal(_ asset: PHAsset) -> Signal<Bool, NoError> {
|
||||
return Signal { subscriber in
|
||||
let options = PHImageRequestOptions()
|
||||
options.isNetworkAccessAllowed = false
|
||||
|
||||
let requestId: PHImageRequestID
|
||||
if #available(iOS 13, *) {
|
||||
requestId = imageManager.requestImageDataAndOrientation(for: asset, options: options) { data, _, _, _ in
|
||||
if data != nil {
|
||||
subscriber.putNext(data != nil)
|
||||
}
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
} else {
|
||||
requestId = imageManager.requestImageData(for: asset, options: options) { data, _, _, _ in
|
||||
if data != nil {
|
||||
subscriber.putNext(data != nil)
|
||||
}
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
}
|
||||
|
||||
return ActionDisposable {
|
||||
imageManager.cancelImageRequest(requestId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum AssetDownloadStatus {
|
||||
case progress(Float)
|
||||
case completed
|
||||
}
|
||||
|
||||
private func downloadAssetMediaData(_ asset: PHAsset) -> Signal<AssetDownloadStatus, NoError> {
|
||||
return Signal { subscriber in
|
||||
let options = PHImageRequestOptions()
|
||||
options.isNetworkAccessAllowed = true
|
||||
options.progressHandler = { progress, _, _, _ in
|
||||
subscriber.putNext(.progress(Float(progress)))
|
||||
}
|
||||
|
||||
let requestId: PHImageRequestID
|
||||
if #available(iOS 13, *) {
|
||||
requestId = imageManager.requestImageDataAndOrientation(for: asset, options: options) { data, _, _, _ in
|
||||
if data != nil {
|
||||
subscriber.putNext(.completed)
|
||||
}
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
} else {
|
||||
requestId = imageManager.requestImageData(for: asset, options: options) { data, _, _, _ in
|
||||
if data != nil {
|
||||
subscriber.putNext(.completed)
|
||||
}
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
}
|
||||
|
||||
return ActionDisposable {
|
||||
imageManager.cancelImageRequest(requestId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func assetImage(fetchResult: PHFetchResult<PHAsset>, index: Int, targetSize: CGSize, exact: Bool, deliveryMode: PHImageRequestOptionsDeliveryMode = .opportunistic, synchronous: Bool = false) -> Signal<UIImage?, NoError> {
|
||||
let asset = fetchResult[index]
|
||||
return assetImage(asset: asset, targetSize: targetSize, exact: exact, deliveryMode: deliveryMode, synchronous: synchronous)
|
||||
@ -68,3 +248,10 @@ func assetVideo(fetchResult: PHFetchResult<PHAsset>, index: Int) -> Signal<AVAss
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension PHAsset {
|
||||
var isLocallyAvailable: Bool? {
|
||||
let resourceArray = PHAssetResource.assetResources(for: self)
|
||||
return resourceArray.first?.value(forKey: "locallyAvailable") as? Bool
|
||||
}
|
||||
}
|
||||
|
@ -777,6 +777,10 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
|
||||
private weak var currentGalleryController: TGModernGalleryController?
|
||||
|
||||
private func requestAssetDownload(_ asset: PHAsset) {
|
||||
|
||||
}
|
||||
|
||||
private var openingMedia = false
|
||||
fileprivate func openMedia(fetchResult: PHFetchResult<PHAsset>, index: Int, immediateThumbnail: UIImage?) {
|
||||
guard let controller = self.controller, let interaction = controller.interaction, let (layout, _) = self.validLayout, !self.openingMedia else {
|
||||
@ -788,7 +792,29 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
|
||||
if let customSelection = controller.customSelection {
|
||||
self.openingMedia = true
|
||||
customSelection(controller, fetchResult[index])
|
||||
|
||||
let asset = fetchResult[index]
|
||||
customSelection(controller, asset)
|
||||
|
||||
// let isLocallyAvailable = asset.isLocallyAvailable
|
||||
//
|
||||
// if let isLocallyAvailable {
|
||||
// if isLocallyAvailable {
|
||||
// customSelection(controller, asset)
|
||||
// } else {
|
||||
// self.requestAssetDownload(asset)
|
||||
// }
|
||||
// } else {
|
||||
// let _ = (checkIfAssetIsLocal(asset)
|
||||
// |> deliverOnMainQueue).start(next: { [weak self] isLocallyAvailable in
|
||||
// if isLocallyAvailable {
|
||||
// customSelection(controller, asset)
|
||||
// } else {
|
||||
// self?.requestAssetDownload(asset)
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
Queue.mainQueue().after(0.3) {
|
||||
self.openingMedia = false
|
||||
}
|
||||
|
@ -1729,7 +1729,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
if let strongSelf = self, (count < 2 && currentTimestamp > timestamp + 24 * 60 * 60) {
|
||||
strongSelf.displayedPreviewTooltip = true
|
||||
|
||||
let controller = TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: .plain(text: isDark ? strongSelf.presentationData.strings.WallpaperPreview_PreviewInDayMode : strongSelf.presentationData.strings.WallpaperPreview_PreviewInNightMode), style: .customBlur(UIColor(rgb: 0x333333, alpha: 0.35)), icon: nil, location: .point(frame.offsetBy(dx: 1.0, dy: 6.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _, _ in
|
||||
let controller = TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: .plain(text: isDark ? strongSelf.presentationData.strings.WallpaperPreview_PreviewInDayMode : strongSelf.presentationData.strings.WallpaperPreview_PreviewInNightMode), style: .customBlur(UIColor(rgb: 0x333333, alpha: 0.35), 0.0), icon: nil, location: .point(frame.offsetBy(dx: 1.0, dy: 6.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _, _ in
|
||||
return .dismiss(consume: false)
|
||||
})
|
||||
strongSelf.galleryController()?.present(controller, in: .current)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,73 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftSignalKit
|
||||
import TelegramCore
|
||||
import TelegramUIPreferences
|
||||
import MediaEditor
|
||||
|
||||
public final class CameraStoredState: Codable {
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case isDualCameraEnabled
|
||||
case dualCameraPosition
|
||||
}
|
||||
|
||||
public let isDualCameraEnabled: Bool
|
||||
public let dualCameraPosition: CameraScreen.PIPPosition
|
||||
|
||||
public init(
|
||||
isDualCameraEnabled: Bool,
|
||||
dualCameraPosition: CameraScreen.PIPPosition
|
||||
) {
|
||||
self.isDualCameraEnabled = isDualCameraEnabled
|
||||
self.dualCameraPosition = dualCameraPosition
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
self.isDualCameraEnabled = try container.decode(Bool.self, forKey: .isDualCameraEnabled)
|
||||
self.dualCameraPosition = CameraScreen.PIPPosition(rawValue: try container.decode(Int32.self, forKey: .dualCameraPosition)) ?? .topRight
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try container.encode(self.isDualCameraEnabled, forKey: .isDualCameraEnabled)
|
||||
try container.encode(self.dualCameraPosition.rawValue, forKey: .dualCameraPosition)
|
||||
}
|
||||
|
||||
public func withIsDualCameraEnabled(_ isDualCameraEnabled: Bool) -> CameraStoredState {
|
||||
return CameraStoredState(isDualCameraEnabled: isDualCameraEnabled, dualCameraPosition: self.dualCameraPosition)
|
||||
}
|
||||
|
||||
public func withDualCameraPosition(_ dualCameraPosition: CameraScreen.PIPPosition) -> CameraStoredState {
|
||||
return CameraStoredState(isDualCameraEnabled: self.isDualCameraEnabled, dualCameraPosition: dualCameraPosition)
|
||||
}
|
||||
}
|
||||
|
||||
func cameraStoredState(engine: TelegramEngine) -> Signal<CameraStoredState?, NoError> {
|
||||
let key = EngineDataBuffer(length: 4)
|
||||
key.setInt32(0, value: 0)
|
||||
|
||||
return engine.data.get(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: ApplicationSpecificItemCacheCollectionId.cameraState, id: key))
|
||||
|> map { entry -> CameraStoredState? in
|
||||
return entry?.get(CameraStoredState.self)
|
||||
}
|
||||
}
|
||||
|
||||
func updateCameraStoredStateInteractively(engine: TelegramEngine, _ f: @escaping (CameraStoredState?) -> CameraStoredState?) {
|
||||
let key = EngineDataBuffer(length: 4)
|
||||
key.setInt32(0, value: 0)
|
||||
|
||||
let _ = (engine.data.get(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: ApplicationSpecificItemCacheCollectionId.cameraState, id: key))
|
||||
|> map { entry -> CameraStoredState? in
|
||||
return entry?.get(CameraStoredState.self)
|
||||
}
|
||||
|> mapToSignal { state -> Signal<Never, NoError> in
|
||||
if let updatedState = f(state) {
|
||||
return engine.itemCache.put(collectionId: ApplicationSpecificItemCacheCollectionId.cameraState, id: key, item: updatedState)
|
||||
} else {
|
||||
return engine.itemCache.remove(collectionId: ApplicationSpecificItemCacheCollectionId.cameraState, id: key)
|
||||
}
|
||||
}).start()
|
||||
}
|
@ -1117,7 +1117,7 @@ final class CaptureControlsComponent: Component {
|
||||
),
|
||||
minSize: hintIconSize,
|
||||
action: {
|
||||
component.flipTapped()
|
||||
component.lockRecording()
|
||||
}
|
||||
)
|
||||
),
|
||||
|
@ -341,41 +341,54 @@ private func verticesData(
|
||||
bottomRight = simd_float2(1.0, 1.0)
|
||||
}
|
||||
|
||||
let relativeSize = CGSize(
|
||||
width: size.width / containerSize.width,
|
||||
height: size.height / containerSize.height
|
||||
)
|
||||
let relativeOffset = CGPoint(
|
||||
x: position.x / containerSize.width,
|
||||
y: position.y / containerSize.height
|
||||
)
|
||||
|
||||
let rect = CGRect(
|
||||
origin: CGPoint(
|
||||
x: relativeOffset.x - relativeSize.width / 2.0,
|
||||
y: relativeOffset.y - relativeSize.height / 2.0
|
||||
),
|
||||
size: relativeSize
|
||||
)
|
||||
let angle = Float(.pi - rotation)
|
||||
let cosAngle = cos(angle)
|
||||
let sinAngle = sin(angle)
|
||||
|
||||
let centerX = Float(position.x)
|
||||
let centerY = Float(position.y)
|
||||
|
||||
let halfWidth = Float(size.width / 2.0)
|
||||
let halfHeight = Float(size.height / 2.0)
|
||||
|
||||
return [
|
||||
VertexData(
|
||||
pos: simd_float4(x: Float(rect.minX) * 2.0, y: Float(rect.minY) * 2.0, z: z, w: 1),
|
||||
pos: simd_float4(
|
||||
x: (centerX + (halfWidth * cosAngle) - (halfHeight * sinAngle)) / Float(containerSize.width) * 2.0,
|
||||
y: (centerY + (halfWidth * sinAngle) + (halfHeight * cosAngle)) / Float(containerSize.height) * 2.0,
|
||||
z: z,
|
||||
w: 1
|
||||
),
|
||||
texCoord: topLeft,
|
||||
localPos: simd_float2(0.0, 0.0)
|
||||
),
|
||||
VertexData(
|
||||
pos: simd_float4(x: Float(rect.maxX) * 2.0, y: Float(rect.minY) * 2.0, z: z, w: 1),
|
||||
pos: simd_float4(
|
||||
x: (centerX - (halfWidth * cosAngle) - (halfHeight * sinAngle)) / Float(containerSize.width) * 2.0,
|
||||
y: (centerY - (halfWidth * sinAngle) + (halfHeight * cosAngle)) / Float(containerSize.height) * 2.0,
|
||||
z: z,
|
||||
w: 1
|
||||
),
|
||||
texCoord: topRight,
|
||||
localPos: simd_float2(1.0, 0.0)
|
||||
),
|
||||
VertexData(
|
||||
pos: simd_float4(x: Float(rect.minX) * 2.0, y: Float(rect.maxY) * 2.0, z: z, w: 1),
|
||||
pos: simd_float4(
|
||||
x: (centerX + (halfWidth * cosAngle) + (halfHeight * sinAngle)) / Float(containerSize.width) * 2.0,
|
||||
y: (centerY + (halfWidth * sinAngle) - (halfHeight * cosAngle)) / Float(containerSize.height) * 2.0,
|
||||
z: z,
|
||||
w: 1
|
||||
),
|
||||
texCoord: bottomLeft,
|
||||
localPos: simd_float2(0.0, 1.0)
|
||||
),
|
||||
VertexData(
|
||||
pos: simd_float4(x: Float(rect.maxX) * 2.0, y: Float(rect.maxY) * 2.0, z: z, w: 1),
|
||||
pos: simd_float4(
|
||||
x: (centerX - (halfWidth * cosAngle) + (halfHeight * sinAngle)) / Float(containerSize.width) * 2.0,
|
||||
y: (centerY - (halfWidth * sinAngle) - (halfHeight * cosAngle)) / Float(containerSize.height) * 2.0,
|
||||
z: z,
|
||||
w: 1
|
||||
),
|
||||
texCoord: bottomRight,
|
||||
localPos: simd_float2(1.0, 1.0)
|
||||
)
|
||||
@ -650,13 +663,13 @@ final class VideoInputScalePass: RenderPass {
|
||||
}
|
||||
|
||||
func process(input: MTLTexture, secondInput: MTLTexture?, timestamp: CMTime, device: MTLDevice, commandBuffer: MTLCommandBuffer) -> MTLTexture? {
|
||||
//#if targetEnvironment(simulator)
|
||||
//
|
||||
//#else
|
||||
#if targetEnvironment(simulator)
|
||||
|
||||
#else
|
||||
guard max(input.width, input.height) > 1920 || secondInput != nil else {
|
||||
return input
|
||||
}
|
||||
//#endif
|
||||
#endif
|
||||
|
||||
let scaledSize = CGSize(width: input.width, height: input.height).fitted(CGSize(width: 1920.0, height: 1920.0))
|
||||
let width: Int
|
||||
@ -705,9 +718,9 @@ final class VideoInputScalePass: RenderPass {
|
||||
|
||||
renderCommandEncoder.setRenderPipelineState(self.mainPipelineState!)
|
||||
|
||||
//#if targetEnvironment(simulator)
|
||||
// let secondInput = input
|
||||
//#endif
|
||||
#if targetEnvironment(simulator)
|
||||
let secondInput = input
|
||||
#endif
|
||||
|
||||
let (mainVideoState, additionalVideoState, transitionVideoState) = self.transitionState(for: timestamp, mainInput: input, additionalInput: secondInput)
|
||||
|
||||
|
@ -935,7 +935,9 @@ final class MediaEditorScreenComponent: Component {
|
||||
|
||||
let scrubberFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - scrubberSize.width) / 2.0), y: availableSize.height - environment.safeInsets.bottom - scrubberSize.height - 8.0 + controlsBottomInset), size: scrubberSize)
|
||||
if let scrubberView = self.scrubber.view {
|
||||
var animateIn = false
|
||||
if scrubberView.superview == nil {
|
||||
animateIn = true
|
||||
if let inputPanelBackgroundView = self.inputPanelBackground.view, inputPanelBackgroundView.superview != nil {
|
||||
self.insertSubview(scrubberView, belowSubview: inputPanelBackgroundView)
|
||||
} else {
|
||||
@ -945,6 +947,10 @@ final class MediaEditorScreenComponent: Component {
|
||||
transition.setFrame(view: scrubberView, frame: scrubberFrame)
|
||||
if !self.animatingButtons {
|
||||
transition.setAlpha(view: scrubberView, alpha: component.isDisplayingTool || component.isDismissing || component.isInteractingWithEntities ? 0.0 : 1.0)
|
||||
} else if animateIn {
|
||||
scrubberView.layer.animatePosition(from: CGPoint(x: 0.0, y: 44.0), to: .zero, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
||||
scrubberView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
scrubberView.layer.animateScale(from: 0.6, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
|
||||
@ -3134,15 +3140,16 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
case bottomRight
|
||||
|
||||
func getPosition(_ size: CGSize) -> CGPoint {
|
||||
let offset = CGPoint(x: 224.0, y: 520.0)
|
||||
switch self {
|
||||
case .topLeft:
|
||||
return CGPoint(x: 224.0, y: 477.0)
|
||||
return CGPoint(x: offset.x, y: offset.y)
|
||||
case .topRight:
|
||||
return CGPoint(x: size.width - 224.0, y: 477.0)
|
||||
return CGPoint(x: size.width - offset.x, y: offset.y)
|
||||
case .bottomLeft:
|
||||
return CGPoint(x: 224.0, y: size.height - 477.0)
|
||||
return CGPoint(x: offset.x, y: size.height - offset.y)
|
||||
case .bottomRight:
|
||||
return CGPoint(x: size.width - 224.0, y: size.height - 477.0)
|
||||
return CGPoint(x: size.width - offset.x, y: size.height - offset.y)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3374,28 +3381,29 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
self.push(
|
||||
ShareWithPeersScreen(
|
||||
context: self.context,
|
||||
initialPrivacy: privacy,
|
||||
allowScreenshots: !isForwardingDisabled,
|
||||
pin: pin,
|
||||
stateContext: stateContext,
|
||||
completion: { [weak self] result, isForwardingDisabled, pin in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if case .closeFriends = privacy.base {
|
||||
let _ = self.context.engine.privacy.updateCloseFriends(peerIds: result.additionallyIncludePeers).start()
|
||||
completion(EngineStoryPrivacy(base: .closeFriends, additionallyIncludePeers: []))
|
||||
} else {
|
||||
completion(result)
|
||||
}
|
||||
},
|
||||
editCategory: { _, _, _ in }
|
||||
)
|
||||
let controller = ShareWithPeersScreen(
|
||||
context: self.context,
|
||||
initialPrivacy: privacy,
|
||||
allowScreenshots: !isForwardingDisabled,
|
||||
pin: pin,
|
||||
stateContext: stateContext,
|
||||
completion: { [weak self] result, isForwardingDisabled, pin in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if case .closeFriends = privacy.base {
|
||||
let _ = self.context.engine.privacy.updateCloseFriends(peerIds: result.additionallyIncludePeers).start()
|
||||
completion(EngineStoryPrivacy(base: .closeFriends, additionallyIncludePeers: []))
|
||||
} else {
|
||||
completion(result)
|
||||
}
|
||||
},
|
||||
editCategory: { _, _, _ in }
|
||||
)
|
||||
controller.dismissed = {
|
||||
self.node.mediaEditor?.play()
|
||||
}
|
||||
self.push(controller)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1235,7 +1235,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
centerInfoView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
|
||||
}
|
||||
if let moreButtonView = self.moreButton.view {
|
||||
moreButtonView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
|
||||
moreButtonView.layer.animateAlpha(from: 0.0, to: moreButtonView.alpha, duration: 0.25)
|
||||
}
|
||||
if let soundButtonView = self.soundButton.view {
|
||||
soundButtonView.layer.animateAlpha(from: 0.0, to: soundButtonView.alpha, duration: 0.25)
|
||||
@ -1361,7 +1361,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
centerInfoView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false)
|
||||
}
|
||||
if let moreButtonView = self.moreButton.view {
|
||||
moreButtonView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false)
|
||||
moreButtonView.layer.animateAlpha(from: moreButtonView.alpha, to: 0.0, duration: 0.25, removeOnCompletion: false)
|
||||
}
|
||||
if let soundButtonView = self.soundButton.view {
|
||||
soundButtonView.layer.animateAlpha(from: soundButtonView.alpha, to: 0.0, duration: 0.25, removeOnCompletion: false)
|
||||
@ -1592,6 +1592,16 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
|
||||
if self.component?.slice.item.storyItem.id != component.slice.item.storyItem.id {
|
||||
self.initializedOffset = false
|
||||
|
||||
if let inputPanelView = self.inputPanel.view as? MessageInputPanelComponent.View {
|
||||
Queue.mainQueue().justDispatch {
|
||||
inputPanelView.clearSendMessageInput()
|
||||
}
|
||||
}
|
||||
|
||||
if let tooltipScreen = self.sendMessageContext.tooltipScreen {
|
||||
tooltipScreen.dismiss()
|
||||
}
|
||||
}
|
||||
var itemsTransition = transition
|
||||
var resetScrollingOffsetWithItemTransition = false
|
||||
@ -3341,7 +3351,6 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
return .single(nil)
|
||||
|> then(
|
||||
.single(.video(symlinkPath, nil, false, nil, nil, PixelDimensions(width: 720, height: 1280), duration ?? 0.0, [], .bottomRight))
|
||||
|> delay(0.1, queue: Queue.mainQueue())
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -3848,7 +3857,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
account: component.context.account,
|
||||
sharedContext: component.context.sharedContext,
|
||||
text: .markdown(text: text),
|
||||
style: .customBlur(UIColor(rgb: 0x1c1c1c)),
|
||||
style: .customBlur(UIColor(rgb: 0x1c1c1c), 0.0),
|
||||
icon: .peer(peer: component.slice.peer, isStory: true),
|
||||
action: TooltipScreen.Action(
|
||||
title: "Undo",
|
||||
|
@ -78,6 +78,7 @@ private enum ApplicationSpecificItemCacheCollectionIdValues: Int8 {
|
||||
case translationState = 10
|
||||
case storySource = 11
|
||||
case mediaEditorState = 12
|
||||
case cameraState = 13
|
||||
}
|
||||
|
||||
public struct ApplicationSpecificItemCacheCollectionId {
|
||||
@ -92,6 +93,7 @@ public struct ApplicationSpecificItemCacheCollectionId {
|
||||
public static let translationState = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.translationState.rawValue)
|
||||
public static let storySource = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.storySource.rawValue)
|
||||
public static let mediaEditorState = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.mediaEditorState.rawValue)
|
||||
public static let cameraState = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.cameraState.rawValue)
|
||||
}
|
||||
|
||||
private enum ApplicationSpecificOrderedItemListCollectionIdValues: Int32 {
|
||||
|
@ -240,7 +240,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
if !hasArrow {
|
||||
let backgroundColor: UIColor
|
||||
var enableSaturation = true
|
||||
if case let .customBlur(color) = style {
|
||||
if case let .customBlur(color, _) = style {
|
||||
backgroundColor = color
|
||||
enableSaturation = false
|
||||
} else {
|
||||
@ -297,7 +297,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
} else {
|
||||
var enableSaturation = true
|
||||
let backgroundColor: UIColor
|
||||
if case let .customBlur(color) = style {
|
||||
if case let .customBlur(color, _) = style {
|
||||
backgroundColor = color
|
||||
enableSaturation = false
|
||||
} else if case .light = style {
|
||||
@ -356,10 +356,11 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
case let .entities(text, entities):
|
||||
attributedText = stringWithAppliedEntities(text, entities: entities, baseColor: textColor, linkColor: textColor, baseFont: baseFont, linkFont: baseFont, boldFont: boldFont, italicFont: italicFont, boldItalicFont: boldItalicFont, fixedFont: fixedFont, blockQuoteFont: baseFont, underlineLinks: true, external: false, message: nil)
|
||||
case let .markdown(text):
|
||||
let linkColor = UIColor(rgb: 0x64d2ff)
|
||||
let markdownAttributes = MarkdownAttributes(
|
||||
body: MarkdownAttributeSet(font: baseFont, textColor: textColor),
|
||||
bold: MarkdownAttributeSet(font: boldFont, textColor: textColor),
|
||||
link: MarkdownAttributeSet(font: baseFont, textColor: textColor),
|
||||
link: MarkdownAttributeSet(font: boldFont, textColor: linkColor),
|
||||
linkAttribute: { _ in
|
||||
return nil
|
||||
}
|
||||
@ -560,14 +561,16 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
|
||||
var backgroundHeight: CGFloat
|
||||
switch self.tooltipStyle {
|
||||
case .default, .gradient, .customBlur, .wide:
|
||||
case .default, .gradient:
|
||||
backgroundHeight = max(animationSize.height, textSize.height) + contentVerticalInset * 2.0
|
||||
case .wide:
|
||||
backgroundHeight = max(animationSize.height, textSize.height) + contentVerticalInset * 2.0 + 4.0
|
||||
case let .customBlur(_, inset):
|
||||
backgroundHeight = max(animationSize.height, textSize.height) + contentVerticalInset * 2.0 + inset * 2.0
|
||||
case .light:
|
||||
backgroundHeight = max(28.0, max(animationSize.height, textSize.height) + 4.0 * 2.0)
|
||||
}
|
||||
if case .wide = self.tooltipStyle {
|
||||
backgroundHeight += 4.0
|
||||
} else if self.actionButtonNode != nil {
|
||||
if self.actionButtonNode != nil {
|
||||
backgroundHeight += 4.0
|
||||
}
|
||||
|
||||
@ -739,6 +742,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
}
|
||||
}
|
||||
|
||||
private var didRequestDismiss = false
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if let event = event {
|
||||
if let _ = self.openActiveTextItem, let result = self.textNode.hitTest(self.view.convert(point, to: self.textNode.view), with: event) {
|
||||
@ -753,14 +757,19 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
if let actionButtonNode = self.actionButtonNode, let result = actionButtonNode.hitTest(self.convert(point, to: actionButtonNode), with: event) {
|
||||
return result
|
||||
}
|
||||
switch self.shouldDismissOnTouch(point, self.containerNode.frame) {
|
||||
case .ignore:
|
||||
break
|
||||
case let .dismiss(consume):
|
||||
self.requestDismiss()
|
||||
if consume {
|
||||
return self.view
|
||||
if !self.didRequestDismiss {
|
||||
switch self.shouldDismissOnTouch(point, self.containerNode.frame) {
|
||||
case .ignore:
|
||||
break
|
||||
case let .dismiss(consume):
|
||||
self.requestDismiss()
|
||||
if consume {
|
||||
self.didRequestDismiss = true
|
||||
return self.view
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return self.view
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -915,7 +924,7 @@ public final class TooltipScreen: ViewController {
|
||||
public enum Style {
|
||||
case `default`
|
||||
case light
|
||||
case customBlur(UIColor)
|
||||
case customBlur(UIColor, CGFloat)
|
||||
case gradient(UIColor, UIColor)
|
||||
case wide
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user