Various improvements

This commit is contained in:
Ilya Laktyushin 2023-02-02 07:02:48 +04:00
parent 6b8a616e70
commit 3242bfc507
10 changed files with 195 additions and 59 deletions

View File

@ -352,6 +352,12 @@ public class AttachmentController: ViewController {
}
}
self.panel.longPressed = { [weak self] _ in
if let strongSelf = self, let currentController = strongSelf.currentControllers.last {
currentController.longTapWithTabBar?()
}
}
self.panel.beganTextEditing = { [weak self] in
if let strongSelf = self {
strongSelf.container.update(isExpanded: true, transition: .animated(duration: 0.4, curve: .spring))

View File

@ -124,6 +124,7 @@ private final class AttachButtonComponent: CombinedComponent {
let strings: PresentationStrings
let theme: PresentationTheme
let action: () -> Void
let longPressAction: () -> Void
init(
context: AccountContext,
@ -131,7 +132,8 @@ private final class AttachButtonComponent: CombinedComponent {
isSelected: Bool,
strings: PresentationStrings,
theme: PresentationTheme,
action: @escaping () -> Void
action: @escaping () -> Void,
longPressAction: @escaping () -> Void
) {
self.context = context
self.type = type
@ -139,6 +141,7 @@ private final class AttachButtonComponent: CombinedComponent {
self.strings = strings
self.theme = theme
self.action = action
self.longPressAction = longPressAction
}
static func ==(lhs: AttachButtonComponent, rhs: AttachButtonComponent) -> Bool {
@ -293,6 +296,11 @@ private final class AttachButtonComponent: CombinedComponent {
.gesture(.tap {
component.action()
})
.gesture(.longPress({ state in
if case .began = state {
component.longPressAction()
}
}))
)
return context.availableSize
@ -495,6 +503,8 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
var isStandalone: Bool = false
var selectionChanged: (AttachmentButtonType) -> Bool = { _ in return false }
var longPressed: (AttachmentButtonType) -> Void = { _ in }
var beganTextEditing: () -> Void = {}
var textUpdated: (NSAttributedString) -> Void = { _ in }
var sendMessagePressed: (AttachmentTextInputPanelSendMode) -> Void = { _ in }
@ -874,6 +884,10 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
}
}
}
}, longPressAction: { [weak self] in
if let strongSelf = self, i == strongSelf.selectedIndex {
strongSelf.longPressed(type)
}
})
),
environment: {},

View File

@ -516,16 +516,51 @@ public final class ComposedPoll {
}
}
private class CreatePollControllerImpl: ItemListController, AttachmentContainable {
private final class CreatePollContext: AttachmentMediaPickerContext {
var selectionCount: Signal<Int, NoError> {
return .single(0)
}
var caption: Signal<NSAttributedString?, NoError> {
return .single(nil)
}
public var loadingProgress: Signal<CGFloat?, NoError> {
return .single(nil)
}
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
return .single(nil)
}
func setCaption(_ caption: NSAttributedString) {
}
func send(silently: Bool, mode: AttachmentMediaPickerSendMode) {
}
func schedule() {
}
func mainButtonAction() {
}
}
public class CreatePollControllerImpl: ItemListController, AttachmentContainable {
public var requestAttachmentMenuExpansion: () -> Void = {}
public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in }
public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
public var cancelPanGesture: () -> Void = { }
public var isContainerPanning: () -> Bool = { return false }
public var isContainerExpanded: () -> Bool = { return false }
public var mediaPickerContext: AttachmentMediaPickerContext? {
return CreatePollContext()
}
}
public func createPollController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: EnginePeer, isQuiz: Bool? = nil, completion: @escaping (ComposedPoll) -> Void) -> AttachmentContainable {
public func createPollController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: EnginePeer, isQuiz: Bool? = nil, completion: @escaping (ComposedPoll) -> Void) -> CreatePollControllerImpl {
var initialState = CreatePollControllerState()
if let isQuiz = isQuiz {
initialState.isQuiz = isQuiz

View File

@ -433,8 +433,12 @@ open class NavigationController: UINavigationController, ContainableController,
minHeight = 40.0
}
var inCallStatusBarFrame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: max(layout.statusBarHeight ?? 0.0, max(minHeight, layout.safeInsets.top))))
if (layout.deviceMetrics.hasTopNotch || layout.deviceMetrics.hasDynamicIsland) && !isLandscape {
inCallStatusBarFrame.size.height += 12.0
if !isLandscape {
if layout.deviceMetrics.hasTopNotch {
inCallStatusBarFrame.size.height += 12.0
} else if layout.deviceMetrics.hasDynamicIsland {
inCallStatusBarFrame.size.height += 20.0
}
}
if inCallStatusBar.frame.isEmpty {
inCallStatusBar.frame = inCallStatusBarFrame

View File

@ -363,4 +363,38 @@ public final class LocationPickerController: ViewController, AttachmentContainab
self.interaction?.dismissSearch()
self.scrollToTop?()
}
public var mediaPickerContext: AttachmentMediaPickerContext? {
return LocationPickerContext()
}
}
private final class LocationPickerContext: AttachmentMediaPickerContext {
var selectionCount: Signal<Int, NoError> {
return .single(0)
}
var caption: Signal<NSAttributedString?, NoError> {
return .single(nil)
}
public var loadingProgress: Signal<CGFloat?, NoError> {
return .single(nil)
}
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
return .single(nil)
}
func setCaption(_ caption: NSAttributedString) {
}
func send(silently: Bool, mode: AttachmentMediaPickerSendMode) {
}
func schedule() {
}
func mainButtonAction() {
}
}

