Various fixes

This commit is contained in:
Ilya Laktyushin 2023-09-01 03:33:28 +04:00
parent 4b5ccefbc8
commit 46f9dd3af2
11 changed files with 239 additions and 49 deletions

View File

@ -63,7 +63,7 @@ public enum LegacyICloudFilePickerMode {
}
}
public func legacyICloudFilePicker(theme: PresentationTheme, mode: LegacyICloudFilePickerMode = .default, documentTypes: [String] = ["public.item"], forceDarkTheme: Bool = false, completion: @escaping ([URL]) -> Void) -> ViewController {
public func legacyICloudFilePicker(theme: PresentationTheme, mode: LegacyICloudFilePickerMode = .default, documentTypes: [String] = ["public.item"], forceDarkTheme: Bool = false, dismissed: @escaping () -> Void = {}, completion: @escaping ([URL]) -> Void) -> ViewController {
var dismissImpl: (() -> Void)?
let legacyController = LegacyICloudFileController(presentation: .modal(animateIn: true), theme: theme, completion: { urls in
dismissImpl?()
@ -96,6 +96,7 @@ public func legacyICloudFilePicker(theme: PresentationTheme, mode: LegacyICloudF
if let legacyController = legacyController {
legacyController.dismiss()
}
dismissed()
}
legacyController.bind(controller: UIViewController())
return legacyController

View File

@ -412,6 +412,7 @@ private final class LocationPickerContext: AttachmentMediaPickerContext {
public func storyLocationPickerController(
context: AccountContext,
location: CLLocationCoordinate2D?,
dismissed: @escaping () -> Void,
completion: @escaping (TelegramMediaMap, Int64?, String?, String?, String?) -> Void
) -> ViewController {
let presentationData = context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: defaultDarkColorPresentationTheme)
@ -427,5 +428,8 @@ public func storyLocationPickerController(
}
controller.navigationPresentation = .flatModal
controller.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
controller.didDismiss = {
dismissed()
}
return controller
}

View File

@ -0,0 +1,20 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "ContextReferenceButtonComponent",
module_name = "ContextReferenceButtonComponent",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/Display",
"//submodules/ComponentFlow",
"//submodules/ContextUI",
],
visibility = [
"//visibility:public",
],
)

View File

@ -0,0 +1,123 @@
import Foundation
import UIKit
import Display
import ComponentFlow
public final class ContextReferenceButtonComponent: Component {
let content: AnyComponent<Empty>
let tag: AnyObject?
let minSize: CGSize?
let action: (UIView, ContextGesture?) -> Void
public init(
content: AnyComponent<Empty>,
tag: AnyObject? = nil,
minSize: CGSize?,
action: @escaping (UIView, ContextGesture?) -> Void
) {
self.content = content
self.tag = tag
self.minSize = minSize
self.action = action
}
public static func ==(lhs: ContextReferenceButtonComponent, rhs: ContextReferenceButtonComponent) -> Bool {
if lhs.content != rhs.content {
return false
}
if lhs.tag !== rhs.tag {
return false
}
if lhs.minSize != rhs.minSize {
return false
}
return true
}
public final class View: UIView, ComponentTaggedView {
let buttonView: HighlightableButtonNode
let sourceView: ContextControllerSourceNode
let contextContentView: ContextReferenceContentNode
private let componentView: ComponentView<Empty>
private var component: ContextReferenceButtonComponent?
public func matches(tag: Any) -> Bool {
if let component = self.component, let componentTag = component.tag {
let tag = tag as AnyObject
if componentTag === tag {
return true
}
}
return false
}
public init() {
self.componentView = ComponentView()
self.buttonView = HighlightableButtonNode()
self.sourceView = ContextControllerSourceNode()
self.contextContentView = ContextReferenceContentNode()
super.init(frame: CGRect())
self.addSubview(self.buttonView.view)
self.buttonView.addSubnode(self.sourceView)
self.sourceView.addSubnode(self.contextContentView)
self.sourceView.activated = { [weak self] gesture, _ in
if let self, let component = self.component {
component.action(self, gesture)
}
}
self.buttonView.addTarget(self, action: #selector(self.pressed), forControlEvents: .touchUpInside)
}
required init?(coder aDecoder: NSCoder) {
preconditionFailure()
}
@objc private func pressed() {
self.component?.action(self, nil)
}
public func update(component: ContextReferenceButtonComponent, availableSize: CGSize, transition: Transition) -> CGSize {
self.component = component
let componentSize = self.componentView.update(
transition: transition,
component: component.content,
environment: {},
containerSize: availableSize
)
var size = componentSize
if let minSize = component.minSize {
size.width = max(size.width, minSize.width)
size.height = max(size.height, minSize.height)
}
if let componentView = self.componentView.view {
componentView.isUserInteractionEnabled = false
if componentView.superview == nil {
self.contextContentView.view.addSubview(componentView)
}
transition.setFrame(view: componentView, frame: CGRect(origin: CGPoint(x: floor((size.width - componentSize.width) / 2.0), y: floor((size.height - componentSize.height) / 2.0)), size: componentSize))
}
transition.setFrame(view: self.buttonView.view, frame: CGRect(origin: .zero, size: size))
transition.setFrame(view: self.sourceView.view, frame: CGRect(origin: .zero, size: size))
transition.setFrame(view: self.contextContentView.view, frame: CGRect(origin: .zero, size: size))
return size
}
}
public func makeView() -> View {
return View()
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}

View File

@ -181,9 +181,9 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
likeAction: nil,
likeOptionsAction: nil,
inputModeAction: nil,
timeoutAction: self.chatLocation.peerId?.namespace == Namespaces.Peer.CloudUser ? { [weak self] sourceView in
timeoutAction: self.chatLocation.peerId?.namespace == Namespaces.Peer.CloudUser ? { [weak self] sourceView, gesture in
if let self {
self.presentTimeoutSetup(sourceView: sourceView)
self.presentTimeoutSetup(sourceView: sourceView, gesture: gesture)
}
} : nil,
forwardAction: nil,
@ -235,7 +235,7 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
return inputPanelSize.height - 8.0
}
private func presentTimeoutSetup(sourceView: UIView) {
private func presentTimeoutSetup(sourceView: UIView, gesture: ContextGesture?) {
self.hapticFeedback.impact(.light)
var items: [ContextMenuItem] = []
@ -284,7 +284,7 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
updateTimeout(nil)
})))
let contextController = ContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: nil)
let contextController = ContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
self.present(contextController)
}

