mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit '3778357baa5dab114c14f7dfe5fc9aaeb835cff5'
# Conflicts: # Telegram/Telegram-iOS/en.lproj/Localizable.strings
This commit is contained in:
commit
384d295e75
@ -13300,6 +13300,19 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"Notification.Gift" = "Gift";
|
"Notification.Gift" = "Gift";
|
||||||
|
|
||||||
|
"WebBrowser.PassExistsError" = "This pass is already added to Wallet.";
|
||||||
|
|
||||||
|
"Chat.VideoProcessingInfo" = "The video will be published once converted and optimized.";
|
||||||
|
|
||||||
|
"Camera.CollageManagementTooltip" = "Tap a tile to delete or reorder it.";
|
||||||
|
"Camera.CollageReorderingInfo" = "Hold and drag tiles to reorder them.";
|
||||||
|
|
||||||
|
"MediaPicker.InvertCaptionTooltip" = "Tap here to move caption up.";
|
||||||
|
"MediaPicker.InvertCaption.Updated.Up.Title" = "Caption moved up";
|
||||||
|
"MediaPicker.InvertCaption.Updated.Up.Text" = "Text will be shown above the media.";
|
||||||
|
"MediaPicker.InvertCaption.Updated.Down.Title" = "Caption moved down";
|
||||||
|
"MediaPicker.InvertCaption.Updated.Down.Text" = "Text will be shown below the media.";
|
||||||
|
|
||||||
"AffiliateSetup.AlertTerminate.Title" = "Warning";
|
"AffiliateSetup.AlertTerminate.Title" = "Warning";
|
||||||
"AffiliateSetup.AlertTerminate.Text" = "If you end your affiliate program:\n\n• Any referral links already shared will be disabled in 24 hours.\n\n• All participating affiliates will be notified.\n\n• You will be able to start a new affiliate program only in 24 hours.";
|
"AffiliateSetup.AlertTerminate.Text" = "If you end your affiliate program:\n\n• Any referral links already shared will be disabled in 24 hours.\n\n• All participating affiliates will be notified.\n\n• You will be able to start a new affiliate program only in 24 hours.";
|
||||||
"AffiliateSetup.AlertTerminate.Action" = "End Anyway";
|
"AffiliateSetup.AlertTerminate.Action" = "End Anyway";
|
||||||
|
@ -896,8 +896,7 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
|||||||
if let data = try? Data(contentsOf: url), let pass = try? PKPass(data: data) {
|
if let data = try? Data(contentsOf: url), let pass = try? PKPass(data: data) {
|
||||||
let passLibrary = PKPassLibrary()
|
let passLibrary = PKPassLibrary()
|
||||||
if passLibrary.containsPass(pass) {
|
if passLibrary.containsPass(pass) {
|
||||||
//TODO:localize
|
let alertController = textAlertController(context: self.context, updatedPresentationData: nil, title: nil, text: self.presentationData.strings.WebBrowser_PassExistsError, actions: [TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_OK, action: {})])
|
||||||
let alertController = textAlertController(context: self.context, updatedPresentationData: nil, title: nil, text: "This pass is already added to Wallet.", actions: [TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_OK, action: {})])
|
|
||||||
self.present(alertController, nil)
|
self.present(alertController, nil)
|
||||||
} else if let controller = PKAddPassesViewController(pass: pass) {
|
} else if let controller = PKAddPassesViewController(pass: pass) {
|
||||||
self.getNavigationController()?.view.window?.rootViewController?.present(controller, animated: true)
|
self.getNavigationController()?.view.window?.rootViewController?.present(controller, animated: true)
|
||||||
|
@ -438,6 +438,7 @@ final class InnerTextSelectionTipContainerNode: ASDisplayNode {
|
|||||||
icon = nil
|
icon = nil
|
||||||
isUserInteractionEnabled = action != nil
|
isUserInteractionEnabled = action != nil
|
||||||
case let .starsReactions(topCount):
|
case let .starsReactions(topCount):
|
||||||
|
//TODO:localize
|
||||||
self.action = nil
|
self.action = nil
|
||||||
self.text = "Send \(topCount) or more to highlight your profile"
|
self.text = "Send \(topCount) or more to highlight your profile"
|
||||||
self.targetSelectionIndex = nil
|
self.targetSelectionIndex = nil
|
||||||
@ -445,14 +446,13 @@ final class InnerTextSelectionTipContainerNode: ASDisplayNode {
|
|||||||
isUserInteractionEnabled = action != nil
|
isUserInteractionEnabled = action != nil
|
||||||
case .videoProcessing:
|
case .videoProcessing:
|
||||||
self.action = nil
|
self.action = nil
|
||||||
self.text = "The video will be published once converted and optimized."
|
self.text = self.presentationData.strings.Chat_VideoProcessingInfo
|
||||||
self.targetSelectionIndex = nil
|
self.targetSelectionIndex = nil
|
||||||
icon = nil
|
icon = nil
|
||||||
isUserInteractionEnabled = action != nil
|
isUserInteractionEnabled = action != nil
|
||||||
case .collageReordering:
|
case .collageReordering:
|
||||||
//TODO:localize
|
|
||||||
self.action = nil
|
self.action = nil
|
||||||
self.text = "Hold and drag tiles to reorder them."
|
self.text = self.presentationData.strings.Camera_CollageReorderingInfo
|
||||||
self.targetSelectionIndex = nil
|
self.targetSelectionIndex = nil
|
||||||
icon = UIImage(bundleImageName: "Chat/Context Menu/Tip")
|
icon = UIImage(bundleImageName: "Chat/Context Menu/Tip")
|
||||||
}
|
}
|
||||||
|
@ -199,6 +199,7 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
|
|||||||
case dismissedBusinessIntroBadge = 72
|
case dismissedBusinessIntroBadge = 72
|
||||||
case dismissedBusinessLinksBadge = 73
|
case dismissedBusinessLinksBadge = 73
|
||||||
case dismissedBusinessChatbotsBadge = 74
|
case dismissedBusinessChatbotsBadge = 74
|
||||||
|
case captionAboveMediaTooltip = 75
|
||||||
|
|
||||||
var key: ValueBoxKey {
|
var key: ValueBoxKey {
|
||||||
let v = ValueBoxKey(length: 4)
|
let v = ValueBoxKey(length: 4)
|
||||||
@ -534,6 +535,10 @@ private struct ApplicationSpecificNoticeKeys {
|
|||||||
static func dismissedBusinessChatbotsBadge() -> NoticeEntryKey {
|
static func dismissedBusinessChatbotsBadge() -> NoticeEntryKey {
|
||||||
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.dismissedBusinessChatbotsBadge.key)
|
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.dismissedBusinessChatbotsBadge.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func captionAboveMediaTooltip() -> NoticeEntryKey {
|
||||||
|
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.captionAboveMediaTooltip.key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ApplicationSpecificNotice {
|
public struct ApplicationSpecificNotice {
|
||||||
@ -2246,4 +2251,31 @@ public struct ApplicationSpecificNotice {
|
|||||||
}
|
}
|
||||||
|> take(1)
|
|> take(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func getCaptionAboveMediaTooltip(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Int32, NoError> {
|
||||||
|
return accountManager.transaction { transaction -> Int32 in
|
||||||
|
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.captionAboveMediaTooltip())?.get(ApplicationSpecificCounterNotice.self) {
|
||||||
|
return value.value
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func incrementCaptionAboveMediaTooltip(accountManager: AccountManager<TelegramAccountManagerTypes>, count: Int = 1) -> Signal<Int, NoError> {
|
||||||
|
return accountManager.transaction { transaction -> Int in
|
||||||
|
var currentValue: Int32 = 0
|
||||||
|
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.captionAboveMediaTooltip())?.get(ApplicationSpecificCounterNotice.self) {
|
||||||
|
currentValue = value.value
|
||||||
|
}
|
||||||
|
let previousValue = currentValue
|
||||||
|
currentValue += Int32(count)
|
||||||
|
|
||||||
|
if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) {
|
||||||
|
transaction.setNotice(ApplicationSpecificNoticeKeys.captionAboveMediaTooltip(), entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Int(previousValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -568,19 +568,33 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func toggleCollageCamera() {
|
func toggleCollageCamera() {
|
||||||
guard let controller = self.getController(), let _ = controller.camera else {
|
guard let controller = self.getController(), let camera = controller.camera else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
let currentTimestamp = CACurrentMediaTime()
|
||||||
|
if let lastDualCameraTimestamp = self.lastDualCameraTimestamp, currentTimestamp - lastDualCameraTimestamp < 1.5 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let lastFlipTimestamp = self.lastFlipTimestamp, currentTimestamp - lastFlipTimestamp < 1.0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.lastDualCameraTimestamp = currentTimestamp
|
||||||
|
|
||||||
controller.node.dismissAllTooltips()
|
controller.node.dismissAllTooltips()
|
||||||
|
|
||||||
|
if controller.cameraState.isDualCameraEnabled {
|
||||||
|
camera.setDualCameraEnabled(false)
|
||||||
|
}
|
||||||
|
|
||||||
if controller.cameraState.isCollageEnabled {
|
if controller.cameraState.isCollageEnabled {
|
||||||
self.displayingCollageSelection = !self.displayingCollageSelection
|
self.displayingCollageSelection = !self.displayingCollageSelection
|
||||||
self.updated(transition: .spring(duration: 0.3))
|
self.updated(transition: .spring(duration: 0.3))
|
||||||
} else {
|
} else {
|
||||||
let isEnabled = !controller.cameraState.isCollageEnabled
|
let isEnabled = !controller.cameraState.isCollageEnabled
|
||||||
self.displayingCollageSelection = isEnabled
|
self.displayingCollageSelection = isEnabled
|
||||||
controller.updateCameraState({ $0.updatedIsCollageEnabled(isEnabled).updatedCollageProgress(0.0) }, transition: .spring(duration: 0.3))
|
controller.updateCameraState({
|
||||||
|
$0.updatedIsCollageEnabled(isEnabled).updatedCollageProgress(0.0).updatedIsDualCameraEnabled(false)
|
||||||
|
}, transition: .spring(duration: 0.3))
|
||||||
}
|
}
|
||||||
self.hapticFeedback.impact(.light)
|
self.hapticFeedback.impact(.light)
|
||||||
}
|
}
|
||||||
@ -635,9 +649,8 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||||||
self.displayingCollageSelection = false
|
self.displayingCollageSelection = false
|
||||||
self.updated(transition: .spring(duration: 0.3))
|
self.updated(transition: .spring(duration: 0.3))
|
||||||
|
|
||||||
//TODO:localize
|
|
||||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
let tooltipController = UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: "Tap a tile to delete or reorder it.", timeout: 3.0, customUndoText: nil), elevatedLayout: false, action: { _ in
|
let tooltipController = UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.Camera_CollageManagementTooltip, timeout: 2.0, customUndoText: nil), elevatedLayout: false, action: { _ in
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
controller.present(tooltipController, in: .current)
|
controller.present(tooltipController, in: .current)
|
||||||
@ -1279,68 +1292,66 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||||||
nextButtonX -= dualButton.size.width + 16.0
|
nextButtonX -= dualButton.size.width + 16.0
|
||||||
}
|
}
|
||||||
|
|
||||||
if !component.cameraState.isDualCameraEnabled {
|
let collageButton = collageButton.update(
|
||||||
let collageButton = collageButton.update(
|
component: CameraButton(
|
||||||
component: CameraButton(
|
content: AnyComponentWithIdentity(
|
||||||
content: AnyComponentWithIdentity(
|
id: "collage",
|
||||||
id: "collage",
|
component: AnyComponent(
|
||||||
component: AnyComponent(
|
CollageIconComponent(
|
||||||
CollageIconComponent(
|
grid: component.cameraState.collageGrid,
|
||||||
grid: component.cameraState.collageGrid,
|
crossed: false,
|
||||||
crossed: false,
|
isSelected: component.cameraState.isCollageEnabled,
|
||||||
isSelected: component.cameraState.isCollageEnabled,
|
tintColor: controlsTintColor
|
||||||
tintColor: controlsTintColor
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
),
|
)
|
||||||
action: { [weak state] in
|
),
|
||||||
if let state {
|
action: { [weak state] in
|
||||||
state.toggleCollageCamera()
|
if let state {
|
||||||
}
|
state.toggleCollageCamera()
|
||||||
}
|
}
|
||||||
).tagged(collageButtonTag),
|
}
|
||||||
availableSize: CGSize(width: 40.0, height: 40.0),
|
).tagged(collageButtonTag),
|
||||||
|
availableSize: CGSize(width: 40.0, height: 40.0),
|
||||||
|
transition: .immediate
|
||||||
|
)
|
||||||
|
var collageButtonX = nextButtonX
|
||||||
|
if rightMostButtonWidth.isZero {
|
||||||
|
collageButtonX = availableSize.width - topControlInset - collageButton.size.width / 2.0 - 5.0
|
||||||
|
}
|
||||||
|
context.add(collageButton
|
||||||
|
.position(CGPoint(x: collageButtonX, y: max(environment.statusBarHeight + 5.0, environment.safeInsets.top + topControlInset) + collageButton.size.height / 2.0 + 2.0))
|
||||||
|
.appear(.default(scale: true))
|
||||||
|
.disappear(.default(scale: true))
|
||||||
|
.shadow(Shadow(color: UIColor(white: 0.0, alpha: 0.25), radius: 3.0, offset: .zero))
|
||||||
|
)
|
||||||
|
nextButtonX -= collageButton.size.width
|
||||||
|
|
||||||
|
if state.displayingCollageSelection {
|
||||||
|
let collageCarousel = collageCarousel.update(
|
||||||
|
component: CollageIconCarouselComponent(
|
||||||
|
grids: collageGrids.filter { $0 != component.cameraState.collageGrid },
|
||||||
|
selected: { [weak state] grid in
|
||||||
|
state?.updateCollageGrid(grid)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
availableSize: CGSize(width: nextButtonX + 4.0, height: 40.0),
|
||||||
transition: .immediate
|
transition: .immediate
|
||||||
)
|
)
|
||||||
var collageButtonX = nextButtonX
|
context.add(collageCarousel
|
||||||
if rightMostButtonWidth.isZero {
|
.position(CGPoint(x: collageCarousel.size.width / 2.0, y: max(environment.statusBarHeight + 5.0, environment.safeInsets.top + topControlInset) + collageCarousel.size.height / 2.0 + 2.0))
|
||||||
collageButtonX = availableSize.width - topControlInset - collageButton.size.width / 2.0 - 5.0
|
.appear(ComponentTransition.Appear({ _, view, transition in
|
||||||
}
|
if let view = view as? CollageIconCarouselComponent.View, !transition.animation.isImmediate {
|
||||||
context.add(collageButton
|
view.animateIn()
|
||||||
.position(CGPoint(x: collageButtonX, y: max(environment.statusBarHeight + 5.0, environment.safeInsets.top + topControlInset) + collageButton.size.height / 2.0 + 2.0))
|
}
|
||||||
.appear(.default(scale: true))
|
}))
|
||||||
.disappear(.default(scale: true))
|
.disappear(ComponentTransition.Disappear({ view, transition, completion in
|
||||||
.shadow(Shadow(color: UIColor(white: 0.0, alpha: 0.25), radius: 3.0, offset: .zero))
|
if let view = view as? CollageIconCarouselComponent.View, !transition.animation.isImmediate {
|
||||||
|
view.animateOut(completion: completion)
|
||||||
|
} else {
|
||||||
|
completion()
|
||||||
|
}
|
||||||
|
}))
|
||||||
)
|
)
|
||||||
nextButtonX -= collageButton.size.width
|
|
||||||
|
|
||||||
if state.displayingCollageSelection {
|
|
||||||
let collageCarousel = collageCarousel.update(
|
|
||||||
component: CollageIconCarouselComponent(
|
|
||||||
grids: collageGrids.filter { $0 != component.cameraState.collageGrid },
|
|
||||||
selected: { [weak state] grid in
|
|
||||||
state?.updateCollageGrid(grid)
|
|
||||||
}
|
|
||||||
),
|
|
||||||
availableSize: CGSize(width: nextButtonX + 4.0, height: 40.0),
|
|
||||||
transition: .immediate
|
|
||||||
)
|
|
||||||
context.add(collageCarousel
|
|
||||||
.position(CGPoint(x: collageCarousel.size.width / 2.0, y: max(environment.statusBarHeight + 5.0, environment.safeInsets.top + topControlInset) + collageCarousel.size.height / 2.0 + 2.0))
|
|
||||||
.appear(ComponentTransition.Appear({ _, view, transition in
|
|
||||||
if let view = view as? CollageIconCarouselComponent.View, !transition.animation.isImmediate {
|
|
||||||
view.animateIn()
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
.disappear(ComponentTransition.Disappear({ view, transition, completion in
|
|
||||||
if let view = view as? CollageIconCarouselComponent.View, !transition.animation.isImmediate {
|
|
||||||
view.animateOut(completion: completion)
|
|
||||||
} else {
|
|
||||||
completion()
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -299,7 +299,7 @@ final class CameraVideoLayer: MetalEngineSubjectLayer, MetalEngineSubject {
|
|||||||
|
|
||||||
encoder.setFragmentTexture(blurredTexture, index: 0)
|
encoder.setFragmentTexture(blurredTexture, index: 0)
|
||||||
|
|
||||||
var brightness: Float = 0.85
|
var brightness: Float = 0.95
|
||||||
var saturation: Float = 1.3
|
var saturation: Float = 1.3
|
||||||
var overlay: SIMD4<Float> = SIMD4<Float>()
|
var overlay: SIMD4<Float> = SIMD4<Float>()
|
||||||
encoder.setFragmentBytes(&brightness, length: 4, index: 0)
|
encoder.setFragmentBytes(&brightness, length: 4, index: 0)
|
||||||
|
@ -24,6 +24,7 @@ swift_library(
|
|||||||
"//submodules/UndoUI",
|
"//submodules/UndoUI",
|
||||||
"//submodules/TelegramUI/Components/MessageInputPanelComponent",
|
"//submodules/TelegramUI/Components/MessageInputPanelComponent",
|
||||||
"//submodules/TelegramUI/Components/LegacyMessageInputPanelInputView",
|
"//submodules/TelegramUI/Components/LegacyMessageInputPanelInputView",
|
||||||
|
"//submodules/TelegramNotices",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -15,6 +15,7 @@ import ContextUI
|
|||||||
import TooltipUI
|
import TooltipUI
|
||||||
import LegacyMessageInputPanelInputView
|
import LegacyMessageInputPanelInputView
|
||||||
import UndoUI
|
import UndoUI
|
||||||
|
import TelegramNotices
|
||||||
|
|
||||||
public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
@ -357,7 +358,6 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func toggleIsCaptionAbove() {
|
private func toggleIsCaptionAbove() {
|
||||||
//TODO:localize
|
|
||||||
self.currentIsCaptionAbove = !self.currentIsCaptionAbove
|
self.currentIsCaptionAbove = !self.currentIsCaptionAbove
|
||||||
self.captionIsAboveUpdated?(self.currentIsCaptionAbove)
|
self.captionIsAboveUpdated?(self.currentIsCaptionAbove)
|
||||||
self.update(transition: .animated(duration: 0.3, curve: .spring))
|
self.update(transition: .animated(duration: 0.3, curve: .spring))
|
||||||
@ -366,8 +366,8 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
|||||||
|
|
||||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
let title = self.currentIsCaptionAbove ? "Caption moved up" : "Caption moved down"
|
let title = self.currentIsCaptionAbove ? presentationData.strings.MediaPicker_InvertCaption_Updated_Up_Title : presentationData.strings.MediaPicker_InvertCaption_Updated_Down_Title
|
||||||
let text = self.currentIsCaptionAbove ? "Text will be shown above the media." : "Text will be shown below the media."
|
let text = self.currentIsCaptionAbove ? presentationData.strings.MediaPicker_InvertCaption_Updated_Up_Text : presentationData.strings.MediaPicker_InvertCaption_Updated_Down_Title
|
||||||
let animationName = self.currentIsCaptionAbove ? "message_preview_sort_above" : "message_preview_sort_below"
|
let animationName = self.currentIsCaptionAbove ? "message_preview_sort_above" : "message_preview_sort_below"
|
||||||
|
|
||||||
let controller = UndoOverlayController(
|
let controller = UndoOverlayController(
|
||||||
@ -498,30 +498,43 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
|||||||
}
|
}
|
||||||
self.dismissAllTooltips()
|
self.dismissAllTooltips()
|
||||||
|
|
||||||
let parentFrame = superview.convert(superview.bounds, to: nil)
|
|
||||||
let absoluteFrame = sourceView.convert(sourceView.bounds, to: nil).offsetBy(dx: -parentFrame.minX, dy: 0.0)
|
|
||||||
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX + 2.0, y: absoluteFrame.minY + 6.0), size: CGSize())
|
|
||||||
|
|
||||||
//TODO:localize
|
let _ = (ApplicationSpecificNotice.getCaptionAboveMediaTooltip(accountManager: self.context.sharedContext.accountManager)
|
||||||
let text = "Tap here to move caption up."
|
|> deliverOnMainQueue).start(next: { [weak self] count in
|
||||||
let tooltipController = TooltipScreen(
|
guard let self else {
|
||||||
account: self.context.account,
|
return
|
||||||
sharedContext: self.context.sharedContext,
|
|
||||||
text: .plain(text: text),
|
|
||||||
balancedTextLayout: false,
|
|
||||||
style: .customBlur(UIColor(rgb: 0x18181a), 4.0),
|
|
||||||
arrowStyle: .small,
|
|
||||||
icon: nil,
|
|
||||||
location: .point(location, .bottom),
|
|
||||||
displayDuration: .default,
|
|
||||||
inset: 4.0,
|
|
||||||
cornerRadius: 10.0,
|
|
||||||
shouldDismissOnTouch: { _, _ in
|
|
||||||
return .ignore
|
|
||||||
}
|
}
|
||||||
)
|
if count > 2 {
|
||||||
self.tooltipController = tooltipController
|
return
|
||||||
self.present(tooltipController)
|
}
|
||||||
|
|
||||||
|
let parentFrame = superview.convert(superview.bounds, to: nil)
|
||||||
|
let absoluteFrame = sourceView.convert(sourceView.bounds, to: nil).offsetBy(dx: -parentFrame.minX, dy: 0.0)
|
||||||
|
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX + 2.0, y: absoluteFrame.minY + 6.0), size: CGSize())
|
||||||
|
|
||||||
|
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
|
let tooltipController = TooltipScreen(
|
||||||
|
account: self.context.account,
|
||||||
|
sharedContext: self.context.sharedContext,
|
||||||
|
text: .plain(text: presentationData.strings.MediaPicker_InvertCaptionTooltip),
|
||||||
|
balancedTextLayout: false,
|
||||||
|
style: .customBlur(UIColor(rgb: 0x18181a), 4.0),
|
||||||
|
arrowStyle: .small,
|
||||||
|
icon: nil,
|
||||||
|
location: .point(location, .bottom),
|
||||||
|
displayDuration: .default,
|
||||||
|
inset: 4.0,
|
||||||
|
cornerRadius: 10.0,
|
||||||
|
shouldDismissOnTouch: { _, _ in
|
||||||
|
return .ignore
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.tooltipController = tooltipController
|
||||||
|
self.present(tooltipController)
|
||||||
|
|
||||||
|
let _ = ApplicationSpecificNotice.incrementCaptionAboveMediaTooltip(accountManager: self.context.sharedContext.accountManager).start()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
|
@ -1686,10 +1686,17 @@ public final class MediaEditor {
|
|||||||
public func setupCollage(_ items: [MediaEditor.Subject.VideoCollageItem]) {
|
public func setupCollage(_ items: [MediaEditor.Subject.VideoCollageItem]) {
|
||||||
let longestItem = longestCollageItem(items)
|
let longestItem = longestCollageItem(items)
|
||||||
var collage: [MediaEditorValues.VideoCollageItem] = []
|
var collage: [MediaEditorValues.VideoCollageItem] = []
|
||||||
|
|
||||||
|
var index = 0
|
||||||
|
var passedFirstVideo = false
|
||||||
|
var mainVideoIsMuted = false
|
||||||
|
|
||||||
for item in items {
|
for item in items {
|
||||||
var content: MediaEditorValues.VideoCollageItem.Content
|
var content: MediaEditorValues.VideoCollageItem.Content
|
||||||
|
var isVideo = false
|
||||||
if item.content == longestItem?.content {
|
if item.content == longestItem?.content {
|
||||||
content = .main
|
content = .main
|
||||||
|
isVideo = true
|
||||||
} else {
|
} else {
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .image(image):
|
case let .image(image):
|
||||||
@ -1700,23 +1707,38 @@ public final class MediaEditor {
|
|||||||
content = .imageFile(path: tempImagePath)
|
content = .imageFile(path: tempImagePath)
|
||||||
case let .video(path, _):
|
case let .video(path, _):
|
||||||
content = .videoFile(path: path)
|
content = .videoFile(path: path)
|
||||||
|
isVideo = true
|
||||||
case let .asset(asset):
|
case let .asset(asset):
|
||||||
content = .asset(localIdentifier: asset.localIdentifier, isVideo: asset.mediaType == .video)
|
content = .asset(localIdentifier: asset.localIdentifier, isVideo: asset.mediaType == .video)
|
||||||
|
isVideo = asset.mediaType == .video
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
collage.append(MediaEditorValues.VideoCollageItem(
|
let item = MediaEditorValues.VideoCollageItem(
|
||||||
content: content,
|
content: content,
|
||||||
frame: item.frame,
|
frame: item.frame,
|
||||||
videoTrimRange: nil,
|
videoTrimRange: nil,
|
||||||
videoOffset: nil,
|
videoOffset: nil,
|
||||||
videoVolume: nil
|
videoVolume: passedFirstVideo ? 0.0 : nil
|
||||||
))
|
)
|
||||||
|
collage.append(item)
|
||||||
|
if isVideo {
|
||||||
|
passedFirstVideo = true
|
||||||
|
}
|
||||||
|
index += 1
|
||||||
|
|
||||||
|
if item.content == .main, let videoVolume = item.videoVolume, videoVolume.isZero {
|
||||||
|
mainVideoIsMuted = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.updateValues(mode: .skipRendering) { values in
|
self.updateValues(mode: .skipRendering) { values in
|
||||||
return values.withUpdatedCollage(collage)
|
var values = values.withUpdatedCollage(collage)
|
||||||
|
if mainVideoIsMuted {
|
||||||
|
values = values.withUpdatedVideoVolume(0.0)
|
||||||
|
}
|
||||||
|
return values
|
||||||
}
|
}
|
||||||
|
|
||||||
self.setupAdditionalVideoPlayback()
|
self.setupAdditionalVideoPlayback()
|
||||||
self.updateAdditionalVideoPlaybackRange()
|
self.updateAdditionalVideoPlaybackRange()
|
||||||
}
|
}
|
||||||
@ -1766,21 +1788,20 @@ public final class MediaEditor {
|
|||||||
|
|
||||||
private func setupAdditionalVideoPlayback() {
|
private func setupAdditionalVideoPlayback() {
|
||||||
if !self.values.collage.isEmpty {
|
if !self.values.collage.isEmpty {
|
||||||
var signals: [Signal<(UniversalTextureSource.Input, AVPlayer?), NoError>] = []
|
var signals: [Signal<(UniversalTextureSource.Input, AVPlayer?, CGFloat?), NoError>] = []
|
||||||
|
|
||||||
for item in self.values.collage {
|
for item in self.values.collage {
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case .main:
|
case .main:
|
||||||
break
|
break
|
||||||
case let .imageFile(path):
|
case let .imageFile(path):
|
||||||
if let image = UIImage(contentsOfFile: path) {
|
if let image = UIImage(contentsOfFile: path) {
|
||||||
signals.append(.single((.image(image, item.frame), nil)))
|
signals.append(.single((.image(image, item.frame), nil, nil)))
|
||||||
}
|
}
|
||||||
case let .videoFile(path):
|
case let .videoFile(path):
|
||||||
let asset = AVURLAsset(url: URL(fileURLWithPath: path))
|
let asset = AVURLAsset(url: URL(fileURLWithPath: path))
|
||||||
let player = self.makePlayer(asset: asset)
|
let player = self.makePlayer(asset: asset)
|
||||||
if let playerItem = player.currentItem {
|
if let playerItem = player.currentItem {
|
||||||
signals.append(.single((.video(playerItem, item.frame), player)))
|
signals.append(.single((.video(playerItem, item.frame), player, item.videoVolume)))
|
||||||
}
|
}
|
||||||
case let .asset(localIdentifier, _):
|
case let .asset(localIdentifier, _):
|
||||||
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [localIdentifier], options: nil)
|
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [localIdentifier], options: nil)
|
||||||
@ -1798,7 +1819,7 @@ public final class MediaEditor {
|
|||||||
}
|
}
|
||||||
let player = self.makePlayer(asset: avAsset)
|
let player = self.makePlayer(asset: avAsset)
|
||||||
if let playerItem = player.currentItem {
|
if let playerItem = player.currentItem {
|
||||||
subscriber.putNext((.video(playerItem, item.frame), player))
|
subscriber.putNext((.video(playerItem, item.frame), player, item.videoVolume))
|
||||||
}
|
}
|
||||||
subscriber.putCompletion()
|
subscriber.putCompletion()
|
||||||
})
|
})
|
||||||
@ -1817,9 +1838,12 @@ public final class MediaEditor {
|
|||||||
var additionalInputs: [UniversalTextureSource.Input] = []
|
var additionalInputs: [UniversalTextureSource.Input] = []
|
||||||
var additionalPlayers: [AVPlayer] = []
|
var additionalPlayers: [AVPlayer] = []
|
||||||
|
|
||||||
for (input, player) in results {
|
for (input, player, volume) in results {
|
||||||
additionalInputs.append(input)
|
additionalInputs.append(input)
|
||||||
if let player {
|
if let player {
|
||||||
|
if let volume {
|
||||||
|
player.volume = Float(volume)
|
||||||
|
}
|
||||||
additionalPlayers.append(player)
|
additionalPlayers.append(player)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1861,23 +1885,41 @@ public final class MediaEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func collageItemIndexForTrackId(_ trackId: Int32) -> Int? {
|
public func collageItemIndexForTrackId(_ trackId: Int32) -> Int? {
|
||||||
var collageIndex = -1
|
var trackIdToIndex: [Int32: Int] = [:]
|
||||||
var trackIndex = -1
|
|
||||||
|
var index = 0
|
||||||
|
var trackIndex: Int32 = 0
|
||||||
for item in self.values.collage {
|
for item in self.values.collage {
|
||||||
if case .main = item.content {
|
if case .main = item.content {
|
||||||
trackIndex += 1
|
trackIdToIndex[0] = index
|
||||||
} else if case .videoFile = item.content {
|
} else {
|
||||||
trackIndex += 1
|
if item.content.isVideo {
|
||||||
} else if case .asset(_, true) = item.content {
|
trackIndex += 1
|
||||||
trackIndex += 1
|
trackIdToIndex[trackIndex] = index
|
||||||
}
|
}
|
||||||
collageIndex += 1
|
|
||||||
|
|
||||||
if trackIndex == trackId {
|
|
||||||
return collageIndex
|
|
||||||
}
|
}
|
||||||
|
index += 1
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
return trackIdToIndex[trackId]
|
||||||
|
|
||||||
|
// var collageIndex = -1
|
||||||
|
// var trackIndex = -1
|
||||||
|
// for item in self.values.collage {
|
||||||
|
// if case .main = item.content {
|
||||||
|
// trackIndex += 1
|
||||||
|
// } else if case .videoFile = item.content {
|
||||||
|
// trackIndex += 1
|
||||||
|
// } else if case .asset(_, true) = item.content {
|
||||||
|
// trackIndex += 1
|
||||||
|
// }
|
||||||
|
// collageIndex += 1
|
||||||
|
//
|
||||||
|
// if trackIndex == trackId {
|
||||||
|
// return collageIndex
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
public func playerIndexForTrackId(_ trackId: Int32) -> Int? {
|
public func playerIndexForTrackId(_ trackId: Int32) -> Int? {
|
||||||
|
@ -41,6 +41,8 @@ extension MediaEditorScreenImpl {
|
|||||||
return false
|
return false
|
||||||
} else if case .empty = subject, !self.node.hasAnyChanges && !self.node.drawingView.internalState.canUndo {
|
} else if case .empty = subject, !self.node.hasAnyChanges && !self.node.drawingView.internalState.canUndo {
|
||||||
return false
|
return false
|
||||||
|
} else if case .videoCollage = subject {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -4579,7 +4579,7 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
|
|||||||
guard let mediaEditor = self.mediaEditor else {
|
guard let mediaEditor = self.mediaEditor else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let isVideo = trackId != 2
|
let isVideo = trackId != 1000
|
||||||
let actionTitle: String = isVideo ? self.presentationData.strings.MediaEditor_RemoveVideo : self.presentationData.strings.MediaEditor_RemoveAudio
|
let actionTitle: String = isVideo ? self.presentationData.strings.MediaEditor_RemoveVideo : self.presentationData.strings.MediaEditor_RemoveAudio
|
||||||
let isCollage = !mediaEditor.values.collage.isEmpty
|
let isCollage = !mediaEditor.values.collage.isEmpty
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user