View File

@ -154,7 +154,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
public var openCamera: ((TGAttachmentCameraView?) -> Void)?
public var presentSchedulePicker: (Bool, @escaping (Int32) -> Void) -> Void = { _, _ in }
public var presentTimerPicker: (@escaping (Int32) -> Void) -> Void = { _ in }
public var presentWebSearch: (MediaGroupsScreen) -> Void = { _ in }
public var presentWebSearch: (MediaGroupsScreen, Bool) -> Void = { _, _ in }
public var getCaptionPanelView: () -> TGCaptionPanelView? = { return nil }
private var completed = false
@ -1350,6 +1350,12 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
}
self.updateSelectionState(count: Int32(selectionContext.count()))
self.longTapWithTabBar = { [weak self] in
if let strongSelf = self {
strongSelf.presentSearch(activateOnDisplay: false)
}
}
}
required init(coder aDecoder: NSCoder) {
@ -1572,27 +1578,34 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
self.controllerNode.updateNavigation(delayDisappear: true, transition: .immediate)
}
private func presentSearch(activateOnDisplay: Bool) {
guard self.moreButtonNode.iconNode.iconState == .search else {
return
}
self.requestAttachmentMenuExpansion()
self.presentWebSearch(MediaGroupsScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, mediaAssetsContext: self.controllerNode.mediaAssetsContext, openGroup: { [weak self] collection in
if let strongSelf = self {
let mediaPicker = MediaPickerScreen(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: strongSelf.peer, threadTitle: strongSelf.threadTitle, chatLocation: strongSelf.chatLocation, bannedSendPhotos: strongSelf.bannedSendPhotos, bannedSendVideos: strongSelf.bannedSendVideos, subject: .assets(collection), editingContext: strongSelf.interaction?.editingState, selectionContext: strongSelf.interaction?.selectionState)
mediaPicker.presentSchedulePicker = strongSelf.presentSchedulePicker
mediaPicker.presentTimerPicker = strongSelf.presentTimerPicker
mediaPicker.getCaptionPanelView = strongSelf.getCaptionPanelView
mediaPicker.legacyCompletion = strongSelf.legacyCompletion
mediaPicker.dismissAll = { [weak self] in
self?.dismiss(animated: true, completion: nil)
}
mediaPicker._presentedInModal = true
mediaPicker.updateNavigationStack = strongSelf.updateNavigationStack
strongSelf.updateNavigationStack({ _ in return ([strongSelf, mediaPicker], strongSelf.mediaPickerContext)})
}
}), activateOnDisplay)
}
@objc private func searchOrMorePressed(node: ContextReferenceContentNode, gesture: ContextGesture?) {
switch self.moreButtonNode.iconNode.iconState {
case .search:
self.requestAttachmentMenuExpansion()
self.presentWebSearch(MediaGroupsScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, mediaAssetsContext: self.controllerNode.mediaAssetsContext, openGroup: { [weak self] collection in
if let strongSelf = self {
let mediaPicker = MediaPickerScreen(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: strongSelf.peer, threadTitle: strongSelf.threadTitle, chatLocation: strongSelf.chatLocation, bannedSendPhotos: strongSelf.bannedSendPhotos, bannedSendVideos: strongSelf.bannedSendVideos, subject: .assets(collection), editingContext: strongSelf.interaction?.editingState, selectionContext: strongSelf.interaction?.selectionState)
mediaPicker.presentSchedulePicker = strongSelf.presentSchedulePicker
mediaPicker.presentTimerPicker = strongSelf.presentTimerPicker
mediaPicker.getCaptionPanelView = strongSelf.getCaptionPanelView
mediaPicker.legacyCompletion = strongSelf.legacyCompletion
mediaPicker.dismissAll = { [weak self] in
self?.dismiss(animated: true, completion: nil)
}
mediaPicker._presentedInModal = true
mediaPicker.updateNavigationStack = strongSelf.updateNavigationStack
strongSelf.updateNavigationStack({ _ in return ([strongSelf, mediaPicker], strongSelf.mediaPickerContext)})
}
}))
self.presentSearch(activateOnDisplay: true)
case .more:
let strings = self.presentationData.strings
let selectionCount = self.selectionCount

View File

@ -163,7 +163,37 @@ private func attachmentFileControllerEntries(presentationData: PresentationData,
return entries
}
private class AttachmentFileControllerImpl: ItemListController, AttachmentContainable {
private final class AttachmentFileContext: AttachmentMediaPickerContext {
var selectionCount: Signal<Int, NoError> {
return .single(0)
}
var caption: Signal<NSAttributedString?, NoError> {
return .single(nil)
}
public var loadingProgress: Signal<CGFloat?, NoError> {
return .single(nil)
}
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
return .single(nil)
}
func setCaption(_ caption: NSAttributedString) {
}
func send(silently: Bool, mode: AttachmentMediaPickerSendMode) {
}
func schedule() {
}
func mainButtonAction() {
}
}
class AttachmentFileControllerImpl: ItemListController, AttachmentContainable {
public var requestAttachmentMenuExpansion: () -> Void = {}
public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in }
public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
@ -174,23 +204,27 @@ private class AttachmentFileControllerImpl: ItemListController, AttachmentContai
var delayDisappear = false
var resetForReuseImpl: () -> Void = {}
public func resetForReuse() {
func resetForReuse() {
self.resetForReuseImpl()
self.scrollToTop?()
}
public func prepareForReuse() {
func prepareForReuse() {
self.delayDisappear = true
self.visibleBottomContentOffsetChanged?(self.visibleBottomContentOffset)
self.delayDisappear = false
}
public var mediaPickerContext: AttachmentMediaPickerContext? {
return AttachmentFileContext()
}
}
private struct AttachmentFileControllerState: Equatable {
var searching: Bool
}
public func attachmentFileController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, bannedSendMedia: (Int32, Bool)?, presentGallery: @escaping () -> Void, presentFiles: @escaping () -> Void, send: @escaping (AnyMediaReference) -> Void) -> AttachmentContainable {
func attachmentFileController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, bannedSendMedia: (Int32, Bool)?, presentGallery: @escaping () -> Void, presentFiles: @escaping () -> Void, send: @escaping (AnyMediaReference) -> Void) -> AttachmentFileControllerImpl {
let actionsDisposable = DisposableSet()
let statePromise = ValuePromise(AttachmentFileControllerState(searching: false), ignoreRepeated: true)

View File

@ -10653,6 +10653,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if case .standard(false) = self.presentationInterfaceState.mode, self.raiseToListen == nil {
self.raiseToListen = RaiseToListenManager(shouldActivate: { [weak self] in
if let strongSelf = self, strongSelf.isNodeLoaded && strongSelf.canReadHistoryValue, strongSelf.presentationInterfaceState.interfaceState.editMessage == nil, strongSelf.playlistStateAndType == nil {
if !strongSelf.context.sharedContext.currentMediaInputSettings.with({ $0.enableRaiseToSpeak }) {
return false
}
if strongSelf.presentationInterfaceState.inputTextPanelState.mediaRecordingState != nil {
return false
}
@ -10670,13 +10674,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return false
}
if case let .media(_, expanded, _) = strongSelf.presentationInterfaceState.inputMode, expanded != nil {
if case .media = strongSelf.presentationInterfaceState.inputMode {
return false
}
if !strongSelf.context.sharedContext.currentMediaInputSettings.with({ $0.enableRaiseToSpeak }) {
return false
}
return true
}
@ -10712,14 +10714,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
strongSelf.chatDisplayNode.historyNode.voicePlaylistItemChanged(previousItem, currentItem)
// if let currentItem = currentItem?.id as? PeerMessagesMediaPlaylistItemId {
// self.controllerInteraction?.currentlyPlayingMessageId = currentItem.messageId
// if let previousItem = previousItem?.id as? PeerMessagesMediaPlaylistItemId, previousItem.messageId.peerId == peerId, currentItem.messageId.peerId == peerId, currentItem.messageId != previousItem.messageId {
// if strongSelf.chatDisplayNode.historyNode.isMessageVisibleOnScreen(currentItem.messageId) {
// strongSelf.navigateToMessage(from: nil, to: .id(currentItem.messageId, nil), scrollPosition: .center(.bottom), rememberInStack: false, animated: true, completion: nil)
// }
// }
// }
}
}
@ -12630,8 +12624,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let inputText = strongSelf.presentationInterfaceState.interfaceState.effectiveInputState.inputText
let currentMediaController = Atomic<MediaPickerScreen?>(value: nil)
let currentFilesController = Atomic<AttachmentContainable?>(value: nil)
let currentLocationController = Atomic<AttachmentContainable?>(value: nil)
let currentFilesController = Atomic<AttachmentFileControllerImpl?>(value: nil)
let currentLocationController = Atomic<LocationPickerController?>(value: nil)
let attachmentController = AttachmentController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, chatLocation: strongSelf.chatLocation, buttons: buttons, initialButton: initialButton, makeEntityInputView: { [weak self] in
guard let strongSelf = self else {
@ -12680,7 +12674,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.controllerNavigationDisposable.set(nil)
let existingController = currentFilesController.with { $0 }
if let controller = existingController {
completion(controller, nil)
completion(controller, controller.mediaPickerContext)
controller.prepareForReuse()
return
}
@ -12703,12 +12697,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})
})
let _ = currentFilesController.swap(controller)
completion(controller, nil)
completion(controller, controller.mediaPickerContext)
case .location:
strongSelf.controllerNavigationDisposable.set(nil)
let existingController = currentLocationController.with { $0 }
if let controller = existingController {
completion(controller, nil)
completion(controller, controller.mediaPickerContext)
controller.prepareForReuse()
return
}
@ -12743,7 +12737,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}, nil)
strongSelf.sendMessages([message])
})
completion(controller, nil)
completion(controller, controller.mediaPickerContext)
let _ = currentLocationController.swap(controller)
})
@ -12909,7 +12903,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}))
case .poll:
let controller = strongSelf.configurePollCreation()
completion(controller, nil)
completion(controller, controller?.mediaPickerContext)
strongSelf.controllerNavigationDisposable.set(nil)
case let .app(bot, botName, _):
let params = WebAppParameters(peerId: peer.id, botId: bot.id, botName: botName, url: nil, queryId: nil, payload: botPayload, buttonText: nil, keepAliveSignal: nil, fromMenu: false, isSimple: false)
@ -13398,8 +13392,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
controller.openCamera = { [weak self] cameraView in
self?.openCamera(cameraView: cameraView)
}
controller.presentWebSearch = { [weak self, weak controller] mediaGroups in
self?.presentWebSearch(editingMessage: false, attachment: true, present: { [weak controller] c, a in
controller.presentWebSearch = { [weak self, weak controller] mediaGroups, activateOnDisplay in
self?.presentWebSearch(editingMessage: false, attachment: true, activateOnDisplay: activateOnDisplay, present: { [weak controller] c, a in
controller?.present(c, in: .current)
if let webSearchController = c as? WebSearchController {
webSearchController.searchingUpdated = { [weak mediaGroups] searching in
@ -13560,7 +13554,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})
}
private func presentWebSearch(editingMessage: Bool, attachment: Bool, present: @escaping (ViewController, Any?) -> Void) {
private func presentWebSearch(editingMessage: Bool, attachment: Bool, activateOnDisplay: Bool = true, present: @escaping (ViewController, Any?) -> Void) {
guard let peer = self.presentationInterfaceState.renderedPeer?.peer else {
return
}
@ -13583,7 +13577,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}
})
}))
}), activateOnDisplay: activateOnDisplay)
controller.attemptItemSelection = { [weak strongSelf] item in
guard let strongSelf, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer else {
return false
@ -14158,7 +14152,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.present(tooltipScreen, in: .current)
}
private func configurePollCreation(isQuiz: Bool? = nil) -> AttachmentContainable? {
private func configurePollCreation(isQuiz: Bool? = nil) -> CreatePollControllerImpl? {
guard let peer = self.presentationInterfaceState.renderedPeer?.peer else {
return nil
}

View File

@ -306,7 +306,7 @@ final class PeerInfoHeaderNavigationTransition {
final class PeerInfoAvatarTransformContainerNode: ASDisplayNode {
let context: AccountContext
private let containerNode: ContextControllerSourceNode
let containerNode: ContextControllerSourceNode
let avatarNode: AvatarNode
fileprivate var videoNode: UniversalVideoNode?
@ -2509,11 +2509,11 @@ final class PeerInfoHeaderNode: ASDisplayNode {
func updateAvatarIsHidden(entry: AvatarGalleryEntry?) {
if let entry = entry {
self.avatarListNode.avatarContainerNode.avatarNode.isHidden = entry == self.avatarListNode.listContainerNode.galleryEntries.first
self.editingContentNode.avatarNode.isHidden = entry == self.avatarListNode.listContainerNode.galleryEntries.first
self.avatarListNode.avatarContainerNode.containerNode.isHidden = entry == self.avatarListNode.listContainerNode.galleryEntries.first
self.editingContentNode.isHidden = entry == self.avatarListNode.listContainerNode.galleryEntries.first
} else {
self.avatarListNode.avatarContainerNode.avatarNode.isHidden = false
self.editingContentNode.avatarNode.isHidden = false
self.avatarListNode.avatarContainerNode.containerNode.isHidden = false
self.editingContentNode.isHidden = false
}
self.avatarListNode.listContainerNode.updateEntryIsHidden(entry: entry)
}

View File

@ -85,6 +85,7 @@ public final class WebSearchController: ViewController {
private let peer: EnginePeer?
private let chatLocation: ChatLocation?
private let configuration: EngineConfiguration.SearchBots
private let activateOnDisplay: Bool
private var controllerNode: WebSearchControllerNode {
return self.displayNode as! WebSearchControllerNode
@ -121,12 +122,13 @@ public final class WebSearchController: ViewController {
public var attemptItemSelection: (ChatContextResult) -> Bool = { _ in return true }
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: EnginePeer?, chatLocation: ChatLocation?, configuration: EngineConfiguration.SearchBots, mode: WebSearchControllerMode) {
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: EnginePeer?, chatLocation: ChatLocation?, configuration: EngineConfiguration.SearchBots, mode: WebSearchControllerMode, activateOnDisplay: Bool = true) {
self.context = context
self.mode = mode
self.peer = peer
self.chatLocation = chatLocation
self.configuration = configuration
self.activateOnDisplay = activateOnDisplay
let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
self.interfaceState = WebSearchInterfaceState(presentationData: presentationData)
@ -329,7 +331,7 @@ public final class WebSearchController: ViewController {
self.didPlayPresentationAnimation = true
self.controllerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
if !self.didActivateSearch {
if !self.didActivateSearch && self.activateOnDisplay {
self.didActivateSearch = true
self.navigationContentNode?.activate(select: select)
}