mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Merge commit 'a320fbf36e'
# Conflicts: # submodules/TelegramUI/Components/CreateBotScreen/Sources/CreateBotScreen.swift
This commit is contained in:
commit
9142299387
25 changed files with 697 additions and 144 deletions
|
|
@ -16095,6 +16095,11 @@ Error: %8$@";
|
|||
"MediaPicker.LivePhoto.Bounce" = "Bounce";
|
||||
"MediaPicker.LivePhoto.LiveOff" = "Live Off";
|
||||
|
||||
"MediaPicker.LivePhoto.Tooltip.Live" = "Live Photo turned on";
|
||||
"MediaPicker.LivePhoto.Tooltip.Loop" = "Live Photo with Loop effect turned on";
|
||||
"MediaPicker.LivePhoto.Tooltip.Bounce" = "Live Photo with Bounce effect turned on";
|
||||
"MediaPicker.LivePhoto.Tooltip.LiveOff" = "Live Photo turned off";
|
||||
|
||||
"AuthConfirmation.UnverifiedApp" = "Unverified App";
|
||||
|
||||
"Chat.ManagedBot.CreatedTitle" = "**%@** is ready!";
|
||||
|
|
|
|||
|
|
@ -132,6 +132,10 @@ typedef NS_ENUM(NSUInteger, TGMediaLivePhotoMode)
|
|||
- (SSignal *)highQualityPhoto;
|
||||
- (void)setHighQualityPhoto:(bool)highQualityPhoto;
|
||||
|
||||
- (bool)isForceLivePhotoEnabled;
|
||||
- (SSignal *)forceLivePhotoEnabled;
|
||||
- (void)setForceLivePhotoEnabled:(bool)forceLivePhotoEnabled;
|
||||
|
||||
- (SSignal *)facesForItem:(NSObject<TGMediaEditableItem> *)item;
|
||||
- (void)setFaces:(NSArray *)faces forItem:(NSObject<TGMediaEditableItem> *)item;
|
||||
|
||||
|
|
|
|||
|
|
@ -144,12 +144,15 @@
|
|||
SPipe *_captionAbovePipe;
|
||||
SPipe *_highQualityPhotoPipe;
|
||||
SPipe *_livePhotoModePipe;
|
||||
SPipe *_forceLivePhotoPipe;
|
||||
|
||||
NSAttributedString *_forcedCaption;
|
||||
|
||||
bool _captionAbove;
|
||||
|
||||
bool _highQualityPhoto;
|
||||
|
||||
bool _forceLivePhotoEnabled;
|
||||
}
|
||||
@end
|
||||
|
||||
|
|
@ -227,6 +230,7 @@
|
|||
_captionAbovePipe = [[SPipe alloc] init];
|
||||
_highQualityPhotoPipe = [[SPipe alloc] init];
|
||||
_livePhotoModePipe = [[SPipe alloc] init];
|
||||
_forceLivePhotoPipe = [[SPipe alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
|
@ -989,6 +993,27 @@
|
|||
_highQualityPhotoPipe.sink(@(highQualityPhoto));
|
||||
}
|
||||
|
||||
- (bool)isForceLivePhotoEnabled {
|
||||
return _forceLivePhotoEnabled;
|
||||
}
|
||||
|
||||
- (SSignal *)forceLivePhotoEnabled
|
||||
{
|
||||
__weak TGMediaEditingContext *weakSelf = self;
|
||||
SSignal *updateSignal = [_forceLivePhotoPipe.signalProducer() map:^NSNumber *(NSNumber *update)
|
||||
{
|
||||
__strong TGMediaEditingContext *strongSelf = weakSelf;
|
||||
return @(strongSelf->_forceLivePhotoEnabled);
|
||||
}];
|
||||
|
||||
return [[SSignal single:@(_forceLivePhotoEnabled)] then:updateSignal];
|
||||
}
|
||||
|
||||
- (void)setForceLivePhotoEnabled:(bool)forceLivePhotoEnabled
|
||||
{
|
||||
_forceLivePhotoEnabled = forceLivePhotoEnabled;
|
||||
_forceLivePhotoPipe.sink(@(forceLivePhotoEnabled));
|
||||
}
|
||||
|
||||
- (SSignal *)facesForItem:(NSObject<TGMediaEditableItem> *)item
|
||||
{
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ swift_library(
|
|||
"//submodules/TelegramUI/Components/GlassBackgroundComponent",
|
||||
"//submodules/TelegramUI/Components/EdgeEffect",
|
||||
"//submodules/TelegramUI/Components/GlassBarButtonComponent",
|
||||
"//submodules/TelegramUI/Components/GlassControls",
|
||||
"//submodules/TelegramUI/Components/LottieComponent",
|
||||
"//submodules/TelegramUI/Components/AlertComponent",
|
||||
"//submodules/Components/BundleIconComponent",
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ import UIKit
|
|||
import Display
|
||||
import LegacyComponents
|
||||
import ComponentFlow
|
||||
import SwiftSignalKit
|
||||
import ViewControllerComponent
|
||||
import MultilineTextComponent
|
||||
import GlassBackgroundComponent
|
||||
import ContextUI
|
||||
import TelegramPresentationData
|
||||
|
|
@ -55,21 +58,25 @@ final class LivePhotoButton: UIView, TGLivePhotoButton {
|
|||
|
||||
var items: [ContextMenuItem] = []
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.MediaPicker_LivePhoto_Live, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Media Editor/LiveOn"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
self?.presentTooltip(.live)
|
||||
self?.modeUpdated?(.live)
|
||||
|
||||
f(.default)
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.MediaPicker_LivePhoto_Loop, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Media Editor/LiveLoop"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
self?.presentTooltip(.loop)
|
||||
self?.modeUpdated?(.loop)
|
||||
|
||||
f(.default)
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.MediaPicker_LivePhoto_Bounce, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Media Editor/LiveBounce"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
self?.presentTooltip(.bounce)
|
||||
self?.modeUpdated?(.bounce)
|
||||
|
||||
f(.default)
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.MediaPicker_LivePhoto_LiveOff, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Media Editor/LiveOff"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
self?.presentTooltip(.off)
|
||||
self?.modeUpdated?(.off)
|
||||
|
||||
f(.default)
|
||||
|
|
@ -79,6 +86,48 @@ final class LivePhotoButton: UIView, TGLivePhotoButton {
|
|||
self.present?(contextController, nil)
|
||||
}
|
||||
|
||||
private func presentTooltip(_ mode: TGMediaLivePhotoMode) {
|
||||
guard self.mode != mode else {
|
||||
return
|
||||
}
|
||||
let iconName: String
|
||||
let text: String
|
||||
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
switch mode {
|
||||
case .live:
|
||||
iconName = "Media Editor/LiveLargeOn"
|
||||
text = presentationData.strings.MediaPicker_LivePhoto_Tooltip_Live
|
||||
case .loop:
|
||||
iconName = "Media Editor/LiveLargeLoop"
|
||||
text = presentationData.strings.MediaPicker_LivePhoto_Tooltip_Loop
|
||||
case .bounce:
|
||||
iconName = "Media Editor/LiveLargeBounce"
|
||||
text = presentationData.strings.MediaPicker_LivePhoto_Tooltip_Bounce
|
||||
case .off:
|
||||
iconName = "Media Editor/LiveLargeOff"
|
||||
text = presentationData.strings.MediaPicker_LivePhoto_Tooltip_LiveOff
|
||||
default:
|
||||
iconName = ""
|
||||
text = ""
|
||||
}
|
||||
|
||||
let controller = TooltipInfoScreen(
|
||||
context: self.context,
|
||||
content: AnyComponent(HStack([
|
||||
AnyComponentWithIdentity(id: "icon", component: AnyComponent(
|
||||
BundleIconComponent(name: iconName, tintColor: .white)
|
||||
)),
|
||||
AnyComponentWithIdentity(id: "label", component: AnyComponent(
|
||||
MultilineTextComponent(text: .plain(NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)))
|
||||
))
|
||||
], spacing: 11.0)),
|
||||
alignment: .center
|
||||
)
|
||||
self.present?(controller, nil)
|
||||
}
|
||||
|
||||
func updateFrame(_ frame: CGRect) {
|
||||
let transition: ContainedViewLayoutTransition
|
||||
if self.frame.width.isZero {
|
||||
|
|
@ -185,3 +234,165 @@ private final class LivePhotoReferenceContentSource: ContextReferenceContentSour
|
|||
return ContextControllerReferenceViewInfo(referenceView: self.sourceView, contentAreaInScreenSpace: UIScreen.main.bounds)
|
||||
}
|
||||
}
|
||||
|
||||
private final class TooltipInfoContent: Component {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
|
||||
let context: AccountContext
|
||||
let content: AnyComponent<Empty>
|
||||
let alignment: TooltipInfoScreen.Alignment
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
content: AnyComponent<Empty>,
|
||||
alignment: TooltipInfoScreen.Alignment
|
||||
) {
|
||||
self.context = context
|
||||
self.content = content
|
||||
self.alignment = alignment
|
||||
}
|
||||
|
||||
static func ==(lhs: TooltipInfoContent, rhs: TooltipInfoContent) -> Bool {
|
||||
if lhs.context !== rhs.context {
|
||||
return false
|
||||
}
|
||||
if lhs.content != rhs.content {
|
||||
return false
|
||||
}
|
||||
if lhs.alignment != rhs.alignment {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public final class View: UIView {
|
||||
private let backgroundView = GlassBackgroundView()
|
||||
private let contentView = ComponentView<Empty>()
|
||||
|
||||
private var component: TooltipInfoContent?
|
||||
private var environment: EnvironmentType?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
self.addSubview(self.backgroundView)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
private var isDismissed = false
|
||||
func dismiss() {
|
||||
guard !self.isDismissed, let controller = self.environment?.controller() else {
|
||||
return
|
||||
}
|
||||
self.isDismissed = true
|
||||
|
||||
let transition = ComponentTransition(animation: .curve(duration: 0.25, curve: .easeInOut))
|
||||
transition.setBlur(layer: self.backgroundView.layer, radius: 10.0)
|
||||
self.backgroundView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
|
||||
controller.dismiss()
|
||||
})
|
||||
}
|
||||
|
||||
func update(component: TooltipInfoContent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
|
||||
let environment = environment[ViewControllerComponentContainer.Environment.self].value
|
||||
|
||||
let insets = UIEdgeInsets(top: 12.0, left: 10.0, bottom: 12.0, right: 18.0)
|
||||
let contentSize = self.contentView.update(
|
||||
transition: .immediate,
|
||||
component: component.content,
|
||||
environment: {},
|
||||
containerSize: availableSize
|
||||
)
|
||||
if let contentView = self.contentView.view {
|
||||
if contentView.superview == nil {
|
||||
self.backgroundView.contentView.addSubview(contentView)
|
||||
}
|
||||
contentView.frame = CGRect(origin: CGPoint(x: insets.left, y: insets.top), size: contentSize)
|
||||
}
|
||||
|
||||
let backgroundSize = CGSize(width: contentSize.width + insets.left + insets.right, height: contentSize.height + insets.top + insets.bottom)
|
||||
self.backgroundView.update(size: backgroundSize, cornerRadius: backgroundSize.height * 0.5, isDark: true, tintColor: .init(kind: .panel), transition: .immediate)
|
||||
|
||||
let backgroundFrame: CGRect
|
||||
switch component.alignment {
|
||||
case .center:
|
||||
backgroundFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - backgroundSize.width) / 2.0), y: floor((availableSize.height - backgroundSize.height) / 2.0)), size: backgroundSize)
|
||||
case .bottom:
|
||||
backgroundFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - backgroundSize.width) / 2.0), y: availableSize.height - backgroundSize.height - environment.additionalInsets.bottom - backgroundSize.height - 38.0), size: backgroundSize)
|
||||
}
|
||||
|
||||
self.backgroundView.frame = backgroundFrame
|
||||
self.environment = environment
|
||||
if self.component == nil {
|
||||
self.backgroundView.layer.animateScale(from: 0.1, to: 1.0, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
self.backgroundView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
|
||||
Queue.mainQueue().after(2.5) {
|
||||
self.dismiss()
|
||||
}
|
||||
}
|
||||
self.component = component
|
||||
|
||||
return availableSize
|
||||
}
|
||||
|
||||
public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
self.dismiss()
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public func makeView() -> View {
|
||||
return View(frame: CGRect())
|
||||
}
|
||||
|
||||
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
|
||||
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
final class TooltipInfoScreen: ViewControllerComponentContainer {
|
||||
enum Alignment {
|
||||
case center
|
||||
case bottom
|
||||
}
|
||||
|
||||
private let context: AccountContext
|
||||
|
||||
public init(
|
||||
context: AccountContext,
|
||||
content: AnyComponent<Empty>,
|
||||
alignment: Alignment
|
||||
) {
|
||||
self.context = context
|
||||
|
||||
super.init(
|
||||
context: context,
|
||||
component: TooltipInfoContent(
|
||||
context: context,
|
||||
content: content,
|
||||
alignment: alignment
|
||||
),
|
||||
navigationBarAppearance: .none,
|
||||
statusBarStyle: .ignore,
|
||||
theme: .default
|
||||
)
|
||||
|
||||
self.navigationPresentation = .flatModal
|
||||
self.automaticallyControlPresentationContextLayout = false
|
||||
}
|
||||
|
||||
required public init(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
public override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
self.view.disablesInteractiveModalDismiss = true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ final class MediaPickerGridItemNode: GridItemNode {
|
|||
var currentMediaState: (TGMediaSelectableItem, Int)?
|
||||
var currentAssetState: (PHFetchResult<PHAsset>, Int)?
|
||||
var currentAsset: PHAsset?
|
||||
var isLivePhoto = false
|
||||
|
||||
var currentDraftState: (MediaEditorDraft, Int)?
|
||||
var enableAnimations: Bool = true
|
||||
|
|
@ -175,6 +176,7 @@ final class MediaPickerGridItemNode: GridItemNode {
|
|||
self.typeIconNode.displaysAsynchronously = false
|
||||
self.typeIconNode.displayWithoutProcessing = true
|
||||
self.typeIconNode.isLayerBacked = true
|
||||
self.typeIconNode.contentMode = .center
|
||||
|
||||
self.durationNode = ImmediateTextNode()
|
||||
self.durationNode.isLayerBacked = true
|
||||
|
|
@ -547,6 +549,27 @@ final class MediaPickerGridItemNode: GridItemNode {
|
|||
}
|
||||
self.imageNode.setSignal(imageSignal)
|
||||
|
||||
if self.currentDraftState != nil {
|
||||
self.currentDraftState = nil
|
||||
}
|
||||
|
||||
var typeIcon: UIImage?
|
||||
var duration: String?
|
||||
if asset.mediaType == .video {
|
||||
if asset.mediaSubtypes.contains(.videoHighFrameRate) {
|
||||
typeIcon = UIImage(bundleImageName: "Media Editor/MediaSlomo")
|
||||
} else if asset.mediaSubtypes.contains(.videoTimelapse) {
|
||||
typeIcon = UIImage(bundleImageName: "Media Editor/MediaTimelapse")
|
||||
} else {
|
||||
typeIcon = UIImage(bundleImageName: "Media Editor/MediaVideo")
|
||||
}
|
||||
duration = stringForDuration(Int32(asset.duration))
|
||||
} else {
|
||||
if asset.mediaSubtypes.contains(.photoLive), self.interaction?.displayLivePhotoIcon == true {
|
||||
self.isLivePhoto = true
|
||||
}
|
||||
}
|
||||
|
||||
let spoilerSignal = Signal<Bool, NoError> { subscriber in
|
||||
if let signal = editingContext.spoilerSignal(forIdentifier: asset.localIdentifier) {
|
||||
let disposable = signal.start(next: { next in
|
||||
|
|
@ -579,35 +602,55 @@ final class MediaPickerGridItemNode: GridItemNode {
|
|||
}
|
||||
}
|
||||
|
||||
self.spoilerDisposable.set((combineLatest(spoilerSignal, priceSignal, self.selectionPromise.get())
|
||||
|> deliverOnMainQueue).start(next: { [weak self] hasSpoiler, price, selectionState in
|
||||
guard let strongSelf = self else {
|
||||
let livePhotoModeSignal: Signal<TGMediaLivePhotoMode?, NoError>
|
||||
if self.isLivePhoto {
|
||||
let itemSignal = Signal<TGMediaLivePhotoMode?, NoError> { subscriber in
|
||||
if let signal = editingContext.livePhotoMode(forIdentifier: asset.localIdentifier) {
|
||||
let disposable = signal.start(next: { next in
|
||||
subscriber.putNext((next as? UInt).flatMap { TGMediaLivePhotoMode(rawValue: $0) })
|
||||
}, error: { _ in
|
||||
}, completed: nil)!
|
||||
|
||||
return ActionDisposable {
|
||||
disposable.dispose()
|
||||
}
|
||||
} else {
|
||||
return EmptyDisposable
|
||||
}
|
||||
}
|
||||
|
||||
let forceSignal = Signal<Bool?, NoError> { subscriber in
|
||||
if let signal = editingContext.forceLivePhotoEnabled() {
|
||||
let disposable = signal.start(next: { next in
|
||||
subscriber.putNext((next as? Bool) ?? false)
|
||||
}, error: { _ in
|
||||
}, completed: nil)!
|
||||
|
||||
return ActionDisposable {
|
||||
disposable.dispose()
|
||||
}
|
||||
} else {
|
||||
return EmptyDisposable
|
||||
}
|
||||
}
|
||||
|
||||
livePhotoModeSignal = combineLatest(itemSignal, forceSignal)
|
||||
|> map { item, _ in
|
||||
return item
|
||||
}
|
||||
} else {
|
||||
livePhotoModeSignal = .single(nil)
|
||||
}
|
||||
|
||||
self.spoilerDisposable.set((combineLatest(spoilerSignal, priceSignal, livePhotoModeSignal, self.selectionPromise.get())
|
||||
|> deliverOnMainQueue).start(next: { [weak self] hasSpoiler, price, livePhotoMode, selectionState in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
strongSelf.updateHasSpoiler(hasSpoiler, price: selectionState.selected ? price : nil, isSingle: selectionState.count == 1 || selectionState.index == 1)
|
||||
self.updateHasSpoiler(hasSpoiler, price: selectionState.selected ? price : nil, isSingle: selectionState.count == 1 || selectionState.index == 1)
|
||||
self.updateLivePhotoMode(livePhotoMode)
|
||||
}))
|
||||
|
||||
if self.currentDraftState != nil {
|
||||
self.currentDraftState = nil
|
||||
}
|
||||
|
||||
var typeIcon: UIImage?
|
||||
var duration: String?
|
||||
if asset.mediaType == .video {
|
||||
if asset.mediaSubtypes.contains(.videoHighFrameRate) {
|
||||
typeIcon = UIImage(bundleImageName: "Media Editor/MediaSlomo")
|
||||
} else if asset.mediaSubtypes.contains(.videoTimelapse) {
|
||||
typeIcon = UIImage(bundleImageName: "Media Editor/MediaTimelapse")
|
||||
} else {
|
||||
typeIcon = UIImage(bundleImageName: "Media Editor/MediaVideo")
|
||||
}
|
||||
duration = stringForDuration(Int32(asset.duration))
|
||||
} else {
|
||||
if asset.mediaSubtypes.contains(.photoLive) && interaction.displayLivePhotoIcon {
|
||||
typeIcon = UIImage(bundleImageName: "Chat/Message/LivePhoto")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if asset.isFavorite {
|
||||
typeIcon = generateTintedImage(image: UIImage(bundleImageName: "Media Grid/Favorite"), color: .white)
|
||||
}
|
||||
|
|
@ -616,7 +659,7 @@ final class MediaPickerGridItemNode: GridItemNode {
|
|||
if self.leftShadowNode.supernode == nil {
|
||||
self.addSubnode(self.leftShadowNode)
|
||||
}
|
||||
} else if self.leftShadowNode.supernode != nil {
|
||||
} else if !self.isLivePhoto, self.leftShadowNode.supernode != nil {
|
||||
self.leftShadowNode.removeFromSupernode()
|
||||
}
|
||||
|
||||
|
|
@ -633,7 +676,7 @@ final class MediaPickerGridItemNode: GridItemNode {
|
|||
if self.typeIconNode.supernode == nil {
|
||||
self.addSubnode(self.typeIconNode)
|
||||
}
|
||||
} else if self.typeIconNode.supernode != nil {
|
||||
} else if !self.isLivePhoto, self.typeIconNode.supernode != nil {
|
||||
self.typeIconNode.removeFromSupernode()
|
||||
}
|
||||
|
||||
|
|
@ -714,6 +757,48 @@ final class MediaPickerGridItemNode: GridItemNode {
|
|||
}
|
||||
}
|
||||
|
||||
private var livePhotoIconName: String?
|
||||
private func updateLivePhotoMode(_ mode: TGMediaLivePhotoMode?) {
|
||||
guard self.isLivePhoto, self.interaction?.displayLivePhotoIcon == true else {
|
||||
return
|
||||
}
|
||||
var effectiveMode: TGMediaLivePhotoMode
|
||||
if let mode, mode != .off {
|
||||
effectiveMode = mode
|
||||
} else {
|
||||
if self.interaction?.editingState.isForceLivePhotoEnabled() == true {
|
||||
effectiveMode = .live
|
||||
} else {
|
||||
effectiveMode = .off
|
||||
}
|
||||
}
|
||||
|
||||
var iconName: String
|
||||
switch effectiveMode {
|
||||
case .off:
|
||||
iconName = "Chat/Message/LivePhotoOff"
|
||||
default:
|
||||
iconName = "Chat/Message/LivePhoto"
|
||||
}
|
||||
|
||||
if self.livePhotoIconName != iconName {
|
||||
self.livePhotoIconName = iconName
|
||||
if self.leftShadowNode.supernode == nil {
|
||||
if self.typeIconNode.supernode != nil {
|
||||
self.insertSubnode(self.leftShadowNode, belowSubnode: self.typeIconNode)
|
||||
} else {
|
||||
self.addSubnode(self.leftShadowNode)
|
||||
}
|
||||
}
|
||||
|
||||
self.typeIconNode.image = UIImage(bundleImageName: iconName)
|
||||
if self.typeIconNode.supernode == nil {
|
||||
self.addSubnode(self.typeIconNode)
|
||||
}
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
}
|
||||
|
||||
override func layout() {
|
||||
super.layout()
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,9 @@ import ComponentFlow
|
|||
import BundleIconComponent
|
||||
import LottieComponent
|
||||
import GlassBarButtonComponent
|
||||
import GlassControls
|
||||
import AlertComponent
|
||||
import MultilineTextComponent
|
||||
|
||||
final class MediaPickerInteraction {
|
||||
let downloadManager: AssetDownloadManager
|
||||
|
|
@ -237,6 +239,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||
private let titleView: MediaPickerTitleView
|
||||
private let cancelButtonNode: WebAppCancelButtonNode
|
||||
|
||||
private var buttons: ComponentView<Empty>?
|
||||
private var cancelButton: ComponentView<Empty>?
|
||||
private var rightButton: ComponentView<Empty>?
|
||||
private let moreButtonPlayOnce = ActionSlot<Void>()
|
||||
|
|
@ -1164,7 +1167,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||
|
||||
}
|
||||
|
||||
private func updateSelectionState(animated: Bool = false, updateLayout: Bool = true) {
|
||||
fileprivate func updateSelectionState(animated: Bool = false, updateLayout: Bool = true) {
|
||||
self.gridNode.forEachItemNode { itemNode in
|
||||
if let itemNode = itemNode as? MediaPickerGridItemNode {
|
||||
itemNode.updateSelectionState(animated: animated)
|
||||
|
|
@ -2102,6 +2105,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||
|
||||
if case .glass = style {
|
||||
self.cancelButton = ComponentView()
|
||||
self.buttons = ComponentView()
|
||||
}
|
||||
self.cancelButtonNode = WebAppCancelButtonNode(theme: self.presentationData.theme, strings: self.presentationData.strings)
|
||||
|
||||
|
|
@ -2635,8 +2639,8 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||
let useGlassButtons = (isBack || !self.controllerNode.scrolledToTop) && !self.controllerNode.isSwitchingAssetGroup
|
||||
|
||||
let barButtonSideInset: CGFloat = 16.0
|
||||
let barButtonSize = CGSize(width: 44.0, height: 44.0)
|
||||
|
||||
|
||||
|
||||
var buttonTransition = ComponentTransition.easeInOut(duration: 0.25)
|
||||
if case let .animated(duration, _) = transition, duration > 0.25 {
|
||||
buttonTransition = .easeInOut(duration: duration)
|
||||
|
|
@ -2659,124 +2663,248 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||
transition.updateAlpha(layer: self.controllerNode.topEdgeEffectView.layer, alpha: self.controllerNode.scrolledExactlyToTop && self.controllerNode.currentDisplayMode == .all ? 0.0 : 1.0)
|
||||
self.controllerNode.topEdgeEffectView.update(content: topEdgeColor, blur: true, alpha: 0.8, rect: topEdgeEffectFrame, edge: .top, edgeSize: topEdgeEffectFrame.height, transition: ComponentTransition(transition))
|
||||
|
||||
if let cancelButton = self.cancelButton {
|
||||
if cancelButton.view == nil {
|
||||
buttonTransition = .immediate
|
||||
}
|
||||
let cancelButtonSize = cancelButton.update(
|
||||
transition: buttonTransition,
|
||||
component: AnyComponent(GlassBarButtonComponent(
|
||||
size: barButtonSize,
|
||||
backgroundColor: nil,
|
||||
isDark: self.presentationData.theme.overallDarkAppearance,
|
||||
state: .glass,
|
||||
component: AnyComponentWithIdentity(id: isBack ? "back" : "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: isBack ? "Navigation/Back" : "Navigation/Close",
|
||||
tintColor: self.presentationData.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
self?.cancelPressed()
|
||||
let leftControlItems: [GlassControlGroupComponent.Item] = [
|
||||
GlassControlGroupComponent.Item(
|
||||
id: AnyHashable(isBack ? "back" : "close"),
|
||||
content: .icon(isBack ? "Navigation/Back" : "Navigation/Close"),
|
||||
action: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: barButtonSize
|
||||
)
|
||||
let cancelButtonFrame = CGRect(origin: CGPoint(x: barButtonSideInset + layout.safeInsets.left, y: barButtonSideInset), size: cancelButtonSize)
|
||||
if let view = cancelButton.view {
|
||||
if view.superview == nil {
|
||||
self.view.addSubview(view)
|
||||
self.cancelPressed()
|
||||
}
|
||||
)
|
||||
]
|
||||
var rightControlItems: [GlassControlGroupComponent.Item] = []
|
||||
if moreIsVisible, case .glass = self.style {
|
||||
if self.hasSelectButton {
|
||||
rightControlItems.append(GlassControlGroupComponent.Item(
|
||||
id: AnyHashable("select"),
|
||||
content: .text(self.presentationData.strings.Common_Select),
|
||||
action: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.selectPressed()
|
||||
}
|
||||
))
|
||||
} else {
|
||||
rightControlItems.append(GlassControlGroupComponent.Item(
|
||||
id: AnyHashable("more"),
|
||||
content: .animation("anim_morewide"),
|
||||
action: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let controlsView = self.buttons?.view as? GlassControlPanelComponent.View, let rightItemView = controlsView.rightItemView, let sourceView = rightItemView.itemView(id: AnyHashable("more")) {
|
||||
self.searchOrMorePressed(view: sourceView, gesture: nil)
|
||||
}
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
var hasLivePhoto = false
|
||||
if let selectionContext = self.interaction?.selectionState, let editingContext = self.interaction?.editingState {
|
||||
for case let item as TGMediaEditableItem in selectionContext.selectedItems() {
|
||||
if let item = item as? TGMediaAsset, let asset = item.backingAsset {
|
||||
if asset.mediaSubtypes.contains(.photoLive) {
|
||||
hasLivePhoto = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if hasLivePhoto {
|
||||
let isForceLivePhoto = editingContext.isForceLivePhotoEnabled()
|
||||
rightControlItems.insert(GlassControlGroupComponent.Item(
|
||||
id: AnyHashable(isForceLivePhoto ? "livePhoto_on" : "livePhoto_off"),
|
||||
content: .icon(isForceLivePhoto ? "Media Editor/LiveOn" : "Media Editor/LiveOff"),
|
||||
action: { [weak self, weak editingContext] in
|
||||
guard let self, let editingContext else {
|
||||
return
|
||||
}
|
||||
editingContext.setForceLivePhotoEnabled(!isForceLivePhoto)
|
||||
self.controllerNode.updateSelectionState()
|
||||
|
||||
let iconName: String
|
||||
let text: String
|
||||
if !isForceLivePhoto {
|
||||
iconName = "Media Editor/LiveLargeOn"
|
||||
text = self.presentationData.strings.MediaPicker_LivePhoto_Tooltip_Live
|
||||
} else {
|
||||
iconName = "Media Editor/LiveLargeOff"
|
||||
text = self.presentationData.strings.MediaPicker_LivePhoto_Tooltip_LiveOff
|
||||
}
|
||||
|
||||
let controller = TooltipInfoScreen(
|
||||
context: self.context,
|
||||
content: AnyComponent(HStack([
|
||||
AnyComponentWithIdentity(id: "icon", component: AnyComponent(
|
||||
BundleIconComponent(name: iconName, tintColor: .white)
|
||||
)),
|
||||
AnyComponentWithIdentity(id: "label", component: AnyComponent(
|
||||
MultilineTextComponent(text: .plain(NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)))
|
||||
))
|
||||
], spacing: 11.0)),
|
||||
alignment: .bottom
|
||||
)
|
||||
self.present(controller, in: .current)
|
||||
}
|
||||
), at: 0)
|
||||
}
|
||||
view.bounds = CGRect(origin: .zero, size: cancelButtonFrame.size)
|
||||
view.center = cancelButtonFrame.center
|
||||
}
|
||||
}
|
||||
|
||||
if moreIsVisible, case .glass = self.style {
|
||||
let moreButton: ComponentView<Empty>
|
||||
if let current = self.rightButton {
|
||||
moreButton = current
|
||||
} else {
|
||||
moreButton = ComponentView<Empty>()
|
||||
self.rightButton = moreButton
|
||||
if let buttons = self.buttons {
|
||||
if buttons.view == nil {
|
||||
buttonTransition = .immediate
|
||||
}
|
||||
|
||||
let buttonComponent: AnyComponent<Empty>
|
||||
let rightButtonSize: CGSize
|
||||
if self.hasSelectButton {
|
||||
buttonComponent = AnyComponent(GlassBarButtonComponent(
|
||||
size: nil,
|
||||
backgroundColor: nil,
|
||||
isDark: self.presentationData.theme.overallDarkAppearance,
|
||||
state: .glass,
|
||||
component: AnyComponentWithIdentity(id: "select", component: AnyComponent(
|
||||
Text(text: self.presentationData.strings.Common_Select, font: Font.semibold(17.0), color: self.presentationData.theme.chat.inputPanel.panelControlColor)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
self?.selectPressed()
|
||||
self?.moreButtonPlayOnce.invoke(Void())
|
||||
})
|
||||
)
|
||||
rightButtonSize = CGSize(width: 160.0, height: 44.0)
|
||||
} else {
|
||||
buttonComponent = AnyComponent(GlassBarButtonComponent(
|
||||
size: barButtonSize,
|
||||
backgroundColor: nil,
|
||||
isDark: self.presentationData.theme.overallDarkAppearance,
|
||||
state: .glass,
|
||||
component: AnyComponentWithIdentity(id: "more", component: AnyComponent(
|
||||
LottieComponent(
|
||||
content: LottieComponent.AppBundleContent(
|
||||
name: "anim_morewide"
|
||||
),
|
||||
color: self.presentationData.theme.chat.inputPanel.panelControlColor,
|
||||
size: CGSize(width: 34.0, height: 34.0),
|
||||
playOnce: self.moreButtonPlayOnce
|
||||
)
|
||||
)),
|
||||
action: { [weak self] view in
|
||||
self?.searchOrMorePressed(view: view, gesture: nil)
|
||||
self?.moreButtonPlayOnce.invoke(Void())
|
||||
})
|
||||
)
|
||||
rightButtonSize = barButtonSize
|
||||
}
|
||||
|
||||
let moreButtonSize = moreButton.update(
|
||||
let buttonsSize = buttons.update(
|
||||
transition: buttonTransition,
|
||||
component: buttonComponent,
|
||||
component: AnyComponent(GlassControlPanelComponent(
|
||||
theme: self.presentationData.theme,
|
||||
leftItem: GlassControlPanelComponent.Item(
|
||||
items: leftControlItems,
|
||||
background: .panel
|
||||
),
|
||||
centralItem: nil,
|
||||
rightItem: rightControlItems.isEmpty ? nil : GlassControlPanelComponent.Item(
|
||||
items: rightControlItems,
|
||||
background: .panel
|
||||
),
|
||||
centerAlignmentIfPossible: true,
|
||||
isDark: self.presentationData.theme.overallDarkAppearance
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: rightButtonSize
|
||||
containerSize: CGSize(width: layout.size.width - barButtonSideInset * 2.0 - layout.safeInsets.left - layout.safeInsets.right, height: 44.0)
|
||||
)
|
||||
let moreButtonFrame = CGRect(origin: CGPoint(x: layout.size.width - moreButtonSize.width - barButtonSideInset - layout.safeInsets.right, y: barButtonSideInset), size: moreButtonSize)
|
||||
if let view = moreButton.view {
|
||||
let buttonsFrame = CGRect(origin: CGPoint(x: barButtonSideInset + layout.safeInsets.left, y: barButtonSideInset), size: buttonsSize)
|
||||
if let view = buttons.view {
|
||||
if view.superview == nil {
|
||||
self.view.addSubview(view)
|
||||
if transition.isAnimated {
|
||||
let transition = ComponentTransition(transition)
|
||||
transition.animateAlpha(view: view, from: 0.0, to: 1.0)
|
||||
transition.animateScale(view: view, from: 0.1, to: 1.0)
|
||||
}
|
||||
}
|
||||
view.bounds = CGRect(origin: .zero, size: moreButtonFrame.size)
|
||||
view.center = moreButtonFrame.center
|
||||
}
|
||||
} else if let moreButton = self.rightButton {
|
||||
self.rightButton = nil
|
||||
if let view = moreButton.view {
|
||||
if transition.isAnimated {
|
||||
let transition = ComponentTransition(transition)
|
||||
view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
|
||||
view.removeFromSuperview()
|
||||
})
|
||||
transition.animateScale(view: view, from: 1.0, to: 0.1)
|
||||
} else {
|
||||
view.removeFromSuperview()
|
||||
}
|
||||
view.bounds = CGRect(origin: .zero, size: buttonsFrame.size)
|
||||
view.center = buttonsFrame.center
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// if let cancelButton = self.cancelButton {
|
||||
// if cancelButton.view == nil {
|
||||
// buttonTransition = .immediate
|
||||
// }
|
||||
// let cancelButtonSize = cancelButton.update(
|
||||
// transition: buttonTransition,
|
||||
// component: AnyComponent(GlassBarButtonComponent(
|
||||
// size: barButtonSize,
|
||||
// backgroundColor: nil,
|
||||
// isDark: self.presentationData.theme.overallDarkAppearance,
|
||||
// state: .glass,
|
||||
// component: AnyComponentWithIdentity(id: isBack ? "back" : "close", component: AnyComponent(
|
||||
// BundleIconComponent(
|
||||
// name: isBack ? "Navigation/Back" : "Navigation/Close",
|
||||
// tintColor: self.presentationData.theme.chat.inputPanel.panelControlColor
|
||||
// )
|
||||
// )),
|
||||
// action: { [weak self] _ in
|
||||
// self?.cancelPressed()
|
||||
// }
|
||||
// )),
|
||||
// environment: {},
|
||||
// containerSize: barButtonSize
|
||||
// )
|
||||
// let cancelButtonFrame = CGRect(origin: CGPoint(x: barButtonSideInset + layout.safeInsets.left, y: barButtonSideInset), size: cancelButtonSize)
|
||||
// if let view = cancelButton.view {
|
||||
// if view.superview == nil {
|
||||
// self.view.addSubview(view)
|
||||
// }
|
||||
// view.bounds = CGRect(origin: .zero, size: cancelButtonFrame.size)
|
||||
// view.center = cancelButtonFrame.center
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if moreIsVisible, case .glass = self.style {
|
||||
// let moreButton: ComponentView<Empty>
|
||||
// if let current = self.rightButton {
|
||||
// moreButton = current
|
||||
// } else {
|
||||
// moreButton = ComponentView<Empty>()
|
||||
// self.rightButton = moreButton
|
||||
// }
|
||||
//
|
||||
// let buttonComponent: AnyComponent<Empty>
|
||||
// let rightButtonSize: CGSize
|
||||
// if self.hasSelectButton {
|
||||
// buttonComponent = AnyComponent(GlassBarButtonComponent(
|
||||
// size: nil,
|
||||
// backgroundColor: nil,
|
||||
// isDark: self.presentationData.theme.overallDarkAppearance,
|
||||
// state: .glass,
|
||||
// component: AnyComponentWithIdentity(id: "select", component: AnyComponent(
|
||||
// Text(text: self.presentationData.strings.Common_Select, font: Font.semibold(17.0), color: self.presentationData.theme.chat.inputPanel.panelControlColor)
|
||||
// )),
|
||||
// action: { [weak self] _ in
|
||||
// self?.selectPressed()
|
||||
// })
|
||||
// )
|
||||
// rightButtonSize = CGSize(width: 160.0, height: 44.0)
|
||||
// } else {
|
||||
// buttonComponent = AnyComponent(GlassBarButtonComponent(
|
||||
// size: barButtonSize,
|
||||
// backgroundColor: nil,
|
||||
// isDark: self.presentationData.theme.overallDarkAppearance,
|
||||
// state: .glass,
|
||||
// component: AnyComponentWithIdentity(id: "more", component: AnyComponent(
|
||||
// LottieComponent(
|
||||
// content: LottieComponent.AppBundleContent(
|
||||
// name: "anim_morewide"
|
||||
// ),
|
||||
// color: self.presentationData.theme.chat.inputPanel.panelControlColor,
|
||||
// size: CGSize(width: 34.0, height: 34.0),
|
||||
// playOnce: self.moreButtonPlayOnce
|
||||
// )
|
||||
// )),
|
||||
// action: { [weak self] view in
|
||||
// self?.searchOrMorePressed(view: view, gesture: nil)
|
||||
// self?.moreButtonPlayOnce.invoke(Void())
|
||||
// })
|
||||
// )
|
||||
// rightButtonSize = barButtonSize
|
||||
// }
|
||||
//
|
||||
// let moreButtonSize = moreButton.update(
|
||||
// transition: buttonTransition,
|
||||
// component: buttonComponent,
|
||||
// environment: {},
|
||||
// containerSize: rightButtonSize
|
||||
// )
|
||||
// let moreButtonFrame = CGRect(origin: CGPoint(x: layout.size.width - moreButtonSize.width - barButtonSideInset - layout.safeInsets.right, y: barButtonSideInset), size: moreButtonSize)
|
||||
// if let view = moreButton.view {
|
||||
// if view.superview == nil {
|
||||
// self.view.addSubview(view)
|
||||
// if transition.isAnimated {
|
||||
// let transition = ComponentTransition(transition)
|
||||
// transition.animateAlpha(view: view, from: 0.0, to: 1.0)
|
||||
// transition.animateScale(view: view, from: 0.1, to: 1.0)
|
||||
// }
|
||||
// }
|
||||
// view.bounds = CGRect(origin: .zero, size: moreButtonFrame.size)
|
||||
// view.center = moreButtonFrame.center
|
||||
// }
|
||||
// } else if let moreButton = self.rightButton {
|
||||
// self.rightButton = nil
|
||||
// if let view = moreButton.view {
|
||||
// if transition.isAnimated {
|
||||
// let transition = ComponentTransition(transition)
|
||||
// view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
|
||||
// view.removeFromSuperview()
|
||||
// })
|
||||
// transition.animateScale(view: view, from: 1.0, to: 0.1)
|
||||
// } else {
|
||||
// view.removeFromSuperview()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
if case .assets(_, .story) = self.subject {
|
||||
if self.selectionCount > 0 {
|
||||
let text = self.presentationData.strings.MediaPicker_CreateStory(self.selectionCount)
|
||||
|
|
|
|||
|
|
@ -128,6 +128,9 @@ extension TelegramUser {
|
|||
if (flags2 & (1 << 17)) != 0 {
|
||||
botFlags.insert(.forumManagedByUser)
|
||||
}
|
||||
if (flags2 & (1 << 18)) != 0 {
|
||||
botFlags.insert(.canManageBots)
|
||||
}
|
||||
botInfo = BotUserInfo(flags: botFlags, inlinePlaceholder: botInlinePlaceholder)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ public struct BotUserInfoFlags: OptionSet {
|
|||
public static let hasWebApp = BotUserInfoFlags(rawValue: (1 << 7))
|
||||
public static let hasForum = BotUserInfoFlags(rawValue: (1 << 8))
|
||||
public static let forumManagedByUser = BotUserInfoFlags(rawValue: (1 << 9))
|
||||
public static let canManageBots = BotUserInfoFlags(rawValue: (1 << 10))
|
||||
}
|
||||
|
||||
public struct BotUserInfo: PostboxCoding, Equatable {
|
||||
|
|
|
|||
|
|
@ -388,6 +388,7 @@ func _internal_sendBotRequestedPeer(account: Account, peerId: PeerId, messageId:
|
|||
public enum CreateBotError {
|
||||
case generic
|
||||
case occupied
|
||||
case limitExceeded
|
||||
}
|
||||
|
||||
func _internal_createBot(account: Account, name: String, username: String, managerPeerId: PeerId, viaDeeplink: Bool) -> Signal<EnginePeer, CreateBotError> {
|
||||
|
|
@ -410,6 +411,8 @@ func _internal_createBot(account: Account, name: String, username: String, manag
|
|||
|> mapError { error -> CreateBotError in
|
||||
if error.errorDescription == "USERNAME_OCCUPIED" {
|
||||
return .occupied
|
||||
} else if error.errorDescription == "BOT_CREATE_LIMIT_EXCEEDED" {
|
||||
return .limitExceeded
|
||||
} else {
|
||||
return .generic
|
||||
}
|
||||
|
|
|
|||
|
|
@ -317,6 +317,14 @@ public final class GlassControlPanelComponent: Component {
|
|||
|
||||
return availableSize
|
||||
}
|
||||
|
||||
public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
let result = super.hitTest(point, with: event)
|
||||
if result === self {
|
||||
return nil
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
public func makeView() -> View {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "livecorner.pdf",
|
||||
"filename" : "livemini.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
|
|
|
|||
BIN
submodules/TelegramUI/Images.xcassets/Chat/Message/LivePhoto.imageset/livemini.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Chat/Message/LivePhoto.imageset/livemini.pdf
vendored
Normal file
Binary file not shown.
12
submodules/TelegramUI/Images.xcassets/Chat/Message/LivePhotoOff.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Message/LivePhotoOff.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "liveoffmini.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/TelegramUI/Images.xcassets/Chat/Message/LivePhotoOff.imageset/liveoffmini.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Chat/Message/LivePhotoOff.imageset/liveoffmini.pdf
vendored
Normal file
Binary file not shown.
12
submodules/TelegramUI/Images.xcassets/Media Editor/LiveLargeBounce.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Media Editor/LiveLargeBounce.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "bounce (3).pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
Binary file not shown.
12
submodules/TelegramUI/Images.xcassets/Media Editor/LiveLargeLoop.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Media Editor/LiveLargeLoop.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "loop (3).pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/TelegramUI/Images.xcassets/Media Editor/LiveLargeLoop.imageset/loop (3).pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Media Editor/LiveLargeLoop.imageset/loop (3).pdf
vendored
Normal file
Binary file not shown.
12
submodules/TelegramUI/Images.xcassets/Media Editor/LiveLargeOff.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Media Editor/LiveLargeOff.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "liveoff (3).pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/TelegramUI/Images.xcassets/Media Editor/LiveLargeOff.imageset/liveoff (3).pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Media Editor/LiveLargeOff.imageset/liveoff (3).pdf
vendored
Normal file
Binary file not shown.
12
submodules/TelegramUI/Images.xcassets/Media Editor/LiveLargeOn.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Media Editor/LiveLargeOn.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "live (3).pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
submodules/TelegramUI/Images.xcassets/Media Editor/LiveLargeOn.imageset/live (3).pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Media Editor/LiveLargeOn.imageset/live (3).pdf
vendored
Normal file
Binary file not shown.
|
|
@ -9,6 +9,7 @@ import AccountContext
|
|||
import ShareController
|
||||
import UndoUI
|
||||
import AttachmentFileController
|
||||
import LegacyMediaPickerUI
|
||||
|
||||
final class OverlayAudioPlayerControllerImpl: ViewController, OverlayAudioPlayerController {
|
||||
private let context: AccountContext
|
||||
|
|
@ -156,9 +157,24 @@ final class OverlayAudioPlayerControllerImpl: ViewController, OverlayAudioPlayer
|
|||
guard let self, let navigationController = self.parentNavigationController else {
|
||||
return
|
||||
}
|
||||
var dismissImpl: (() -> Void)?
|
||||
let controller = makeAttachmentFileControllerImpl(
|
||||
context: self.context,
|
||||
mode: .audio(.savedMusic),
|
||||
presentFiles: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
dismissImpl?()
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
let controller = legacyICloudFilePicker(theme: presentationData.theme, mode: .import, documentTypes: ["public.mp3", "public.mpeg-4-audio", "public.aac-audio", "org.xiph.flac"], completion: { urls in
|
||||
guard let url = urls.first else {
|
||||
return
|
||||
}
|
||||
print(url)
|
||||
})
|
||||
self.present(controller, in: .window(.root))
|
||||
},
|
||||
send: { [weak self] mediaReferences, _, _, _ in
|
||||
guard let self, let reference = mediaReferences.first?.concrete(TelegramMediaFile.self) else {
|
||||
return
|
||||
|
|
@ -168,6 +184,9 @@ final class OverlayAudioPlayerControllerImpl: ViewController, OverlayAudioPlayer
|
|||
) as! AttachmentFileControllerImpl
|
||||
controller.navigationPresentation = .modal
|
||||
navigationController.pushViewController(controller)
|
||||
dismissImpl = { [weak controller] in
|
||||
controller?.dismiss()
|
||||
}
|
||||
},
|
||||
getParentController: { [weak self] in
|
||||
return self
|
||||
|
|
|
|||
|
|
@ -871,14 +871,14 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||
)
|
||||
)
|
||||
}
|
||||
rightControlItems.append(
|
||||
GlassControlGroupComponent.Item(
|
||||
id: AnyHashable("search"),
|
||||
content: .icon("Navigation/Search"),
|
||||
action: {
|
||||
}
|
||||
)
|
||||
)
|
||||
// rightControlItems.append(
|
||||
// GlassControlGroupComponent.Item(
|
||||
// id: AnyHashable("search"),
|
||||
// content: .icon("Navigation/Search"),
|
||||
// action: {
|
||||
// }
|
||||
// )
|
||||
// )
|
||||
|
||||
let headerInset: CGFloat = 16.0
|
||||
let headerButtonsSize = self.headerButtons.update(
|
||||
|
|
@ -891,7 +891,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||
background: .panel
|
||||
),
|
||||
centralItem: nil,
|
||||
rightItem: GlassControlPanelComponent.Item(
|
||||
rightItem: rightControlItems.isEmpty ? nil : GlassControlPanelComponent.Item(
|
||||
items: rightControlItems,
|
||||
background: .panel
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue