mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Attach menu improvements
This commit is contained in:
parent
59595cb027
commit
3ddf3518c5
@ -3,7 +3,7 @@ import Display
|
||||
import SwiftSignalKit
|
||||
|
||||
public protocol ContactSelectionController: ViewController {
|
||||
var result: Signal<([ContactListPeer], ContactListAction)?, NoError> { get }
|
||||
var result: Signal<([ContactListPeer], ContactListAction, Bool, Int32?)?, NoError> { get }
|
||||
var displayProgress: Bool { get set }
|
||||
var dismissed: (() -> Void)? { get set }
|
||||
|
||||
|
@ -273,7 +273,7 @@ public class AttachmentController: ViewController {
|
||||
|
||||
self.container.position = startPosition
|
||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring)
|
||||
transition.animateView({
|
||||
transition.animateView(allowUserInteraction: true, {
|
||||
self.container.position = targetPosition
|
||||
})
|
||||
}
|
||||
|
@ -584,7 +584,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
||||
if textInputPanelNode.frame.width.isZero {
|
||||
panelTransition = .immediate
|
||||
}
|
||||
let panelHeight = textInputPanelNode.updateLayout(width: layout.size.width, leftInset: insets.left, rightInset: insets.right, additionalSideInsets: UIEdgeInsets(), maxHeight: layout.size.height / 2.0, isSecondary: false, transition: panelTransition, interfaceState: self.presentationInterfaceState, metrics: layout.metrics)
|
||||
let panelHeight = textInputPanelNode.updateLayout(width: layout.size.width, leftInset: insets.left + layout.safeInsets.left, rightInset: insets.right + layout.safeInsets.right, additionalSideInsets: UIEdgeInsets(), maxHeight: layout.size.height / 2.0, isSecondary: false, transition: panelTransition, interfaceState: self.presentationInterfaceState, metrics: layout.metrics)
|
||||
let panelFrame = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: panelHeight)
|
||||
if textInputPanelNode.frame.width.isZero {
|
||||
textInputPanelNode.frame = panelFrame
|
||||
|
@ -385,7 +385,7 @@ public final class CallListController: TelegramBaseController {
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak controller, weak self] result in
|
||||
controller?.dismissSearch()
|
||||
if let strongSelf = self, let (contactPeers, action) = result, let contactPeer = contactPeers.first, case let .peer(peer, _, _) = contactPeer {
|
||||
if let strongSelf = self, let (contactPeers, action, _, _) = result, let contactPeer = contactPeers.first, case let .peer(peer, _, _) = contactPeer {
|
||||
strongSelf.call(peer.id, isVideo: action == .videoCall, began: {
|
||||
if let strongSelf = self {
|
||||
let _ = (strongSelf.context.sharedContext.hasOngoingCall.get()
|
||||
|
@ -801,6 +801,9 @@ public final class ContactListNode: ASDisplayNode {
|
||||
public var selectionState: ContactListNodeGroupSelectionState? {
|
||||
return self.selectionStateValue
|
||||
}
|
||||
public var selectionStateSignal: Signal<ContactListNodeGroupSelectionState?, NoError> {
|
||||
return self.selectionStatePromise.get()
|
||||
}
|
||||
public var selectionStateUpdated: ((ContactListNodeGroupSelectionState?) -> Void)?
|
||||
|
||||
public var selectedPeers: [ContactListPeer] {
|
||||
|
@ -1440,13 +1440,17 @@ public struct CombinedTransition {
|
||||
}
|
||||
|
||||
public extension ContainedViewLayoutTransition {
|
||||
func animateView(_ f: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) {
|
||||
func animateView(allowUserInteraction: Bool = false, _ f: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) {
|
||||
switch self {
|
||||
case .immediate:
|
||||
f()
|
||||
completion?(true)
|
||||
case let .animated(duration, curve):
|
||||
UIView.animate(withDuration: duration, delay: 0.0, options: curve.viewAnimationOptions, animations: {
|
||||
var options = curve.viewAnimationOptions
|
||||
if allowUserInteraction {
|
||||
options.insert(.allowUserInteraction)
|
||||
}
|
||||
UIView.animate(withDuration: duration, delay: 0.0, options: options, animations: {
|
||||
f()
|
||||
}, completion: completion)
|
||||
}
|
||||
|
@ -23,16 +23,18 @@ final class MediaPickerInteraction {
|
||||
let toggleSelection: (TGMediaSelectableItem, Bool) -> Void
|
||||
let sendSelected: (TGMediaSelectableItem?, Bool, Int32?, Bool) -> Void
|
||||
let schedule: () -> Void
|
||||
let dismissInput: () -> Void
|
||||
let selectionState: TGMediaSelectionContext?
|
||||
let editingState: TGMediaEditingContext
|
||||
var hiddenMediaId: String?
|
||||
|
||||
init(openMedia: @escaping (PHFetchResult<PHAsset>, Int, UIImage?) -> Void, openSelectedMedia: @escaping (TGMediaSelectableItem, UIImage?) -> Void, toggleSelection: @escaping (TGMediaSelectableItem, Bool) -> Void, sendSelected: @escaping (TGMediaSelectableItem?, Bool, Int32?, Bool) -> Void, schedule: @escaping () -> Void, selectionState: TGMediaSelectionContext?, editingState: TGMediaEditingContext) {
|
||||
init(openMedia: @escaping (PHFetchResult<PHAsset>, Int, UIImage?) -> Void, openSelectedMedia: @escaping (TGMediaSelectableItem, UIImage?) -> Void, toggleSelection: @escaping (TGMediaSelectableItem, Bool) -> Void, sendSelected: @escaping (TGMediaSelectableItem?, Bool, Int32?, Bool) -> Void, schedule: @escaping () -> Void, dismissInput: @escaping () -> Void, selectionState: TGMediaSelectionContext?, editingState: TGMediaEditingContext) {
|
||||
self.openMedia = openMedia
|
||||
self.openSelectedMedia = openSelectedMedia
|
||||
self.toggleSelection = toggleSelection
|
||||
self.sendSelected = sendSelected
|
||||
self.schedule = schedule
|
||||
self.dismissInput = dismissInput
|
||||
self.selectionState = selectionState
|
||||
self.editingState = editingState
|
||||
}
|
||||
@ -108,6 +110,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
private var presentationData: PresentationData
|
||||
private let mediaAssetsContext: MediaAssetsContext
|
||||
|
||||
private let backgroundNode: NavigationBackgroundNode
|
||||
private let gridNode: GridNode
|
||||
private var cameraView: TGAttachmentCameraView?
|
||||
private var placeholderNode: MediaPickerPlaceholderNode?
|
||||
@ -142,12 +145,14 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
let mediaAssetsContext = MediaAssetsContext()
|
||||
self.mediaAssetsContext = mediaAssetsContext
|
||||
|
||||
self.backgroundNode = NavigationBackgroundNode(color: self.presentationData.theme.rootController.tabBar.backgroundColor)
|
||||
self.gridNode = GridNode()
|
||||
|
||||
super.init()
|
||||
|
||||
self.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.gridNode)
|
||||
|
||||
self.interaction = MediaPickerInteraction(openMedia: { [weak self] fetchResult, index, immediateThumbnail in
|
||||
@ -171,6 +176,10 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
self?.interaction?.sendSelected(nil, false, time, true)
|
||||
})
|
||||
}
|
||||
}, dismissInput: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.dismissInput()
|
||||
}
|
||||
}, selectionState: TGMediaSelectionContext(), editingState: TGMediaEditingContext())
|
||||
self.interaction?.selectionState?.grouping = true
|
||||
|
||||
@ -281,6 +290,8 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
cameraView.startPreview()
|
||||
|
||||
self.gridNode.scrollView.addSubview(cameraView)
|
||||
|
||||
// self.controller?.navigationBar?.updateBackgroundAlpha(0.0, transition: .immediate)
|
||||
}
|
||||
|
||||
private func dismissInput() {
|
||||
@ -590,6 +601,9 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
let gridInsets = UIEdgeInsets(top: insets.top + manageHeight, left: layout.safeInsets.left, bottom: layout.intrinsicInsets.bottom, right: layout.safeInsets.right)
|
||||
transition.updateFrame(node: self.gridNode, frame: bounds)
|
||||
|
||||
transition.updateFrame(node: self.backgroundNode, frame: bounds)
|
||||
self.backgroundNode.update(size: bounds.size, transition: transition)
|
||||
|
||||
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: bounds.size, insets: gridInsets, scrollIndicatorInsets: nil, preloadSize: 200.0, type: .fixed(itemSize: CGSize(width: itemWidth, height: itemWidth), fillWidth: true, lineSpacing: itemSpacing, itemSpacing: itemSpacing), cutout: cameraRect), transition: transition), itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil, updateOpaqueState: nil, synchronousLoads: false), completion: { [weak self] _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -696,7 +710,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
|
||||
self.moreButtonNode = MediaPickerMoreButtonNode(theme: self.presentationData.theme)
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: presentationData))
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: presentationData, hideBackground: false, hideBadge: false, hideSeparator: true))
|
||||
|
||||
self.statusBar.statusBarStyle = .Ignore
|
||||
|
||||
|
@ -189,7 +189,7 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
final class MediaPickerSelectedListNode: ASDisplayNode {
|
||||
final class MediaPickerSelectedListNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
private let context: AccountContext
|
||||
|
||||
fileprivate let wallpaperBackgroundNode: WallpaperBackgroundNode
|
||||
@ -225,6 +225,8 @@ final class MediaPickerSelectedListNode: ASDisplayNode {
|
||||
self.scrollNode.view.contentInsetAdjustmentBehavior = .never
|
||||
}
|
||||
|
||||
self.scrollNode.view.delegate = self
|
||||
|
||||
self.view.addGestureRecognizer(ReorderingGestureRecognizer(shouldBegin: { [weak self] point in
|
||||
if let strongSelf = self, !strongSelf.scrollNode.view.isTracking {
|
||||
for (_, itemNode) in strongSelf.itemNodes {
|
||||
@ -246,6 +248,10 @@ final class MediaPickerSelectedListNode: ASDisplayNode {
|
||||
}))
|
||||
}
|
||||
|
||||
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
|
||||
self.interaction?.dismissInput()
|
||||
}
|
||||
|
||||
func scrollToTop(animated: Bool) {
|
||||
self.scrollNode.view.setContentOffset(CGPoint(), animated: animated)
|
||||
}
|
||||
@ -399,9 +405,21 @@ final class MediaPickerSelectedListNode: ASDisplayNode {
|
||||
for i in stride(from: 0, to: itemSizes.count, by: groupSize) {
|
||||
let sizes = itemSizes[i ..< min(i + groupSize, itemSizes.count)]
|
||||
let items = items[i ..< min(i + groupSize, items.count)]
|
||||
|
||||
if items.count > 1 {
|
||||
let (mosaicLayout, size) = chatMessageBubbleMosaicLayout(maxSize: boundingSize, itemSizes: Array(sizes), spacing: 1.0, fillWidth: true)
|
||||
let layout = zip(items, mosaicLayout).map { ($0, $1.0, $1.1) }
|
||||
groupLayouts.append((layout, size))
|
||||
} else if let item = items.first, var itemSize = sizes.first {
|
||||
if itemSize.width > itemSize.height {
|
||||
itemSize = itemSize.aspectFitted(boundingSize)
|
||||
} else {
|
||||
itemSize = boundingSize
|
||||
}
|
||||
let itemRect = CGRect(origin: CGPoint(), size: itemSize)
|
||||
let position: MosaicItemPosition = [.top, .bottom, .left, .right]
|
||||
groupLayouts.append(([(item, itemRect, position)], itemRect.size))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i in 0 ..< itemSizes.count {
|
||||
|
@ -1322,7 +1322,7 @@ private func addContactToExisting(context: AccountContext, parentController: Vie
|
||||
(parentController.navigationController as? NavigationController)?.pushViewController(contactsController)
|
||||
let _ = (contactsController.result
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
if let (peers, _) = result, let peer = peers.first {
|
||||
if let (peers, _, _, _) = result, let peer = peers.first {
|
||||
let dataSignal: Signal<(Peer?, DeviceContactStableId?), NoError>
|
||||
switch peer {
|
||||
case let .peer(contact, _, _):
|
||||
|
@ -63,10 +63,10 @@ public func presentPeerReportOptions(context: AccountContext, parent: ViewContro
|
||||
icon = UIImage(bundleImageName: "Chat/Context Menu/ReportCopyright")
|
||||
case .illegalDrugs:
|
||||
title = presentationData.strings.ReportPeer_ReasonIllegalDrugs
|
||||
icon = UIImage(bundleImageName: "Chat/Context Menu/ReportCopyright")
|
||||
icon = UIImage(bundleImageName: "Chat/Context Menu/ReportDrugs")
|
||||
case .personalDetails:
|
||||
title = presentationData.strings.ReportPeer_ReasonPersonalDetails
|
||||
icon = UIImage(bundleImageName: "Chat/Context Menu/ReportCopyright")
|
||||
icon = UIImage(bundleImageName: "Chat/Context Menu/User")
|
||||
case .other:
|
||||
title = presentationData.strings.ReportPeer_ReasonOther
|
||||
icon = UIImage(bundleImageName: "Chat/Context Menu/Report")
|
||||
|
@ -46,9 +46,9 @@ public extension ToolbarTheme {
|
||||
}
|
||||
|
||||
public extension NavigationBarTheme {
|
||||
convenience init(rootControllerTheme: PresentationTheme, enableBackgroundBlur: Bool = true, hideBackground: Bool = false, hideBadge: Bool = false) {
|
||||
convenience init(rootControllerTheme: PresentationTheme, enableBackgroundBlur: Bool = true, hideBackground: Bool = false, hideBadge: Bool = false, hideSeparator: Bool = false) {
|
||||
let theme = rootControllerTheme.rootController.navigationBar
|
||||
self.init(buttonColor: theme.buttonColor, disabledButtonColor: theme.disabledButtonColor, primaryTextColor: theme.primaryTextColor, backgroundColor: hideBackground ? .clear : theme.blurredBackgroundColor, enableBackgroundBlur: enableBackgroundBlur, separatorColor: hideBackground ? .clear : theme.separatorColor, badgeBackgroundColor: hideBadge ? .clear : theme.badgeBackgroundColor, badgeStrokeColor: hideBadge ? .clear : theme.badgeStrokeColor, badgeTextColor: hideBadge ? .clear : theme.badgeTextColor)
|
||||
self.init(buttonColor: theme.buttonColor, disabledButtonColor: theme.disabledButtonColor, primaryTextColor: theme.primaryTextColor, backgroundColor: hideBackground ? .clear : theme.blurredBackgroundColor, enableBackgroundBlur: enableBackgroundBlur, separatorColor: hideBackground || hideSeparator ? .clear : theme.separatorColor, badgeBackgroundColor: hideBadge ? .clear : theme.badgeBackgroundColor, badgeStrokeColor: hideBadge ? .clear : theme.badgeStrokeColor, badgeTextColor: hideBadge ? .clear : theme.badgeTextColor)
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,8 +63,8 @@ public extension NavigationBarPresentationData {
|
||||
self.init(theme: NavigationBarTheme(rootControllerTheme: presentationData.theme), strings: NavigationBarStrings(presentationStrings: presentationData.strings))
|
||||
}
|
||||
|
||||
convenience init(presentationData: PresentationData, hideBackground: Bool, hideBadge: Bool) {
|
||||
self.init(theme: NavigationBarTheme(rootControllerTheme: presentationData.theme, hideBackground: hideBackground, hideBadge: hideBadge), strings: NavigationBarStrings(presentationStrings: presentationData.strings))
|
||||
convenience init(presentationData: PresentationData, hideBackground: Bool, hideBadge: Bool, hideSeparator: Bool = false) {
|
||||
self.init(theme: NavigationBarTheme(rootControllerTheme: presentationData.theme, hideBackground: hideBackground, hideBadge: hideBadge, hideSeparator: hideSeparator), strings: NavigationBarStrings(presentationStrings: presentationData.strings))
|
||||
}
|
||||
|
||||
convenience init(presentationTheme: PresentationTheme, presentationStrings: PresentationStrings) {
|
||||
|
12
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/ReportDrugs.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/ReportDrugs.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "drugs_24.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
97
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/ReportDrugs.imageset/drugs_24.pdf
vendored
Normal file
97
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/ReportDrugs.imageset/drugs_24.pdf
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
0.707107 -0.707107 0.707107 0.707107 -0.794397 7.217199 cm
|
||||
0.000000 0.000000 0.000000 scn
|
||||
5.665000 23.093994 m
|
||||
2.536307 23.093994 0.000000 20.557688 0.000000 17.428993 c
|
||||
0.000000 11.626219 l
|
||||
0.000000 10.428994 l
|
||||
0.000000 7.428994 l
|
||||
0.000000 4.300301 2.536307 1.763992 5.665000 1.763992 c
|
||||
8.793693 1.763992 11.330000 4.300301 11.330000 7.428994 c
|
||||
11.330000 10.428994 l
|
||||
11.330000 11.626219 l
|
||||
11.330000 17.428993 l
|
||||
11.330000 20.557688 8.793693 23.093994 5.665000 23.093994 c
|
||||
h
|
||||
10.000000 13.456901 m
|
||||
10.000000 17.428993 l
|
||||
10.000000 19.823149 8.059155 21.763994 5.665000 21.763994 c
|
||||
3.270846 21.763994 1.330000 19.823149 1.330000 17.428993 c
|
||||
1.330000 13.456901 l
|
||||
2.192297 13.760678 3.608150 14.093994 5.665000 14.093994 c
|
||||
7.721851 14.093994 9.137704 13.760677 10.000000 13.456901 c
|
||||
h
|
||||
1.330000 11.626219 m
|
||||
1.330000 10.428994 l
|
||||
1.330000 7.428994 l
|
||||
1.330000 5.034840 3.270846 3.093994 5.665000 3.093994 c
|
||||
8.059155 3.093994 10.000000 5.034840 10.000000 7.428994 c
|
||||
10.000000 10.428994 l
|
||||
10.000000 11.626219 l
|
||||
10.000000 11.915585 9.860453 12.089630 9.704794 12.148787 c
|
||||
9.019821 12.409109 7.712020 12.763994 5.665000 12.763994 c
|
||||
3.617980 12.763994 2.310179 12.409109 1.625207 12.148788 c
|
||||
1.469548 12.089630 1.330000 11.915585 1.330000 11.626219 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
1275
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000001365 00000 n
|
||||
0000001388 00000 n
|
||||
0000001561 00000 n
|
||||
0000001635 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
1694
|
||||
%%EOF
|
@ -10325,7 +10325,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let currentLocationController = Atomic<AttachmentContainable?>(value: nil)
|
||||
|
||||
var canSendPolls = true
|
||||
if let _ = peer as? TelegramUser {
|
||||
if peer is TelegramUser || peer is TelegramSecretChat {
|
||||
canSendPolls = false
|
||||
} else if let channel = peer as? TelegramChannel {
|
||||
if channel.hasBannedPermission(.banSendPolls) != nil {
|
||||
@ -10434,11 +10434,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
})
|
||||
case .contact:
|
||||
let contactsController = ContactSelectionControllerImpl(ContactSelectionControllerParams(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, title: { $0.Contacts_Title }, displayDeviceContacts: true, multipleSelection: true))
|
||||
contactsController.presentScheduleTimePicker = { [weak self] completion in
|
||||
if let strongSelf = self {
|
||||
strongSelf.presentScheduleTimePicker(completion: completion)
|
||||
}
|
||||
}
|
||||
contactsController.navigationPresentation = .modal
|
||||
completion(contactsController, nil)
|
||||
completion(contactsController, contactsController.mediaPickerContext)
|
||||
strongSelf.controllerNavigationDisposable.set((contactsController.result
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peers in
|
||||
if let strongSelf = self, let (peers, _) = peers {
|
||||
if let strongSelf = self, let (peers, _, silent, scheduleTime) = peers {
|
||||
if peers.count > 1 {
|
||||
var enqueueMessages: [EnqueueMessage] = []
|
||||
for peer in peers {
|
||||
@ -10475,7 +10480,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
enqueueMessages.append(message)
|
||||
}
|
||||
}
|
||||
strongSelf.sendMessages(enqueueMessages)
|
||||
strongSelf.sendMessages(strongSelf.transformEnqueueMessages(enqueueMessages, silentPosting: silent, scheduleTime: scheduleTime))
|
||||
} else if let peer = peers.first {
|
||||
let dataSignal: Signal<(Peer?, DeviceContactExtendedData?), NoError>
|
||||
switch peer {
|
||||
@ -10531,7 +10536,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}, nil)
|
||||
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: replyMessageId, localGroupingKey: nil, correlationId: nil)
|
||||
strongSelf.sendMessages([message])
|
||||
strongSelf.sendMessages(strongSelf.transformEnqueueMessages([message], silentPosting: silent, scheduleTime: scheduleTime))
|
||||
} else {
|
||||
let contactController = strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .filter(peer: peerAndContactData.0, contactId: nil, contactData: contactData, completion: { peer, contactData in
|
||||
guard let strongSelf = self, !contactData.basicData.phoneNumbers.isEmpty else {
|
||||
@ -10549,7 +10554,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}, nil)
|
||||
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: replyMessageId, localGroupingKey: nil, correlationId: nil)
|
||||
strongSelf.sendMessages([message])
|
||||
strongSelf.sendMessages(strongSelf.transformEnqueueMessages([message], silentPosting: silent, scheduleTime: scheduleTime))
|
||||
}
|
||||
}), completed: nil, cancelled: nil)
|
||||
strongSelf.effectiveNavigationController?.pushViewController(contactController)
|
||||
@ -11267,7 +11272,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self.effectiveNavigationController?.pushViewController(contactsController)
|
||||
self.controllerNavigationDisposable.set((contactsController.result
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peers in
|
||||
if let strongSelf = self, let (peers, _) = peers {
|
||||
if let strongSelf = self, let (peers, _, _, _) = peers {
|
||||
if peers.count > 1 {
|
||||
var enqueueMessages: [EnqueueMessage] = []
|
||||
for peer in peers {
|
||||
|
@ -157,7 +157,7 @@ public class ComposeControllerImpl: ViewController, ComposeController {
|
||||
strongSelf.createActionDisposable.set((controller.result
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak controller] result in
|
||||
if let strongSelf = self, let (contactPeers, _) = result, case let .peer(peer, _, _) = contactPeers.first {
|
||||
if let strongSelf = self, let (contactPeers, _, _, _) = result, case let .peer(peer, _, _) = contactPeers.first {
|
||||
controller?.dismissSearch()
|
||||
controller?.displayNavigationActivity = true
|
||||
strongSelf.createActionDisposable.set((strongSelf.context.engine.peers.createSecretChat(peerId: peer.id) |> deliverOnMainQueue).start(next: { peerId in
|
||||
|
@ -17,7 +17,7 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
||||
private let context: AccountContext
|
||||
private let autoDismiss: Bool
|
||||
|
||||
private var contactsNode: ContactSelectionControllerNode {
|
||||
fileprivate var contactsNode: ContactSelectionControllerNode {
|
||||
return self.displayNode as! ContactSelectionControllerNode
|
||||
}
|
||||
|
||||
@ -43,14 +43,16 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
||||
return self._ready
|
||||
}
|
||||
|
||||
private let _result = Promise<([ContactListPeer], ContactListAction)?>()
|
||||
var result: Signal<([ContactListPeer], ContactListAction)?, NoError> {
|
||||
private let _result = Promise<([ContactListPeer], ContactListAction, Bool, Int32?)?>()
|
||||
var result: Signal<([ContactListPeer], ContactListAction, Bool, Int32?)?, NoError> {
|
||||
return self._result.get()
|
||||
}
|
||||
|
||||
private let confirmation: (ContactListPeer) -> Signal<Bool, NoError>
|
||||
var dismissed: (() -> Void)?
|
||||
|
||||
var presentScheduleTimePicker: (@escaping (Int32) -> Void) -> Void = { _ in }
|
||||
|
||||
private let createActionDisposable = MetaDisposable()
|
||||
private let confirmationDisposable = MetaDisposable()
|
||||
|
||||
@ -215,10 +217,10 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
||||
}
|
||||
}
|
||||
|
||||
self.contactsNode.requestMultipleAction = { [weak self] in
|
||||
self.contactsNode.requestMultipleAction = { [weak self] silent, scheduleTime in
|
||||
if let strongSelf = self {
|
||||
let selectedPeers = strongSelf.contactsNode.contactListNode.selectedPeers
|
||||
strongSelf._result.set(.single((selectedPeers, .generic)))
|
||||
strongSelf._result.set(.single((selectedPeers, .generic, silent, scheduleTime)))
|
||||
if strongSelf.autoDismiss {
|
||||
strongSelf.dismiss()
|
||||
}
|
||||
@ -313,7 +315,7 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
||||
self.confirmationDisposable.set((self.confirmation(peer) |> deliverOnMainQueue).start(next: { [weak self] value in
|
||||
if let strongSelf = self {
|
||||
if value {
|
||||
strongSelf._result.set(.single(([peer], action)))
|
||||
strongSelf._result.set(.single(([peer], action, false, nil)))
|
||||
if strongSelf.autoDismiss {
|
||||
strongSelf.dismiss()
|
||||
}
|
||||
@ -325,6 +327,10 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
||||
func dismissSearch() {
|
||||
self.deactivateSearch()
|
||||
}
|
||||
|
||||
public var mediaPickerContext: AttachmentMediaPickerContext {
|
||||
return ContactsPickerContext(controller: self)
|
||||
}
|
||||
}
|
||||
|
||||
private let searchBarFont = Font.regular(17.0)
|
||||
@ -380,3 +386,40 @@ final class ContactsSearchNavigationContentNode: NavigationBarContentNode {
|
||||
self.searchBar.updateThemeAndStrings(theme: SearchBarNodeTheme(theme: presentationData.theme, hasSeparator: false), strings: presentationData.strings)
|
||||
}
|
||||
}
|
||||
|
||||
final class ContactsPickerContext: AttachmentMediaPickerContext {
|
||||
private weak var controller: ContactSelectionControllerImpl?
|
||||
|
||||
var selectionCount: Signal<Int, NoError> {
|
||||
if let controller = self.controller {
|
||||
return controller.contactsNode.contactListNode.selectionStateSignal
|
||||
|> map { state in
|
||||
return state?.selectedPeerIndices.count ?? 0
|
||||
}
|
||||
} else {
|
||||
return .single(0)
|
||||
}
|
||||
}
|
||||
|
||||
var caption: Signal<NSAttributedString?, NoError> {
|
||||
return .single(nil)
|
||||
}
|
||||
|
||||
init(controller: ContactSelectionControllerImpl) {
|
||||
self.controller = controller
|
||||
}
|
||||
|
||||
func setCaption(_ caption: NSAttributedString) {
|
||||
|
||||
}
|
||||
|
||||
func send(silently: Bool, mode: AttachmentMediaPickerSendMode) {
|
||||
self.controller?.contactsNode.requestMultipleAction?(silently, nil)
|
||||
}
|
||||
|
||||
func schedule() {
|
||||
self.controller?.presentScheduleTimePicker ({ time in
|
||||
self.controller?.contactsNode.requestMultipleAction?(false, time)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ final class ContactSelectionControllerNode: ASDisplayNode {
|
||||
|
||||
var requestDeactivateSearch: (() -> Void)?
|
||||
var requestOpenPeerFromSearch: ((ContactListPeer) -> Void)?
|
||||
var requestMultipleAction: (() -> Void)?
|
||||
var requestMultipleAction: ((_ silent: Bool, _ scheduleTime: Int32?) -> Void)?
|
||||
var dismiss: (() -> Void)?
|
||||
|
||||
var presentationData: PresentationData {
|
||||
@ -58,7 +58,10 @@ final class ContactSelectionControllerNode: ASDisplayNode {
|
||||
self.displayDeviceContacts = displayDeviceContacts
|
||||
self.displayCallIcons = displayCallIcons
|
||||
|
||||
self.contactListNode = ContactListNode(context: context, updatedPresentationData: (presentationData, self.presentationDataPromise.get()), presentation: .single(.natural(options: options, includeChatList: false)), displayCallIcons: displayCallIcons, multipleSelection: multipleSelection)
|
||||
var contextActionImpl: ((EnginePeer, ASDisplayNode, ContextGesture?) -> Void)?
|
||||
self.contactListNode = ContactListNode(context: context, updatedPresentationData: (presentationData, self.presentationDataPromise.get()), presentation: .single(.natural(options: options, includeChatList: false)), displayCallIcons: displayCallIcons, contextAction: multipleSelection ? { peer, node, gesture in
|
||||
contextActionImpl?(peer, node, gesture)
|
||||
} : nil, multipleSelection: multipleSelection)
|
||||
|
||||
self.dimNode = ASDisplayNode()
|
||||
|
||||
@ -98,7 +101,17 @@ final class ContactSelectionControllerNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
shareImpl = { [weak self] in
|
||||
self?.requestMultipleAction?()
|
||||
self?.requestMultipleAction?(false, nil)
|
||||
}
|
||||
|
||||
contextActionImpl = { [weak self] peer, node, gesture in
|
||||
if let strongSelf = self, (strongSelf.selectionState?.selectedPeerIndices.isEmpty ?? true) {
|
||||
strongSelf.contactListNode.updateSelectionState { state in
|
||||
let peerId = ContactListPeerId.peer(peer.id)
|
||||
let state = state ?? ContactListNodeGroupSelectionState()
|
||||
return state.withToggledPeerId(peerId).withSelectedPeerMap([peerId: ContactListPeer.peer(peer: peer._asPeer(), isGlobal: false, participantCount: nil)])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,13 +147,13 @@ final class ContactSelectionControllerNode: ASDisplayNode {
|
||||
|
||||
self.contactListNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
|
||||
let countPanelHeight = self.countPanelNode.updateLayout(width: layout.size.width, sideInset: layout.safeInsets.left, bottomInset: layout.intrinsicInsets.bottom, transition: transition)
|
||||
if (self.selectionState?.selectedPeerIndices.isEmpty ?? true) {
|
||||
transition.updateFrame(node: self.countPanelNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height), size: CGSize(width: layout.size.width, height: countPanelHeight)))
|
||||
} else {
|
||||
insets.bottom += countPanelHeight
|
||||
transition.updateFrame(node: self.countPanelNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - countPanelHeight), size: CGSize(width: layout.size.width, height: countPanelHeight)))
|
||||
}
|
||||
// let countPanelHeight = self.countPanelNode.updateLayout(width: layout.size.width, sideInset: layout.safeInsets.left, bottomInset: layout.intrinsicInsets.bottom, transition: transition)
|
||||
// if (self.selectionState?.selectedPeerIndices.isEmpty ?? true) {
|
||||
// transition.updateFrame(node: self.countPanelNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height), size: CGSize(width: layout.size.width, height: countPanelHeight)))
|
||||
// } else {
|
||||
// insets.bottom += countPanelHeight
|
||||
// transition.updateFrame(node: self.countPanelNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - countPanelHeight), size: CGSize(width: layout.size.width, height: countPanelHeight)))
|
||||
// }
|
||||
|
||||
if let searchDisplayController = self.searchDisplayController {
|
||||
searchDisplayController.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
|
||||
|
@ -8059,7 +8059,7 @@ func presentAddMembers(context: AccountContext, updatedPresentationData: (initia
|
||||
if let contactsController = contactsController as? ContactSelectionController {
|
||||
selectAddMemberDisposable.set((contactsController.result
|
||||
|> deliverOnMainQueue).start(next: { [weak contactsController] result in
|
||||
guard let (peers, _) = result, let memberPeer = peers.first else {
|
||||
guard let (peers, _, _, _) = result, let memberPeer = peers.first else {
|
||||
return
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user