Camera and editor improvements

This commit is contained in:
Ilya Laktyushin 2023-06-05 18:12:58 +04:00
parent 9ae260945c
commit c3ed819d01
3 changed files with 82 additions and 33 deletions

View File

@ -518,7 +518,19 @@ private final class StoryContainerScreenComponent: Component {
let slice = currentSlices[i] 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 { if let itemSetPanState = self.itemSetPanState {
panFraction = -itemSetPanState.fraction
if self.visibleItemSetViews[slice.peer.id] != nil { if self.visibleItemSetViews[slice.peer.id] != nil {
isItemVisible = true isItemVisible = true
} }
@ -543,14 +555,16 @@ private final class StoryContainerScreenComponent: Component {
self.visibleItemSetViews[slice.peer.id] = itemSetView 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 { if case .regular = environment.metrics.widthClass {
let availableHeight = availableSize.height - max(45.0, environment.safeInsets.bottom) * 2.0 let availableHeight = min(1080.0, availableSize.height - max(45.0, environment.safeInsets.bottom) * 2.0)
let mediaHeight = min(1040.0, availableHeight - 90.0) let mediaHeight = availableHeight - 40.0
let mediaWidth = floorToScreenPixels(mediaHeight * 0.5625) let mediaWidth = floor(mediaHeight * 0.5625)
itemContainerSize = CGSize(width: mediaWidth, height: availableHeight) itemSetContainerSize = CGSize(width: mediaWidth, height: availableHeight)
} else { itemSetContainerTopInset = 0.0
itemContainerSize = availableSize itemSetContainerSafeInsets.bottom = 0.0
} }
let _ = itemSetView.view.update( let _ = itemSetView.view.update(
@ -561,11 +575,13 @@ private final class StoryContainerScreenComponent: Component {
slice: slice, slice: slice,
theme: environment.theme, theme: environment.theme,
strings: environment.strings, strings: environment.strings,
containerInsets: UIEdgeInsets(top: environment.statusBarHeight + 12.0, left: 0.0, bottom: environment.inputHeight, right: 0.0), containerInsets: UIEdgeInsets(top: itemSetContainerTopInset, left: 0.0, bottom: environment.inputHeight, right: 0.0),
safeInsets: environment.safeInsets, safeInsets: itemSetContainerSafeInsets,
inputHeight: environment.inputHeight, inputHeight: environment.inputHeight,
metrics: environment.metrics,
isProgressPaused: isProgressPaused || i != focusedIndex, isProgressPaused: isProgressPaused || i != focusedIndex,
hideUI: i == focusedIndex && self.itemSetPanState?.didBegin == false, hideUI: i == focusedIndex && self.itemSetPanState?.didBegin == false,
visibilityFraction: 1.0 - abs(panFraction + cubeAdditionalRotationFraction),
presentController: { [weak self] c in presentController: { [weak self] c in
guard let self, let environment = self.environment else { guard let self, let environment = self.environment else {
return return
@ -641,14 +657,14 @@ private final class StoryContainerScreenComponent: Component {
} }
)), )),
environment: {}, environment: {},
containerSize: itemContainerSize containerSize: itemSetContainerSize
) )
if i == focusedIndex { if i == focusedIndex {
contentDerivedBottomInset = itemSetView.externalState.derivedBottomInset 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 let itemSetComponentView = itemSetView.view.view {
if itemSetView.superview == nil { if itemSetView.superview == nil {
self.addSubview(itemSetView) 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.setPosition(view: itemSetComponentView, position: CGRect(origin: CGPoint(), size: itemFrame.size).center)
itemSetTransition.setBounds(view: itemSetComponentView, bounds: CGRect(origin: CGPoint(), size: itemFrame.size)) itemSetTransition.setBounds(view: itemSetComponentView, bounds: CGRect(origin: CGPoint(), size: itemFrame.size))
itemSetTransition.setPosition(layer: itemSetView.tintLayer, position: CGRect(origin: CGPoint(), size: itemFrame.size).center) let itemTintSize: CGSize
itemSetTransition.setBounds(layer: itemSetView.tintLayer, bounds: CGRect(origin: CGPoint(), size: itemFrame.size)) 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 perspectiveConstant: CGFloat = 500.0
let width = itemFrame.width 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_d: CGFloat = -pow(perspectiveConstant, 2)*pow(sideDistance, 2)
let sideAngle_e: CGFloat = pow(perspectiveConstant, 2)*pow(width, 2) let sideAngle_e: CGFloat = pow(perspectiveConstant, 2)*pow(width, 2)
@ -713,21 +741,7 @@ private final class StoryContainerScreenComponent: Component {
return targetTransform 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(view: itemSetComponentView, transform: faceTransform)
Transition.immediate.setTransform(layer: itemSetView.tintLayer, transform: faceTransform) Transition.immediate.setTransform(layer: itemSetView.tintLayer, transform: faceTransform)

View File

@ -21,6 +21,7 @@ import AvatarNode
public final class StoryItemSetContainerComponent: Component { public final class StoryItemSetContainerComponent: Component {
public final class ExternalState { public final class ExternalState {
public fileprivate(set) var derivedBottomInset: CGFloat = 0.0 public fileprivate(set) var derivedBottomInset: CGFloat = 0.0
public fileprivate(set) var derivedMediaSize: CGSize = .zero
public init() { public init() {
} }
@ -39,8 +40,10 @@ public final class StoryItemSetContainerComponent: Component {
public let containerInsets: UIEdgeInsets public let containerInsets: UIEdgeInsets
public let safeInsets: UIEdgeInsets public let safeInsets: UIEdgeInsets
public let inputHeight: CGFloat public let inputHeight: CGFloat
public let metrics: LayoutMetrics
public let isProgressPaused: Bool public let isProgressPaused: Bool
public let hideUI: Bool public let hideUI: Bool
public let visibilityFraction: CGFloat
public let presentController: (ViewController) -> Void public let presentController: (ViewController) -> Void
public let close: () -> Void public let close: () -> Void
public let navigate: (NavigationDirection) -> Void public let navigate: (NavigationDirection) -> Void
@ -56,8 +59,10 @@ public final class StoryItemSetContainerComponent: Component {
containerInsets: UIEdgeInsets, containerInsets: UIEdgeInsets,
safeInsets: UIEdgeInsets, safeInsets: UIEdgeInsets,
inputHeight: CGFloat, inputHeight: CGFloat,
metrics: LayoutMetrics,
isProgressPaused: Bool, isProgressPaused: Bool,
hideUI: Bool, hideUI: Bool,
visibilityFraction: CGFloat,
presentController: @escaping (ViewController) -> Void, presentController: @escaping (ViewController) -> Void,
close: @escaping () -> Void, close: @escaping () -> Void,
navigate: @escaping (NavigationDirection) -> Void, navigate: @escaping (NavigationDirection) -> Void,
@ -72,8 +77,10 @@ public final class StoryItemSetContainerComponent: Component {
self.containerInsets = containerInsets self.containerInsets = containerInsets
self.safeInsets = safeInsets self.safeInsets = safeInsets
self.inputHeight = inputHeight self.inputHeight = inputHeight
self.metrics = metrics
self.isProgressPaused = isProgressPaused self.isProgressPaused = isProgressPaused
self.hideUI = hideUI self.hideUI = hideUI
self.visibilityFraction = visibilityFraction
self.presentController = presentController self.presentController = presentController
self.close = close self.close = close
self.navigate = navigate self.navigate = navigate
@ -103,12 +110,18 @@ public final class StoryItemSetContainerComponent: Component {
if lhs.inputHeight != rhs.inputHeight { if lhs.inputHeight != rhs.inputHeight {
return false return false
} }
if lhs.metrics != rhs.metrics {
return false
}
if lhs.isProgressPaused != rhs.isProgressPaused { if lhs.isProgressPaused != rhs.isProgressPaused {
return false return false
} }
if lhs.hideUI != rhs.hideUI { if lhs.hideUI != rhs.hideUI {
return false return false
} }
if lhs.visibilityFraction != rhs.visibilityFraction {
return false
}
return true return true
} }
@ -1283,12 +1296,16 @@ public final class StoryItemSetContainerComponent: Component {
self.itemLayout = itemLayout self.itemLayout = itemLayout
let inputPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - inputPanelBottomInset - inputPanelSize.height), size: inputPanelSize) 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 let inputPanelView = self.inputPanel.view {
if inputPanelView.superview == nil { if inputPanelView.superview == nil {
self.addSubview(inputPanelView) self.addSubview(inputPanelView)
} }
transition.setFrame(view: inputPanelView, frame: inputPanelFrame) 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 { 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 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 { if self.displayViewList {
footerPanelFrame.origin.y += footerPanelSize.height footerPanelFrame.origin.y += footerPanelSize.height
} }
@ -1551,7 +1572,7 @@ public final class StoryItemSetContainerComponent: Component {
self.addSubview(footerPanelView) self.addSubview(footerPanelView)
} }
transition.setFrame(view: footerPanelView, frame: footerPanelFrame) 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 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) component.externalState.derivedBottomInset = availableSize.height - min(inputPanelFrame.minY, contentFrame.maxY)
return contentSize return contentSize

View File

@ -8,6 +8,7 @@ import FFMpegBinding
import LocalMediaResources import LocalMediaResources
import LegacyMediaPickerUI import LegacyMediaPickerUI
import MediaEditor import MediaEditor
import Photos
private final class AVURLAssetCopyItem: MediaResourceDataFetchCopyLocalItem { private final class AVURLAssetCopyItem: MediaResourceDataFetchCopyLocalItem {
private let url: URL private let url: URL
@ -268,10 +269,22 @@ public func fetchVideoLibraryMediaResource(account: Account, resource: VideoLibr
var value = stat() var value = stat()
if stat(tempFile.path, &value) == 0 { if stat(tempFile.path, &value) == 0 {
let remuxedTempFile = TempBox.shared.tempFile(fileName: "video.mp4") 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) TempBox.shared.dispose(tempFile)
subscriber.putNext(.moveTempFile(file: remuxedTempFile)) subscriber.putNext(.moveTempFile(file: remuxedTempFile))
} else { } 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) TempBox.shared.dispose(remuxedTempFile)
if let data = try? Data(contentsOf: URL(fileURLWithPath: tempFile.path), options: [.mappedRead]) { if let data = try? Data(contentsOf: URL(fileURLWithPath: tempFile.path), options: [.mappedRead]) {
var range: Range<Int64>? var range: Range<Int64>?
@ -424,7 +437,7 @@ func fetchLocalFileVideoMediaResource(account: Account, resource: LocalFileVideo
var value = stat() var value = stat()
if stat(tempFile.path, &value) == 0 { if stat(tempFile.path, &value) == 0 {
let remuxedTempFile = TempBox.shared.tempFile(fileName: "video.mp4") 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) TempBox.shared.dispose(tempFile)
subscriber.putNext(.moveTempFile(file: remuxedTempFile)) subscriber.putNext(.moveTempFile(file: remuxedTempFile))
} else { } else {