Various fixes

This commit is contained in:
Ilya Laktyushin 2023-07-08 02:53:19 +02:00
parent 965d3fe392
commit a84ee0ffd7
7 changed files with 97 additions and 290 deletions

View File

@ -689,48 +689,6 @@ public class ContactsController: ViewController {
let controller = ContextController(account: self.context.account, presentationData: self.presentationData, source: .extracted(ContactsTabBarContextExtractedContentSource(controller: self, sourceNode: sourceNode)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
self.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller)
}
private var storyCameraTransitionInCoordinator: StoryCameraTransitionInCoordinator?
var hasStoryCameraTransition: Bool {
return self.storyCameraTransitionInCoordinator != nil
}
func storyCameraPanGestureChanged(transitionFraction: CGFloat) {
guard let rootController = self.context.sharedContext.mainWindow?.viewController as? TelegramRootControllerInterface else {
return
}
let coordinator: StoryCameraTransitionInCoordinator?
if let current = self.storyCameraTransitionInCoordinator {
coordinator = current
} else {
coordinator = rootController.openStoryCamera(transitionIn: nil, transitionedIn: {}, transitionOut: { [weak self] finished in
guard let self else {
return nil
}
let _ = self
// if finished, let componentView = self.chatListHeaderView() {
// if let (transitionView, _) = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
// return StoryCameraTransitionOut(
// destinationView: transitionView,
// destinationRect: transitionView.bounds,
// destinationCornerRadius: transitionView.bounds.height * 0.5
// )
// }
// }
return nil
})
self.storyCameraTransitionInCoordinator = coordinator
}
coordinator?.updateTransitionProgress(transitionFraction)
}
func storyCameraPanGestureEnded(transitionFraction: CGFloat, velocity: CGFloat) {
if let coordinator = self.storyCameraTransitionInCoordinator {
coordinator.completeWithTransitionProgressAndVelocity(transitionFraction, velocity)
self.storyCameraTransitionInCoordinator = nil
}
}
}
private final class ContactsTabBarContextExtractedContentSource: ContextExtractedContentSource {

View File

@ -68,10 +68,7 @@ final class ContactsControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
private var presentationData: PresentationData
private var presentationDataDisposable: Disposable?
private let stringsPromise = Promise<PresentationStrings>()
private var isStoryPostingAvailable = false
private var storiesPostingAvailabilityDisposable: Disposable?
weak var controller: ContactsController?
private var initialScrollingOffset: CGFloat?
@ -254,80 +251,11 @@ final class ContactsControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
}
self.openStories?(peer, sourceNode)
}
let storiesPostingAvailability = self.context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration])
|> map { view -> AppConfiguration in
let appConfiguration: AppConfiguration = view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue
return appConfiguration
}
|> distinctUntilChanged
|> map { appConfiguration -> StoriesConfiguration.PostingAvailability in
let storiesConfiguration = StoriesConfiguration.with(appConfiguration: appConfiguration)
return storiesConfiguration.posting
}
self.storiesPostingAvailabilityDisposable = combineLatest(queue: Queue.mainQueue(),
storiesPostingAvailability,
self.context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId))
|> map { peer -> Bool in
if case let .user(user) = peer, user.isPremium {
return true
} else {
return false
}
}
|> distinctUntilChanged
).start(next: { [weak self] postingAvailability, isPremium in
if let self {
let isStoryPostingAvailable: Bool
switch postingAvailability {
case .enabled:
isStoryPostingAvailable = true
case .premium:
isStoryPostingAvailable = isPremium
case .disabled:
isStoryPostingAvailable = false
}
self.isStoryPostingAvailable = isStoryPostingAvailable
}
})
}
deinit {
self.presentationDataDisposable?.dispose()
self.storySubscriptionsDisposable?.dispose()
self.storiesPostingAvailabilityDisposable?.dispose()
}
override func didLoad() {
super.didLoad()
let panRecognizer = InteractiveTransitionGestureRecognizer(target: self, action: #selector(self.panGesture(_:)), allowedDirections: { _ in
return [.rightCenter, .rightEdge]
}, edgeWidth: .widthMultiplier(factor: 1.0 / 6.0, min: 22.0, max: 80.0))
panRecognizer.delegate = self
panRecognizer.delaysTouchesBegan = false
panRecognizer.cancelsTouchesInView = true
self.panRecognizer = panRecognizer
self.view.addGestureRecognizer(panRecognizer)
}
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return false
}
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if let _ = otherGestureRecognizer as? InteractiveTransitionGestureRecognizer {
return false
}
if let _ = otherGestureRecognizer as? UIPanGestureRecognizer {
return true
}
return false
}
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
return self.isStoryPostingAvailable
}
private func updateThemeAndStrings() {
@ -594,38 +522,6 @@ final class ContactsControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
placeholderNode.frame = previousFrame
}
}
@objc private func panGesture(_ recognizer: UIPanGestureRecognizer) {
guard let (layout, _) = self.containerLayout else {
return
}
switch recognizer.state {
case .began:
break
case .changed:
let translation = recognizer.translation(in: self.view)
if case .compact = layout.metrics.widthClass {
let cameraIsAlreadyOpened = self.controller?.hasStoryCameraTransition ?? false
if translation.x > 0.0 {
self.controller?.storyCameraPanGestureChanged(transitionFraction: translation.x / layout.size.width)
} else if translation.x <= 0.0 && cameraIsAlreadyOpened {
self.controller?.storyCameraPanGestureChanged(transitionFraction: 0.0)
}
if cameraIsAlreadyOpened {
return
}
}
case .cancelled, .ended:
let translation = recognizer.translation(in: self.view)
let velocity = recognizer.velocity(in: self.view)
let hasStoryCameraTransition = self.controller?.hasStoryCameraTransition ?? false
if hasStoryCameraTransition {
self.controller?.storyCameraPanGestureEnded(transitionFraction: translation.x / layout.size.width, velocity: velocity.x)
}
default:
break
}
}
}
private final class ContactContextExtractedContentSource: ContextExtractedContentSource {

View File

@ -96,6 +96,7 @@ swift_library(
"//submodules/TelegramUI/Components/MediaEditor",
"//submodules/ChatPresentationInterfaceState:ChatPresentationInterfaceState",
"//submodules/StickerPackPreviewUI:StickerPackPreviewUI",
"//submodules/TelegramUI/Components/LottieComponent",
],
visibility = [
"//visibility:public",

View File

@ -1242,7 +1242,7 @@ public class PremiumDemoScreen: ViewControllerComponentContainer {
case other
}
var disposed: () -> Void = {}
public var disposed: () -> Void = {}
private var didSetReady = false
private let _ready = Promise<Bool>()

View File

@ -2093,6 +2093,9 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
}
}
self.isInteractingWithEntities = isInteracting
if !isInteracting {
self.controller?.isSavingAvailable = true
}
self.requestUpdate(transition: .easeInOut(duration: 0.2))
}
},
@ -3853,11 +3856,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
let entities = self.node.entitiesView.entities.filter { !($0 is DrawingMediaEntity) }
let codableEntities = DrawingEntitiesView.encodeEntities(entities, entitiesView: self.node.entitiesView)
mediaEditor.setDrawingAndEntities(data: nil, image: mediaEditor.values.drawing, entities: codableEntities)
if let previousSavedValues = self.previousSavedValues, mediaEditor.values == previousSavedValues {
return
}
self.hapticFeedback.impact(.light)
self.previousSavedValues = mediaEditor.values