View File

@ -1117,7 +1117,7 @@ final class MediaEditorScreenComponent: Component {
}
}
},
timeoutAction: isEditingStory ? nil : { [weak self] view in
timeoutAction: isEditingStory ? nil : { [weak self] view, gesture in
guard let self, let controller = self.environment?.controller() as? MediaEditorScreen else {
return
}
@ -1130,7 +1130,7 @@ final class MediaEditorScreenComponent: Component {
} else {
hasPremium = false
}
controller?.presentTimeoutSetup(sourceView: view, hasPremium: hasPremium)
controller?.presentTimeoutSetup(sourceView: view, gesture: gesture, hasPremium: hasPremium)
})
},
forwardAction: nil,
@ -2972,7 +2972,15 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
location = draft.location
}
}
let locationController = storyLocationPickerController(context: self.context, location: location, completion: { [weak self] location, queryId, resultId, address, countryCode in
let locationController = storyLocationPickerController(
context: self.context,
location: location,
dismissed: { [weak self] in
if let self {
self.mediaEditor?.play()
}
},
completion: { [weak self] location, queryId, resultId, address, countryCode in
if let self {
let emojiFile: Signal<TelegramMediaFile?, NoError>
if let countryCode {
@ -3050,7 +3058,13 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
}
func presentAudioPicker() {
self.controller?.present(legacyICloudFilePicker(theme: self.presentationData.theme, mode: .import, documentTypes: ["public.mp3"], forceDarkTheme: true, completion: { [weak self] urls in
self.controller?.present(legacyICloudFilePicker(theme: self.presentationData.theme, mode: .import, documentTypes: ["public.mp3"], forceDarkTheme: true, dismissed: { [weak self] in
if let self {
Queue.mainQueue().after(0.1) {
self.mediaEditor?.play()
}
}
}, completion: { [weak self] urls in
guard let self, let mediaEditor = self.mediaEditor, !urls.isEmpty, let url = urls.first else {
return
}
@ -3075,10 +3089,6 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
}
self.requestUpdate(transition: .easeInOut(duration: 0.2))
Queue.mainQueue().after(0.1) {
self.mediaEditor?.play()
}
}), in: .window(.root))
}
@ -3096,7 +3106,13 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
action: { [weak self] f in
f.dismissWithResult(.default)
if let self {
self.mediaEditor?.setAudioTrack(nil)
if let mediaEditor = self.mediaEditor {
mediaEditor.setAudioTrack(nil)
if !mediaEditor.sourceIsVideo && !mediaEditor.isPlaying {
mediaEditor.play()
}
}
self.requestUpdate(transition: .easeInOut(duration: 0.25))
}
}
@ -3887,7 +3903,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
})
}
func presentTimeoutSetup(sourceView: UIView, hasPremium: Bool) {
func presentTimeoutSetup(sourceView: UIView, gesture: ContextGesture?, hasPremium: Bool) {
self.hapticFeedback.impact(.light)
var items: [ContextMenuItem] = []
@ -3908,7 +3924,6 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
let presentationData = self.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: defaultDarkPresentationTheme)
let title = presentationData.strings.Story_Editor_ExpirationText
let currentValue = self.state.privacy.timeout
let currentArchived = self.state.privacy.pin
let emptyAction: ((ContextMenuActionItem.Action) -> Void)? = nil
items.append(.action(ContextMenuActionItem(text: title, textLayout: .multiline, textFont: .small, icon: { _ in return nil }, action: emptyAction)))
@ -3944,7 +3959,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
}
})))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Story_Editor_ExpirationValue(24), icon: { theme in
return currentValue == 86400 && !currentArchived ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
return currentValue == 86400 ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : nil
}, action: { _, a in
a(.default)
@ -3966,7 +3981,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
}
})))
let contextController = ContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: self, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: nil)
let contextController = ContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: self, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
self.present(contextController, in: .window(.root))
}

