diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift index 00a9a448df..39792a8157 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift @@ -518,7 +518,19 @@ private final class StoryContainerScreenComponent: Component { let slice = currentSlices[i] + let cubeAdditionalRotationFraction: CGFloat + if i == focusedIndex { + cubeAdditionalRotationFraction = 0.0 + } else if i < focusedIndex { + cubeAdditionalRotationFraction = -1.0 + } else { + cubeAdditionalRotationFraction = 1.0 + } + + var panFraction: CGFloat = 0.0 if let itemSetPanState = self.itemSetPanState { + panFraction = -itemSetPanState.fraction + if self.visibleItemSetViews[slice.peer.id] != nil { isItemVisible = true } @@ -543,14 +555,16 @@ private final class StoryContainerScreenComponent: Component { self.visibleItemSetViews[slice.peer.id] = itemSetView } - let itemContainerSize: CGSize + var itemSetContainerSize = availableSize + var itemSetContainerTopInset = environment.statusBarHeight + 12.0 + var itemSetContainerSafeInsets = environment.safeInsets if case .regular = environment.metrics.widthClass { - let availableHeight = availableSize.height - max(45.0, environment.safeInsets.bottom) * 2.0 - let mediaHeight = min(1040.0, availableHeight - 90.0) - let mediaWidth = floorToScreenPixels(mediaHeight * 0.5625) - itemContainerSize = CGSize(width: mediaWidth, height: availableHeight) - } else { - itemContainerSize = availableSize + let availableHeight = min(1080.0, availableSize.height - max(45.0, environment.safeInsets.bottom) * 2.0) + let mediaHeight = availableHeight - 40.0 + let mediaWidth = floor(mediaHeight * 0.5625) + itemSetContainerSize = CGSize(width: mediaWidth, height: availableHeight) + itemSetContainerTopInset = 0.0 + itemSetContainerSafeInsets.bottom = 0.0 } let _ = itemSetView.view.update( @@ -561,11 +575,13 @@ private final class StoryContainerScreenComponent: Component { slice: slice, theme: environment.theme, strings: environment.strings, - containerInsets: UIEdgeInsets(top: environment.statusBarHeight + 12.0, left: 0.0, bottom: environment.inputHeight, right: 0.0), - safeInsets: environment.safeInsets, + containerInsets: UIEdgeInsets(top: itemSetContainerTopInset, left: 0.0, bottom: environment.inputHeight, right: 0.0), + safeInsets: itemSetContainerSafeInsets, inputHeight: environment.inputHeight, + metrics: environment.metrics, isProgressPaused: isProgressPaused || i != focusedIndex, hideUI: i == focusedIndex && self.itemSetPanState?.didBegin == false, + visibilityFraction: 1.0 - abs(panFraction + cubeAdditionalRotationFraction), presentController: { [weak self] c in guard let self, let environment = self.environment else { return @@ -641,14 +657,14 @@ private final class StoryContainerScreenComponent: Component { } )), environment: {}, - containerSize: itemContainerSize + containerSize: itemSetContainerSize ) if i == focusedIndex { contentDerivedBottomInset = itemSetView.externalState.derivedBottomInset } - let itemFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - itemContainerSize.width) / 2.0), y: floorToScreenPixels((availableSize.height - itemContainerSize.height) / 2.0)), size: itemContainerSize) + let itemFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - itemSetContainerSize.width) / 2.0), y: floorToScreenPixels((availableSize.height - itemSetContainerSize.height) / 2.0)), size: itemSetContainerSize) if let itemSetComponentView = itemSetView.view.view { if itemSetView.superview == nil { self.addSubview(itemSetView) @@ -666,13 +682,25 @@ private final class StoryContainerScreenComponent: Component { itemSetTransition.setPosition(view: itemSetComponentView, position: CGRect(origin: CGPoint(), size: itemFrame.size).center) itemSetTransition.setBounds(view: itemSetComponentView, bounds: CGRect(origin: CGPoint(), size: itemFrame.size)) - itemSetTransition.setPosition(layer: itemSetView.tintLayer, position: CGRect(origin: CGPoint(), size: itemFrame.size).center) - itemSetTransition.setBounds(layer: itemSetView.tintLayer, bounds: CGRect(origin: CGPoint(), size: itemFrame.size)) + let itemTintSize: CGSize + if case .regular = environment.metrics.widthClass { + itemTintSize = itemSetView.externalState.derivedMediaSize + } else { + itemTintSize = itemFrame.size + } + + itemSetTransition.setPosition(layer: itemSetView.tintLayer, position: CGRect(origin: CGPoint(), size: itemTintSize).center) + itemSetTransition.setBounds(layer: itemSetView.tintLayer, bounds: CGRect(origin: CGPoint(), size: itemTintSize)) let perspectiveConstant: CGFloat = 500.0 let width = itemFrame.width - let sideDistance: CGFloat = 40.0 + let sideDistance: CGFloat + if case .regular = environment.metrics.widthClass { + sideDistance = 0.0 + } else { + sideDistance = 40.0 + } let sideAngle_d: CGFloat = -pow(perspectiveConstant, 2)*pow(sideDistance, 2) let sideAngle_e: CGFloat = pow(perspectiveConstant, 2)*pow(width, 2) @@ -713,21 +741,7 @@ private final class StoryContainerScreenComponent: Component { return targetTransform } - - let cubeAdditionalRotationFraction: CGFloat - if i == focusedIndex { - cubeAdditionalRotationFraction = 0.0 - } else if i < focusedIndex { - cubeAdditionalRotationFraction = -1.0 - } else { - cubeAdditionalRotationFraction = 1.0 - } - - var panFraction: CGFloat = 0.0 - if let itemSetPanState = self.itemSetPanState { - panFraction = -itemSetPanState.fraction - } - + Transition.immediate.setTransform(view: itemSetComponentView, transform: faceTransform) Transition.immediate.setTransform(layer: itemSetView.tintLayer, transform: faceTransform) diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift index bb44761533..ff5eecd2ac 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift @@ -21,6 +21,7 @@ import AvatarNode public final class StoryItemSetContainerComponent: Component { public final class ExternalState { public fileprivate(set) var derivedBottomInset: CGFloat = 0.0 + public fileprivate(set) var derivedMediaSize: CGSize = .zero public init() { } @@ -39,8 +40,10 @@ public final class StoryItemSetContainerComponent: Component { public let containerInsets: UIEdgeInsets public let safeInsets: UIEdgeInsets public let inputHeight: CGFloat + public let metrics: LayoutMetrics public let isProgressPaused: Bool public let hideUI: Bool + public let visibilityFraction: CGFloat public let presentController: (ViewController) -> Void public let close: () -> Void public let navigate: (NavigationDirection) -> Void @@ -56,8 +59,10 @@ public final class StoryItemSetContainerComponent: Component { containerInsets: UIEdgeInsets, safeInsets: UIEdgeInsets, inputHeight: CGFloat, + metrics: LayoutMetrics, isProgressPaused: Bool, hideUI: Bool, + visibilityFraction: CGFloat, presentController: @escaping (ViewController) -> Void, close: @escaping () -> Void, navigate: @escaping (NavigationDirection) -> Void, @@ -72,8 +77,10 @@ public final class StoryItemSetContainerComponent: Component { self.containerInsets = containerInsets self.safeInsets = safeInsets self.inputHeight = inputHeight + self.metrics = metrics self.isProgressPaused = isProgressPaused self.hideUI = hideUI + self.visibilityFraction = visibilityFraction self.presentController = presentController self.close = close self.navigate = navigate @@ -103,12 +110,18 @@ public final class StoryItemSetContainerComponent: Component { if lhs.inputHeight != rhs.inputHeight { return false } + if lhs.metrics != rhs.metrics { + return false + } if lhs.isProgressPaused != rhs.isProgressPaused { return false } if lhs.hideUI != rhs.hideUI { return false } + if lhs.visibilityFraction != rhs.visibilityFraction { + return false + } return true } @@ -1283,12 +1296,16 @@ public final class StoryItemSetContainerComponent: Component { self.itemLayout = itemLayout let inputPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - inputPanelBottomInset - inputPanelSize.height), size: inputPanelSize) + var inputPanelAlpha: CGFloat = focusedItem?.isMy == true ? 0.0 : 1.0 + if case .regular = component.metrics.widthClass { + inputPanelAlpha *= component.visibilityFraction + } if let inputPanelView = self.inputPanel.view { if inputPanelView.superview == nil { self.addSubview(inputPanelView) } transition.setFrame(view: inputPanelView, frame: inputPanelFrame) - transition.setAlpha(view: inputPanelView, alpha: focusedItem?.isMy == true ? 0.0 : 1.0) + transition.setAlpha(view: inputPanelView, alpha: inputPanelAlpha) } if let captionItem = self.captionItem, captionItem.itemId != component.slice.item.storyItem.id { @@ -1543,6 +1560,10 @@ public final class StoryItemSetContainerComponent: Component { } var footerPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - inputPanelBottomInset - footerPanelSize.height), size: footerPanelSize) + var footerPanelAlpha: CGFloat = (focusedItem?.isMy == true && !self.displayViewList) ? 1.0 : 0.0 + if case .regular = component.metrics.widthClass { + footerPanelAlpha *= component.visibilityFraction + } if self.displayViewList { footerPanelFrame.origin.y += footerPanelSize.height } @@ -1551,7 +1572,7 @@ public final class StoryItemSetContainerComponent: Component { self.addSubview(footerPanelView) } transition.setFrame(view: footerPanelView, frame: footerPanelFrame) - transition.setAlpha(view: footerPanelView, alpha: (focusedItem?.isMy == true && !self.displayViewList) ? 1.0 : 0.0) + transition.setAlpha(view: footerPanelView, alpha: footerPanelAlpha) } let bottomGradientHeight = inputPanelSize.height + 32.0 @@ -1650,6 +1671,7 @@ public final class StoryItemSetContainerComponent: Component { } } + component.externalState.derivedMediaSize = contentFrame.size component.externalState.derivedBottomInset = availableSize.height - min(inputPanelFrame.minY, contentFrame.maxY) return contentSize diff --git a/submodules/TelegramUI/Sources/FetchVideoMediaResource.swift b/submodules/TelegramUI/Sources/FetchVideoMediaResource.swift index 05d51330e7..a8b5699f2e 100644 --- a/submodules/TelegramUI/Sources/FetchVideoMediaResource.swift +++ b/submodules/TelegramUI/Sources/FetchVideoMediaResource.swift @@ -8,6 +8,7 @@ import FFMpegBinding import LocalMediaResources import LegacyMediaPickerUI import MediaEditor +import Photos private final class AVURLAssetCopyItem: MediaResourceDataFetchCopyLocalItem { private let url: URL @@ -268,10 +269,22 @@ public func fetchVideoLibraryMediaResource(account: Account, resource: VideoLibr var value = stat() if stat(tempFile.path, &value) == 0 { let remuxedTempFile = TempBox.shared.tempFile(fileName: "video.mp4") - if let size = fileSize(tempFile.path), size <= 32 * 1024 * 1024, FFMpegRemuxer.remux(tempFile.path, to: remuxedTempFile.path) { + if !"".isEmpty, let size = fileSize(tempFile.path), size <= 32 * 1024 * 1024, FFMpegRemuxer.remux(tempFile.path, to: remuxedTempFile.path) { TempBox.shared.dispose(tempFile) subscriber.putNext(.moveTempFile(file: remuxedTempFile)) } else { + let tempVideoPath = NSTemporaryDirectory() + "\(Int64.random(in: Int64.min ... Int64.max)).mp4" + if let _ = try? FileManager.default.copyItem(atPath: tempFile.path, toPath: tempVideoPath) { + PHPhotoLibrary.shared().performChanges({ + PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: URL(fileURLWithPath: tempVideoPath)) + }, completionHandler: { _, error in + if let error = error { + print("\(error)") + } + let _ = try? FileManager.default.removeItem(atPath: tempVideoPath) + }) + } + TempBox.shared.dispose(remuxedTempFile) if let data = try? Data(contentsOf: URL(fileURLWithPath: tempFile.path), options: [.mappedRead]) { var range: Range? @@ -424,7 +437,7 @@ func fetchLocalFileVideoMediaResource(account: Account, resource: LocalFileVideo var value = stat() if stat(tempFile.path, &value) == 0 { let remuxedTempFile = TempBox.shared.tempFile(fileName: "video.mp4") - if let size = fileSize(tempFile.path), size <= 32 * 1024 * 1024, FFMpegRemuxer.remux(tempFile.path, to: remuxedTempFile.path) { + if !"".isEmpty, let size = fileSize(tempFile.path), size <= 32 * 1024 * 1024, FFMpegRemuxer.remux(tempFile.path, to: remuxedTempFile.path) { TempBox.shared.dispose(tempFile) subscriber.putNext(.moveTempFile(file: remuxedTempFile)) } else {