View File

@ -583,6 +583,12 @@ public final class StoryItemSetContainerComponent: Component {
}
}
if let inputMediaView = self.sendMessageContext.inputMediaNode {
if inputMediaView.frame.contains(point) {
return false
}
}
if let centerInfoItemView = self.centerInfoItem?.view.view {
if centerInfoItemView.convert(centerInfoItemView.bounds, to: self).contains(point) {
return false
@ -2804,7 +2810,24 @@ public final class StoryItemSetContainerComponent: Component {
}
reactionContextNode.premiumReactionsSelected = { [weak self] file in
guard let self, let file, let component = self.component else {
guard let self, let component = self.component else {
return
}
guard let file else {
let context = component.context
var replaceImpl: ((ViewController) -> Void)?
let controller = PremiumDemoScreen(context: context, subject: .uniqueReactions, action: {
let controller = PremiumIntroScreen(context: context, source: .reactions)
replaceImpl?(controller)
})
controller.disposed = { [weak self] in
self?.updateIsProgressPaused()
}
replaceImpl = { [weak controller] c in
controller?.replace(with: c)
}
component.controller()?.push(controller)
return
}
@ -2820,6 +2843,9 @@ public final class StoryItemSetContainerComponent: Component {
let controller = PremiumIntroScreen(context: context, source: .reactions)
replaceImpl?(controller)
})
controller.disposed = { [weak self] in
self?.updateIsProgressPaused()
}
replaceImpl = { [weak controller] c in
controller?.replace(with: c)
}

View File

@ -326,6 +326,35 @@ final class StoryItemSetContainerSendMessage {
}
}
private func presentMessageSentTooltip(view: StoryItemSetContainerComponent.View, peer: EnginePeer, messageId: EngineMessage.Id?) {
guard let component = view.component, let controller = component.controller() as? StoryContainerScreen else {
return
}
if let tooltipScreen = self.tooltipScreen {
tooltipScreen.dismiss(animated: true)
}
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
let tooltipScreen = UndoOverlayController(
presentationData: presentationData,
content: .actionSucceeded(title: "", text: "Message Sent", cancel: messageId != nil ? "View in Chat" : "", destructive: false),
elevatedLayout: false,
animateInAsReplacement: false,
action: { [weak view, weak self] action in
if case .undo = action, let messageId {
view?.navigateToPeer(peer: peer, chat: true, messageId: messageId)
}
self?.tooltipScreen = nil
view?.updateIsProgressPaused()
return false
}
)
controller.present(tooltipScreen, in: .current)
self.tooltipScreen = tooltipScreen
view.updateIsProgressPaused()
}
func performSendMessageAction(
view: StoryItemSetContainerComponent.View
) {
@ -342,8 +371,7 @@ final class StoryItemSetContainerSendMessage {
}
let peer = component.slice.peer
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
let controller = component.controller()
let controller = component.controller() as? StoryContainerScreen
if let recordedAudioPreview = self.recordedAudioPreview {
self.recordedAudioPreview = nil
@ -370,27 +398,22 @@ final class StoryItemSetContainerSendMessage {
replyTo: nil,
storyId: focusedStoryId,
content: .text(text.string, entities)
) |> deliverOnMainQueue).start(next: { [weak controller, weak view] messageIds in
if let controller {
Queue.mainQueue().after(0.3) {
controller.present(UndoOverlayController(
presentationData: presentationData,
content: .actionSucceeded(title: "", text: "Message Sent", cancel: "View in Chat", destructive: false),
elevatedLayout: false,
animateInAsReplacement: false,
action: { [weak view] action in
if case .undo = action, let messageId = messageIds.first {
view?.navigateToPeer(peer: peer, chat: true, messageId: messageId)
}
return false
}
), in: .current)
) |> deliverOnMainQueue).start(next: { [weak self, weak view] messageIds in
Queue.mainQueue().after(0.3) {
if let self, let view {
self.presentMessageSentTooltip(view: view, peer: peer, messageId: messageIds.first.flatMap { $0 })
}
}
})
inputPanelView.clearSendMessageInput()
self.currentInputMode = .text
view.endEditing(true)
if hasFirstResponder(view) {
view.endEditing(true)
} else {
view.state?.updated(transition: .spring(duration: 0.3))
}
controller?.requestLayout(forceUpdate: true, transition: .animated(duration: 0.3, curve: .spring))
}
}
}
@ -407,7 +430,6 @@ final class StoryItemSetContainerSendMessage {
let focusedStoryId = StoryId(peerId: peerId, id: focusedItem.storyItem.id)
let peer = component.slice.peer
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
let controller = component.controller() as? StoryContainerScreen
if let navigationController = controller?.navigationController as? NavigationController {
@ -433,21 +455,10 @@ final class StoryItemSetContainerSendMessage {
replyTo: nil,
storyId: focusedStoryId,
content: .file(fileReference)
) |> deliverOnMainQueue).start(next: { [weak controller, weak view] messageIds in
if let controller {
Queue.mainQueue().after(0.3) {
controller.present(UndoOverlayController(
presentationData: presentationData,
content: .actionSucceeded(title: "", text: "Message Sent", cancel: "View in Chat", destructive: false),
elevatedLayout: false,
animateInAsReplacement: false,
action: { [weak view] action in
if case .undo = action, let messageId = messageIds.first {
view?.navigateToPeer(peer: peer, chat: true, messageId: messageId)
}
return false
}
), in: .current)
) |> deliverOnMainQueue).start(next: { [weak self, weak view] messageIds in
Queue.mainQueue().after(0.3) {
if let self, let view {
self.presentMessageSentTooltip(view: view, peer: peer, messageId: messageIds.first.flatMap { $0 })
}
}
})
@ -457,8 +468,8 @@ final class StoryItemSetContainerSendMessage {
view.endEditing(true)
} else {
view.state?.updated(transition: .spring(duration: 0.3))
controller?.requestLayout(forceUpdate: true, transition: .animated(duration: 0.3, curve: .spring))
}
controller?.requestLayout(forceUpdate: true, transition: .animated(duration: 0.3, curve: .spring))
}
func performSendContextResultAction(view: StoryItemSetContainerComponent.View, results: ChatContextResultCollection, result: ChatContextResult) {
@ -472,7 +483,6 @@ final class StoryItemSetContainerSendMessage {
let focusedStoryId = StoryId(peerId: peerId, id: focusedItem.storyItem.id)
let peer = component.slice.peer
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
let controller = component.controller() as? StoryContainerScreen
if let navigationController = controller?.navigationController as? NavigationController {
@ -498,21 +508,10 @@ final class StoryItemSetContainerSendMessage {
replyTo: nil,
storyId: focusedStoryId,
content: .contextResult(results, result)
) |> deliverOnMainQueue).start(next: { [weak controller, weak view] messageIds in
if let controller {
Queue.mainQueue().after(0.3) {
controller.present(UndoOverlayController(
presentationData: presentationData,
content: .actionSucceeded(title: "", text: "Message Sent", cancel: "View in Chat", destructive: false),
elevatedLayout: false,
animateInAsReplacement: false,
action: { [weak view] action in
if case .undo = action, let messageId = messageIds.first {
view?.navigateToPeer(peer: peer, chat: true, messageId: messageId)
}
return false
}
), in: .current)
) |> deliverOnMainQueue).start(next: { [weak self, weak view] messageIds in
Queue.mainQueue().after(0.3) {
if let self, let view {
self.presentMessageSentTooltip(view: view, peer: peer, messageId: messageIds.first.flatMap { $0 })
}
}
})
@ -522,8 +521,8 @@ final class StoryItemSetContainerSendMessage {
view.endEditing(true)
} else {
view.state?.updated(transition: .spring(duration: 0.3))
controller?.requestLayout(forceUpdate: true, transition: .animated(duration: 0.3, curve: .spring))
}
controller?.requestLayout(forceUpdate: true, transition: .animated(duration: 0.3, curve: .spring))
}
func setMediaRecordingActive(
@ -1160,18 +1159,13 @@ final class StoryItemSetContainerSendMessage {
}
let message: EnqueueMessage = .message(text: "", attributes: [], inlineStickers: [:], mediaReference: mediaReference, replyToMessageId: nil, replyToStoryId: focusedStoryId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])
let _ = (enqueueMessages(account: component.context.account, peerId: peer.id, messages: [message.withUpdatedReplyToMessageId(nil)])
|> deliverOnMainQueue).start()
if let controller = component.controller() {
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
controller.present(UndoOverlayController(
presentationData: presentationData,
content: .succeed(text: "Message Sent"),
elevatedLayout: false,
animateInAsReplacement: false,
action: { _ in return false }
), in: .current)
}
|> deliverOnMainQueue).start(next: { [weak self, weak view] messageIds in
if let self, let view {
Queue.mainQueue().after(0.3) {
self.presentMessageSentTooltip(view: view, peer: peer, messageId: messageIds.first.flatMap { $0 })
}
}
})
})
let _ = currentFilesController.swap(controller)
if let controller = controller as? AttachmentContainable, let mediaPickerContext = controller.mediaPickerContext {
@ -1357,10 +1351,6 @@ final class StoryItemSetContainerSendMessage {
}))
}
}))
case .poll:
let controller = self.configurePollCreation(view: view, peer: peer, targetMessageId: nil)
completion(controller, controller?.mediaPickerContext)
self.controllerNavigationDisposable.set(nil)
case .gift:
/*let premiumGiftOptions = strongSelf.presentationInterfaceState.premiumGiftOptions
if !premiumGiftOptions.isEmpty {
@ -2002,56 +1992,6 @@ final class StoryItemSetContainerSendMessage {
component.controller()?.present(controller, in: .window(.root))
}
private func configurePollCreation(view: StoryItemSetContainerComponent.View, peer: EnginePeer, targetMessageId: EngineMessage.Id?, isQuiz: Bool? = nil) -> CreatePollControllerImpl? {
guard let component = view.component else {
return nil
}
let focusedItem = component.slice.item
guard let peerId = focusedItem.peerId else {
return nil
}
let focusedStoryId = StoryId(peerId: peerId, id: focusedItem.storyItem.id)
let theme = component.theme
return createPollController(context: component.context, updatedPresentationData: (component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), component.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) }), peer: peer, isQuiz: isQuiz, completion: { [weak self, weak view] poll in
guard let self, let view else {
return
}
let replyMessageId = targetMessageId
/*strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.chatDisplayNode.collapseInput()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
$0.updatedInterfaceState { $0.withUpdatedReplyMessageId(nil) }
})
}
}, nil)*/
let message: EnqueueMessage = .message(
text: "",
attributes: [],
inlineStickers: [:],
mediaReference: .standalone(media: TelegramMediaPoll(
pollId: EngineMedia.Id(namespace: Namespaces.Media.LocalPoll, id: Int64.random(in: Int64.min ... Int64.max)),
publicity: poll.publicity,
kind: poll.kind,
text: poll.text,
options: poll.options,
correctAnswers: poll.correctAnswers,
results: poll.results,
isClosed: false,
deadlineTimeout: poll.deadlineTimeout
)),
replyToMessageId: nil,
replyToStoryId: focusedStoryId,
localGroupingKey: nil,
correlationId: nil,
bubbleUpEmojiOrStickersets: []
)
self.sendMessages(view: view, peer: peer, messages: [message.withUpdatedReplyToMessageId(replyMessageId)])
})
}
private func transformEnqueueMessages(view: StoryItemSetContainerComponent.View, messages: [EnqueueMessage], silentPosting: Bool, scheduleTime: Int32? = nil) -> [EnqueueMessage] {
var focusedStoryId: StoryId?
if let component = view.component, let peerId = component.slice.item.peerId {
@ -2095,27 +2035,14 @@ final class StoryItemSetContainerSendMessage {
}
private func sendMessages(view: StoryItemSetContainerComponent.View, peer: EnginePeer, messages: [EnqueueMessage], media: Bool = false, commit: Bool = false) {
guard let component = view.component, let controller = component.controller() else {
guard let component = view.component else {
return
}
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
let _ = (enqueueMessages(account: component.context.account, peerId: peer.id, messages: self.transformEnqueueMessages(view: view, messages: messages, silentPosting: false))
|> deliverOnMainQueue).start(next: { [weak controller] messageIds in
if let controller {
Queue.mainQueue().after(0.3) {
controller.present(UndoOverlayController(
presentationData: presentationData,
content: .actionSucceeded(title: "", text: "Message Sent", cancel: "View in Chat", destructive: false),
elevatedLayout: false,
animateInAsReplacement: false,
action: { [weak view] action in
if case .undo = action, let messageId = messageIds.first {
view?.navigateToPeer(peer: peer, chat: true, messageId: messageId)
}
return false
}
), in: .current)
|> deliverOnMainQueue).start(next: { [weak self, weak view] messageIds in
Queue.mainQueue().after(0.3) {
if let view {
self?.presentMessageSentTooltip(view: view, peer: peer, messageId: messageIds.first.flatMap { $0 })
}
}
})