View File

@ -37,6 +37,8 @@ swift_library(
"//submodules/AnimatedCountLabelNode",
"//submodules/TelegramUI/Components/MessageInputActionButtonComponent",
"//submodules/SearchPeerMembers",
"//submodules/ContextUI",
"//submodules/TelegramUI/Components/ContextReferenceButtonComponent",
],
visibility = [
"//visibility:public",

View File

@ -18,6 +18,9 @@ import AudioToolbox
import AnimatedTextComponent
import AnimatedCountLabelNode
import MessageInputActionButtonComponent
import ContextReferenceButtonComponent
private let timeoutButtonTag = GenericComponentViewTag()
public final class MessageInputPanelComponent: Component {
public struct ContextQueryTypes: OptionSet {
@ -120,7 +123,7 @@ public final class MessageInputPanelComponent: Component {
public let likeAction: (() -> Void)?
public let likeOptionsAction: ((UIView, ContextGesture?) -> Void)?
public let inputModeAction: (() -> Void)?
public let timeoutAction: ((UIView) -> Void)?
public let timeoutAction: ((UIView, ContextGesture?) -> Void)?
public let forwardAction: (() -> Void)?
public let moreAction: ((UIView, ContextGesture?) -> Void)?
public let presentVoiceMessagesUnavailableTooltip: ((UIView) -> Void)?
@ -172,7 +175,7 @@ public final class MessageInputPanelComponent: Component {
likeAction: (() -> Void)?,
likeOptionsAction: ((UIView, ContextGesture?) -> Void)?,
inputModeAction: (() -> Void)?,
timeoutAction: ((UIView) -> Void)?,
timeoutAction: ((UIView, ContextGesture?) -> Void)?,
forwardAction: (() -> Void)?,
moreAction: ((UIView, ContextGesture?) -> Void)?,
presentVoiceMessagesUnavailableTooltip: ((UIView) -> Void)?,
@ -1458,7 +1461,7 @@ public final class MessageInputPanelComponent: Component {
if let timeoutAction = component.timeoutAction, let timeoutValue = component.timeoutValue {
let timeoutButtonSize = self.timeoutButton.update(
transition: transition,
component: AnyComponent(Button(
component: AnyComponent(ContextReferenceButtonComponent(
content: AnyComponent(
TimeoutContentComponent(
color: .white,
@ -1467,13 +1470,12 @@ public final class MessageInputPanelComponent: Component {
value: timeoutValue
)
),
action: { [weak self] in
guard let self, let timeoutButtonView = self.timeoutButton.view else {
return
}
timeoutAction(timeoutButtonView)
tag: timeoutButtonTag,
minSize: CGSize(width: 32.0, height: 32.0),
action: { view, gesture in
timeoutAction(view, gesture)
}
).minSize(CGSize(width: 32.0, height: 32.0))),
)),
environment: {},
containerSize: CGSize(width: 32.0, height: 32.0)
)

View File

@ -78,13 +78,13 @@ public final class TimeoutContentComponent: Component {
if let textView = self.text.view, let snapshotView = textView.snapshotView(afterScreenUpdates: false) {
snapshotView.frame = textView.frame
self.addSubview(snapshotView)
snapshotView.layer.animatePosition(from: .zero, to: CGPoint(x: 0.0, y: 3.0), duration: 0.2, removeOnCompletion: false, additive: true)
snapshotView.layer.animatePosition(from: .zero, to: CGPoint(x: 0.0, y: -3.0), duration: 0.2, removeOnCompletion: false, additive: true)
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in
snapshotView.removeFromSuperview()
})
textView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
textView.layer.animatePosition(from: CGPoint(x: 0.0, y: -3.0), to: .zero, duration: 0.2, additive: true)
textView.layer.animatePosition(from: CGPoint(x: 0.0, y: 3.0), to: .zero, duration: 0.2, additive: true)
}
}
}

View File

@ -503,6 +503,8 @@ final class ShareWithPeersScreenComponent: Component {
let translation = recognizer.translation(in: self)
self.dismissPanState = DismissPanState(translation: translation.y)
self.state?.updated(transition: .immediate)
self.updateModalOverlayTransition(transition: .immediate)
case .cancelled, .ended:
if self.dismissPanState != nil {
let translation = recognizer.translation(in: self)
@ -512,8 +514,13 @@ final class ShareWithPeersScreenComponent: Component {
if translation.y > 100.0 || velocity.y > 10.0 {
controller.requestDismiss()
Queue.mainQueue().justDispatch {
controller.updateModalStyleOverlayTransitionFactor(0.0, transition: .animated(duration: 0.3, curve: .spring))
}
} else {
self.state?.updated(transition: Transition(animation: .curve(duration: 0.3, curve: .spring)))
let transition = Transition(animation: .curve(duration: 0.3, curve: .spring))
self.state?.updated(transition: transition)
self.updateModalOverlayTransition(transition: transition)
}
}
default:
@ -782,7 +789,7 @@ final class ShareWithPeersScreenComponent: Component {
guard let self else {
return
}
let controller = ShareWithPeersScreen(
let peersController = ShareWithPeersScreen(
context: component.context,
initialPrivacy: EngineStoryPrivacy(base: .nobody, additionallyIncludePeers: []),
stateContext: stateContext,
@ -797,10 +804,40 @@ final class ShareWithPeersScreenComponent: Component {
self.state?.updated(transition: .spring(duration: 0.4))
}
)
self.environment?.controller()?.push(controller)
if let controller = self.environment?.controller() as? ShareWithPeersScreen {
controller.dismissAllTooltips()
controller.push(peersController)
}
})
}
private func updateModalOverlayTransition(transition: Transition) {
guard let _ = self.component, let environment = self.environment, let itemLayout = self.itemLayout else {
return
}
var topOffset = -self.scrollView.bounds.minY + itemLayout.topInset
topOffset = max(0.0, topOffset)
if let dismissPanState = self.dismissPanState {
topOffset += dismissPanState.translation
}
let topOffsetDistance: CGFloat = min(200.0, floor(itemLayout.containerSize.height * 0.25))
var topOffsetFraction = topOffset / topOffsetDistance
topOffsetFraction = max(0.0, min(1.0, topOffsetFraction))
let transitionFactor: CGFloat = 1.0 - topOffsetFraction
if let controller = environment.controller() {
Queue.mainQueue().justDispatch {
var transition = transition
if controller.modalStyleOverlayTransitionFactor.isZero && transitionFactor > 0.0, transition.animation.isImmediate {
transition = .spring(duration: 0.4)
}
controller.updateModalStyleOverlayTransitionFactor(transitionFactor, transition: transition.containedViewLayoutTransition)
}
}
}
private func updateScrolling(transition: Transition) {
guard let component = self.component, let environment = self.environment, let itemLayout = self.itemLayout else {
return
@ -819,21 +856,7 @@ final class ShareWithPeersScreenComponent: Component {
var bottomAlpha: CGFloat = bottomDistance / bottomAlphaDistance
bottomAlpha = max(0.0, min(1.0, bottomAlpha))
let topOffsetDistance: CGFloat = min(200.0, floor(itemLayout.containerSize.height * 0.25))
self.topOffsetDistance = topOffsetDistance
var topOffsetFraction = topOffset / topOffsetDistance
topOffsetFraction = max(0.0, min(1.0, topOffsetFraction))
let transitionFactor: CGFloat = 1.0 - topOffsetFraction
if let controller = environment.controller() {
Queue.mainQueue().justDispatch {
var transition = transition
if controller.modalStyleOverlayTransitionFactor.isZero && transitionFactor > 0.0, transition.animation.isImmediate {
transition = .spring(duration: 0.4)
}
controller.updateModalStyleOverlayTransitionFactor(transitionFactor, transition: transition.containedViewLayoutTransition)
}
}
self.updateModalOverlayTransition(transition: transition)
var visibleBounds = self.scrollView.bounds
visibleBounds.origin.y -= itemLayout.topInset
@ -1043,7 +1066,7 @@ final class ShareWithPeersScreenComponent: Component {
if isStories {
let _ = self.presentSendAsPeer()
} else {
self.hapticFeedback.tap()
self.hapticFeedback.impact(.light)
self.environment?.controller()?.dismiss()
self.component?.peerCompletion(peer.id)
}

View File

@ -2045,7 +2045,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
if isSecretMedia {
let remainingTime: Int32?
if let (maybeBeginTime, timeout) = secretBeginTimeAndTimeout {
if let (maybeBeginTime, timeout) = secretBeginTimeAndTimeout, Int32(timeout) != viewOnceTimeout {
if let beginTime = maybeBeginTime {
let elapsedTime = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 - beginTime
remainingTime = Int32(max(0.0, timeout - elapsedTime))