mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Attachment menu improvements
This commit is contained in:
parent
82104445dd
commit
7b8c90fbdc
@ -7307,25 +7307,13 @@ Sorry for the inconvenience.";
|
|||||||
"Attachment.OpenCamera" = "Open Camera";
|
"Attachment.OpenCamera" = "Open Camera";
|
||||||
|
|
||||||
"Attachment.DeselectedPhotos_1" = "%@ photo deselected";
|
"Attachment.DeselectedPhotos_1" = "%@ photo deselected";
|
||||||
"Attachment.DeselectedPhotos_2" = "%@ photos deselected";
|
|
||||||
"Attachment.DeselectedPhotos_3_10" = "%@ photos deselected";
|
|
||||||
"Attachment.DeselectedPhotos_any" = "%@ photos deselected";
|
"Attachment.DeselectedPhotos_any" = "%@ photos deselected";
|
||||||
"Attachment.DeselectedPhotos_many" = "%@ photos deselected";
|
|
||||||
"Attachment.DeselectedPhotos_0" = "%@ photos deselected";
|
|
||||||
|
|
||||||
"Attachment.DeselectedVideos_1" = "%@ video deselected";
|
"Attachment.DeselectedVideos_1" = "%@ video deselected";
|
||||||
"Attachment.DeselectedVideos_2" = "%@ videos deselected";
|
|
||||||
"Attachment.DeselectedVideos_3_10" = "%@ videos deselected";
|
|
||||||
"Attachment.DeselectedVideos_any" = "%@ videos deselected";
|
"Attachment.DeselectedVideos_any" = "%@ videos deselected";
|
||||||
"Attachment.DeselectedVideos_many" = "%@ videos deselected";
|
|
||||||
"Attachment.DeselectedVideos_0" = "%@ videos deselected";
|
|
||||||
|
|
||||||
"Attachment.DeselectedItems_1" = "%@ item deselected";
|
"Attachment.DeselectedItems_1" = "%@ item deselected";
|
||||||
"Attachment.DeselectedItems_2" = "%@ items deselected";
|
|
||||||
"Attachment.DeselectedItems_3_10" = "%@ items deselected";
|
|
||||||
"Attachment.DeselectedItems_any" = "%@ items deselected";
|
"Attachment.DeselectedItems_any" = "%@ items deselected";
|
||||||
"Attachment.DeselectedItems_many" = "%@ items deselected";
|
|
||||||
"Attachment.DeselectedItems_0" = "%@ items deselected";
|
|
||||||
|
|
||||||
"PrivacyPhoneNumberSettings.CustomPublicLink" = "Users who have your number saved in their contacts will also see it on Telegram.\n\nThis public link opens a chat with you:\n[https://t.me/%@]()";
|
"PrivacyPhoneNumberSettings.CustomPublicLink" = "Users who have your number saved in their contacts will also see it on Telegram.\n\nThis public link opens a chat with you:\n[https://t.me/%@]()";
|
||||||
|
|
||||||
@ -7357,3 +7345,6 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"Attachment.MyAlbums" = "My Albums";
|
"Attachment.MyAlbums" = "My Albums";
|
||||||
"Attachment.MediaTypes" = "Media Types";
|
"Attachment.MediaTypes" = "Media Types";
|
||||||
|
|
||||||
|
"Attachment.LocationAccessTitle" = "Access Your Location";
|
||||||
|
"Attachment.LocationAccessText" = "Share places or your live location.";
|
||||||
|
@ -289,7 +289,6 @@ public class AttachmentController: ViewController {
|
|||||||
self.currentType = type
|
self.currentType = type
|
||||||
self.controller?.requestController(type, { [weak self] controller, mediaPickerContext in
|
self.controller?.requestController(type, { [weak self] controller, mediaPickerContext in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.mediaPickerContext = mediaPickerContext
|
|
||||||
if let controller = controller {
|
if let controller = controller {
|
||||||
strongSelf.controller?._ready.set(controller.ready.get())
|
strongSelf.controller?._ready.set(controller.ready.get())
|
||||||
controller._presentedInModal = true
|
controller._presentedInModal = true
|
||||||
@ -346,6 +345,7 @@ public class AttachmentController: ViewController {
|
|||||||
strongSelf.switchingController = false
|
strongSelf.switchingController = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
strongSelf.mediaPickerContext = mediaPickerContext
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -419,7 +419,6 @@ public class AttachmentController: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var isCollapsed: Bool = false
|
|
||||||
private var isUpdatingContainer = false
|
private var isUpdatingContainer = false
|
||||||
private var switchingController = false
|
private var switchingController = false
|
||||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
@ -427,22 +426,15 @@ public class AttachmentController: ViewController {
|
|||||||
|
|
||||||
transition.updateFrame(node: self.dim, frame: CGRect(origin: CGPoint(), size: layout.size))
|
transition.updateFrame(node: self.dim, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||||
|
|
||||||
if self.modalProgress < 0.5 {
|
|
||||||
self.isCollapsed = false
|
|
||||||
} else if self.modalProgress == 1.0 {
|
|
||||||
self.isCollapsed = true
|
|
||||||
}
|
|
||||||
|
|
||||||
var containerLayout = layout
|
var containerLayout = layout
|
||||||
let containerRect: CGRect
|
let containerRect: CGRect
|
||||||
if case .regular = layout.metrics.widthClass {
|
if case .regular = layout.metrics.widthClass {
|
||||||
let size = CGSize(width: 390.0, height: 620.0)
|
let size = CGSize(width: 390.0, height: 620.0)
|
||||||
|
|
||||||
|
let insets = layout.insets(options: [.input])
|
||||||
let masterWidth = min(max(320.0, floor(layout.size.width / 3.0)), floor(layout.size.width / 2.0))
|
let masterWidth = min(max(320.0, floor(layout.size.width / 3.0)), floor(layout.size.width / 2.0))
|
||||||
var position: CGPoint = CGPoint(x: masterWidth - 174.0, y: layout.size.height - size.height - layout.intrinsicInsets.bottom - 40.0)
|
let position: CGPoint = CGPoint(x: masterWidth - 174.0, y: layout.size.height - size.height - insets.bottom - 40.0)
|
||||||
if let inputHeight = layout.inputHeight {
|
|
||||||
position.y -= inputHeight
|
|
||||||
}
|
|
||||||
containerRect = CGRect(origin: position, size: size)
|
containerRect = CGRect(origin: position, size: size)
|
||||||
containerLayout.size = containerRect.size
|
containerLayout.size = containerRect.size
|
||||||
containerLayout.intrinsicInsets.bottom = 12.0
|
containerLayout.intrinsicInsets.bottom = 12.0
|
||||||
@ -469,8 +461,8 @@ public class AttachmentController: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let isEffecitvelyCollapsedUpdated = (self.isCollapsed || self.selectionCount > 0) != (self.panel.isCollapsed || self.panel.isSelecting)
|
let isEffecitvelyCollapsedUpdated = (self.selectionCount > 0) != (self.panel.isSelecting)
|
||||||
let panelHeight = self.panel.update(layout: containerLayout, buttons: self.controller?.buttons ?? [], isCollapsed: self.isCollapsed, isSelecting: self.selectionCount > 0, transition: transition)
|
let panelHeight = self.panel.update(layout: containerLayout, buttons: self.controller?.buttons ?? [], isSelecting: self.selectionCount > 0, transition: transition)
|
||||||
var panelTransition = transition
|
var panelTransition = transition
|
||||||
if isEffecitvelyCollapsedUpdated {
|
if isEffecitvelyCollapsedUpdated {
|
||||||
panelTransition = .animated(duration: 0.25, curve: .easeInOut)
|
panelTransition = .animated(duration: 0.25, curve: .easeInOut)
|
||||||
|
@ -169,7 +169,6 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
private var buttons: [AttachmentButtonType] = []
|
private var buttons: [AttachmentButtonType] = []
|
||||||
private var selectedIndex: Int = 0
|
private var selectedIndex: Int = 0
|
||||||
private(set) var isCollapsed: Bool = false
|
|
||||||
private(set) var isSelecting: Bool = false
|
private(set) var isSelecting: Bool = false
|
||||||
|
|
||||||
private var validLayout: ContainerViewLayout?
|
private var validLayout: ContainerViewLayout?
|
||||||
@ -383,7 +382,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
strongSelf.updateChatPresentationInterfaceState({ $0.updatedTheme(presentationData.theme) })
|
strongSelf.updateChatPresentationInterfaceState({ $0.updatedTheme(presentationData.theme) })
|
||||||
|
|
||||||
if let layout = strongSelf.validLayout {
|
if let layout = strongSelf.validLayout {
|
||||||
let _ = strongSelf.update(layout: layout, buttons: strongSelf.buttons, isCollapsed: strongSelf.isCollapsed, isSelecting: strongSelf.isSelecting, transition: .immediate)
|
let _ = strongSelf.update(layout: layout, buttons: strongSelf.buttons, isSelecting: strongSelf.isSelecting, transition: .immediate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -551,12 +550,9 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(layout: ContainerViewLayout, buttons: [AttachmentButtonType], isCollapsed: Bool, isSelecting: Bool, transition: ContainedViewLayoutTransition) -> CGFloat {
|
func update(layout: ContainerViewLayout, buttons: [AttachmentButtonType], isSelecting: Bool, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||||
self.validLayout = layout
|
self.validLayout = layout
|
||||||
self.buttons = buttons
|
self.buttons = buttons
|
||||||
|
|
||||||
let isCollapsedUpdated = self.isCollapsed != isCollapsed
|
|
||||||
self.isCollapsed = isCollapsed
|
|
||||||
|
|
||||||
let isSelectingUpdated = self.isSelecting != isSelecting
|
let isSelectingUpdated = self.isSelecting != isSelecting
|
||||||
self.isSelecting = isSelecting
|
self.isSelecting = isSelecting
|
||||||
@ -605,7 +601,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
containerFrame = bounds
|
containerFrame = bounds
|
||||||
}
|
}
|
||||||
let containerBounds = CGRect(origin: CGPoint(), size: containerFrame.size)
|
let containerBounds = CGRect(origin: CGPoint(), size: containerFrame.size)
|
||||||
if isCollapsedUpdated || isSelectingUpdated {
|
if isSelectingUpdated {
|
||||||
containerTransition = .animated(duration: 0.25, curve: .easeInOut)
|
containerTransition = .animated(duration: 0.25, curve: .easeInOut)
|
||||||
} else {
|
} else {
|
||||||
containerTransition = transition
|
containerTransition = transition
|
||||||
@ -635,13 +631,9 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.backgroundNode.update(size: containerBounds.size, transition: transition)
|
self.backgroundNode.update(size: containerBounds.size, transition: transition)
|
||||||
containerTransition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: bounds.width, height: UIScreenPixel)))
|
containerTransition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: bounds.width, height: UIScreenPixel)))
|
||||||
|
|
||||||
let _ = self.updateScrollLayoutIfNeeded(force: isCollapsedUpdated || isSelectingUpdated, transition: containerTransition)
|
let _ = self.updateScrollLayoutIfNeeded(force: isSelectingUpdated, transition: containerTransition)
|
||||||
|
|
||||||
var buttonTransition: Transition = .immediate
|
self.updateViews(transition: .immediate)
|
||||||
if isCollapsedUpdated {
|
|
||||||
buttonTransition = .easeInOut(duration: 0.25)
|
|
||||||
}
|
|
||||||
self.updateViews(transition: buttonTransition)
|
|
||||||
|
|
||||||
return containerFrame.height
|
return containerFrame.height
|
||||||
}
|
}
|
||||||
|
@ -1499,7 +1499,10 @@ public final class ContactListNode: ASDisplayNode {
|
|||||||
self.indexNode.update(size: indexNodeFrame.size, color: self.presentationData.theme.list.itemAccentColor, sections: indexSections, transition: transition)
|
self.indexNode.update(size: indexNodeFrame.size, color: self.presentationData.theme.list.itemAccentColor, sections: indexSections, transition: transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.authorizationNode.updateLayout(size: layout.size, insets: insets, transition: transition)
|
let permissionSize = CGSize(width: layout.size.width, height: layout.size.height - 160.0)
|
||||||
|
var permissionInsets = insets
|
||||||
|
permissionInsets.bottom += 100.0
|
||||||
|
self.authorizationNode.updateLayout(size: permissionSize, insets: permissionInsets, transition: transition)
|
||||||
transition.updateFrame(node: self.authorizationNode, frame: self.bounds)
|
transition.updateFrame(node: self.authorizationNode, frame: self.bounds)
|
||||||
|
|
||||||
if !hadValidLayout {
|
if !hadValidLayout {
|
||||||
|
@ -20,7 +20,6 @@ public enum DeviceAccessCameraSubject {
|
|||||||
case qrCode
|
case qrCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public enum DeviceAccessMicrophoneSubject {
|
public enum DeviceAccessMicrophoneSubject {
|
||||||
case audio
|
case audio
|
||||||
case video
|
case video
|
||||||
|
@ -1056,7 +1056,7 @@ open class NavigationBar: ASDisplayNode {
|
|||||||
var rightTitleInset: CGFloat = rightInset + 1.0
|
var rightTitleInset: CGFloat = rightInset + 1.0
|
||||||
if self.backButtonNode.supernode != nil {
|
if self.backButtonNode.supernode != nil {
|
||||||
let backButtonSize = self.backButtonNode.updateLayout(constrainedSize: CGSize(width: size.width, height: nominalHeight), isLandscape: isLandscape)
|
let backButtonSize = self.backButtonNode.updateLayout(constrainedSize: CGSize(width: size.width, height: nominalHeight), isLandscape: isLandscape)
|
||||||
leftTitleInset += backButtonSize.width + backButtonInset + 1.0
|
leftTitleInset = backButtonSize.width + backButtonInset + 1.0
|
||||||
|
|
||||||
let topHitTestSlop = (nominalHeight - backButtonSize.height) * 0.5
|
let topHitTestSlop = (nominalHeight - backButtonSize.height) * 0.5
|
||||||
self.backButtonNode.hitTestSlop = UIEdgeInsets(top: -topHitTestSlop, left: -27.0, bottom: -topHitTestSlop, right: -8.0)
|
self.backButtonNode.hitTestSlop = UIEdgeInsets(top: -topHitTestSlop, left: -27.0, bottom: -topHitTestSlop, right: -8.0)
|
||||||
|
@ -900,7 +900,7 @@ public final class ListMessageFileItemNode: ListMessageNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
transition.updateFrame(node: strongSelf.separatorNode, frame: CGRect(origin: CGPoint(x: leftInset + leftOffset, y: nodeLayout.contentSize.height - UIScreenPixel), size: CGSize(width: params.width - leftInset - leftOffset, height: UIScreenPixel)))
|
transition.updateFrame(node: strongSelf.separatorNode, frame: CGRect(origin: CGPoint(x: leftInset + leftOffset, y: nodeLayout.contentSize.height - UIScreenPixel), size: CGSize(width: params.width - leftInset - leftOffset, height: UIScreenPixel)))
|
||||||
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: nodeLayout.size.height + UIScreenPixel))
|
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -nodeLayout.insets.top - UIScreenPixel), size: CGSize(width: params.width, height: nodeLayout.size.height + UIScreenPixel - nodeLayout.insets.bottom))
|
||||||
|
|
||||||
if let backgroundNode = strongSelf.backgroundNode {
|
if let backgroundNode = strongSelf.backgroundNode {
|
||||||
backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -nodeLayout.insets.top), size: CGSize(width: params.width, height: nodeLayout.size.height - nodeLayout.insets.bottom))
|
backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -nodeLayout.insets.top), size: CGSize(width: params.width, height: nodeLayout.size.height - nodeLayout.insets.bottom))
|
||||||
|
@ -43,6 +43,8 @@ swift_library(
|
|||||||
"//submodules/TooltipUI:TooltipUI",
|
"//submodules/TooltipUI:TooltipUI",
|
||||||
"//submodules/UndoUI:UndoUI",
|
"//submodules/UndoUI:UndoUI",
|
||||||
"//submodules/AttachmentUI:AttachmentUI",
|
"//submodules/AttachmentUI:AttachmentUI",
|
||||||
|
"//submodules/AnimatedStickerNode:AnimatedStickerNode",
|
||||||
|
"//submodules/TelegramAnimatedStickerNode:TelegramAnimatedStickerNode",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -294,7 +294,7 @@ public final class LocationPickerController: ViewController, AttachmentContainab
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.displayNode = LocationPickerControllerNode(context: self.context, presentationData: self.presentationData, mode: self.mode, interaction: interaction, locationManager: self.locationManager)
|
self.displayNode = LocationPickerControllerNode(controller: self, context: self.context, presentationData: self.presentationData, mode: self.mode, interaction: interaction, locationManager: self.locationManager)
|
||||||
self.displayNodeDidLoad()
|
self.displayNodeDidLoad()
|
||||||
self.controllerNode.beganInteractiveDragging = { [weak self] in
|
self.controllerNode.beganInteractiveDragging = { [weak self] in
|
||||||
self?.requestAttachmentMenuExpansion()
|
self?.requestAttachmentMenuExpansion()
|
||||||
@ -324,6 +324,8 @@ public final class LocationPickerController: ViewController, AttachmentContainab
|
|||||||
})
|
})
|
||||||
|
|
||||||
self.navigationBar?.passthroughTouches = false
|
self.navigationBar?.passthroughTouches = false
|
||||||
|
|
||||||
|
self.updateTabBarAlpha(1.0, .immediate)
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
@ -349,6 +351,6 @@ public final class LocationPickerController: ViewController, AttachmentContainab
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func prepareForReuse() {
|
public func prepareForReuse() {
|
||||||
self.updateTabBarAlpha(1.0, .animated(duration: 0.25, curve: .easeInOut))
|
self.updateTabBarAlpha(1.0, .immediate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,7 +240,44 @@ struct LocationPickerState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class LocationContext: NSObject, CLLocationManagerDelegate {
|
||||||
|
private let locationManager: CLLocationManager
|
||||||
|
|
||||||
|
private let accessSink = ValuePipe<CLAuthorizationStatus>()
|
||||||
|
|
||||||
|
override init() {
|
||||||
|
self.locationManager = CLLocationManager()
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.locationManager.delegate = self
|
||||||
|
}
|
||||||
|
|
||||||
|
func locationAccess() -> Signal<CLAuthorizationStatus, NoError> {
|
||||||
|
let initialStatus: CLAuthorizationStatus
|
||||||
|
if #available(iOS 14.0, *) {
|
||||||
|
initialStatus = self.locationManager.authorizationStatus
|
||||||
|
} else {
|
||||||
|
initialStatus = CLLocationManager.authorizationStatus()
|
||||||
|
}
|
||||||
|
return .single(initialStatus)
|
||||||
|
|> then(
|
||||||
|
self.accessSink.signal()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 14.0, *)
|
||||||
|
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
|
||||||
|
self.accessSink.putNext(manager.authorizationStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
|
||||||
|
self.accessSink.putNext(status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationManagerDelegate {
|
final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationManagerDelegate {
|
||||||
|
private weak var controller: LocationPickerController?
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
private let presentationDataPromise: Promise<PresentationData>
|
private let presentationDataPromise: Promise<PresentationData>
|
||||||
@ -248,6 +285,8 @@ final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationM
|
|||||||
private let interaction: LocationPickerInteraction
|
private let interaction: LocationPickerInteraction
|
||||||
private let locationManager: LocationManager
|
private let locationManager: LocationManager
|
||||||
|
|
||||||
|
private let locationContext: LocationContext
|
||||||
|
|
||||||
private let listNode: ListView
|
private let listNode: ListView
|
||||||
private let emptyResultsTextNode: ImmediateTextNode
|
private let emptyResultsTextNode: ImmediateTextNode
|
||||||
private let headerNode: LocationMapHeaderNode
|
private let headerNode: LocationMapHeaderNode
|
||||||
@ -257,6 +296,10 @@ final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationM
|
|||||||
private let optionsNode: LocationOptionsNode
|
private let optionsNode: LocationOptionsNode
|
||||||
private(set) var searchContainerNode: LocationSearchContainerNode?
|
private(set) var searchContainerNode: LocationSearchContainerNode?
|
||||||
|
|
||||||
|
private var placeholderBackgroundNode: NavigationBackgroundNode?
|
||||||
|
private var placeholderNode: LocationPlaceholderNode?
|
||||||
|
private var locationAccessDenied = true
|
||||||
|
|
||||||
private var enqueuedTransitions: [LocationPickerTransaction] = []
|
private var enqueuedTransitions: [LocationPickerTransaction] = []
|
||||||
|
|
||||||
private var disposable: Disposable?
|
private var disposable: Disposable?
|
||||||
@ -271,7 +314,8 @@ final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationM
|
|||||||
|
|
||||||
var beganInteractiveDragging: () -> Void = {}
|
var beganInteractiveDragging: () -> Void = {}
|
||||||
|
|
||||||
init(context: AccountContext, presentationData: PresentationData, mode: LocationPickerMode, interaction: LocationPickerInteraction, locationManager: LocationManager) {
|
init(controller: LocationPickerController, context: AccountContext, presentationData: PresentationData, mode: LocationPickerMode, interaction: LocationPickerInteraction, locationManager: LocationManager) {
|
||||||
|
self.controller = controller
|
||||||
self.context = context
|
self.context = context
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.presentationDataPromise = Promise(presentationData)
|
self.presentationDataPromise = Promise(presentationData)
|
||||||
@ -279,6 +323,8 @@ final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationM
|
|||||||
self.interaction = interaction
|
self.interaction = interaction
|
||||||
self.locationManager = locationManager
|
self.locationManager = locationManager
|
||||||
|
|
||||||
|
self.locationContext = LocationContext()
|
||||||
|
|
||||||
self.state = LocationPickerState()
|
self.state = LocationPickerState()
|
||||||
self.statePromise = Promise(self.state)
|
self.statePromise = Promise(self.state)
|
||||||
|
|
||||||
@ -448,8 +494,8 @@ final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationM
|
|||||||
let previousAnnotations = Atomic<[LocationPinAnnotation]>(value: [])
|
let previousAnnotations = Atomic<[LocationPinAnnotation]>(value: [])
|
||||||
let previousEntries = Atomic<[LocationPickerEntry]?>(value: nil)
|
let previousEntries = Atomic<[LocationPickerEntry]?>(value: nil)
|
||||||
|
|
||||||
self.disposable = (combineLatest(self.presentationDataPromise.get(), self.statePromise.get(), userLocation, venues, foundVenues)
|
self.disposable = (combineLatest(self.presentationDataPromise.get(), self.statePromise.get(), userLocation, venues, foundVenues, self.locationContext.locationAccess())
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData, state, userLocation, venues, foundVenuesAndLocation in
|
|> deliverOnMainQueue).start(next: { [weak self] presentationData, state, userLocation, venues, foundVenuesAndLocation, access in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let (foundVenues, foundVenuesLocation) = foundVenuesAndLocation ?? (nil, nil)
|
let (foundVenues, foundVenuesLocation) = foundVenuesAndLocation ?? (nil, nil)
|
||||||
|
|
||||||
@ -589,6 +635,18 @@ final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationM
|
|||||||
if let (layout, navigationBarHeight) = strongSelf.validLayout {
|
if let (layout, navigationBarHeight) = strongSelf.validLayout {
|
||||||
var updateLayout = false
|
var updateLayout = false
|
||||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.45, curve: .spring)
|
let transition: ContainedViewLayoutTransition = .animated(duration: 0.45, curve: .spring)
|
||||||
|
|
||||||
|
if [.denied, .restricted].contains(access) {
|
||||||
|
if !strongSelf.locationAccessDenied {
|
||||||
|
strongSelf.locationAccessDenied = true
|
||||||
|
updateLayout = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if strongSelf.locationAccessDenied {
|
||||||
|
strongSelf.locationAccessDenied = false
|
||||||
|
updateLayout = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if previousState.displayingMapModeOptions != state.displayingMapModeOptions {
|
if previousState.displayingMapModeOptions != state.displayingMapModeOptions {
|
||||||
updateLayout = true
|
updateLayout = true
|
||||||
@ -892,6 +950,49 @@ final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationM
|
|||||||
searchContainerNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
searchContainerNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||||
searchContainerNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: LayoutMetrics(), deviceMetrics: layout.deviceMetrics, intrinsicInsets: layout.intrinsicInsets, safeInsets: layout.safeInsets, additionalInsets: layout.additionalInsets, statusBarHeight: nil, inputHeight: layout.inputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), navigationBarHeight: navigationHeight, transition: transition)
|
searchContainerNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: LayoutMetrics(), deviceMetrics: layout.deviceMetrics, intrinsicInsets: layout.intrinsicInsets, safeInsets: layout.safeInsets, additionalInsets: layout.additionalInsets, statusBarHeight: nil, inputHeight: layout.inputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), navigationBarHeight: navigationHeight, transition: transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.locationAccessDenied {
|
||||||
|
self.controller?.navigationBar?.updateBackgroundAlpha(0.0, transition: .immediate)
|
||||||
|
Queue.mainQueue().after(0.2) {
|
||||||
|
self.controller?.updateTabBarAlpha(0.0, .immediate)
|
||||||
|
}
|
||||||
|
|
||||||
|
var placeholderTransition = transition
|
||||||
|
let placeholderNode: LocationPlaceholderNode
|
||||||
|
let backgroundNode: NavigationBackgroundNode
|
||||||
|
if let current = self.placeholderNode, let background = self.placeholderBackgroundNode {
|
||||||
|
placeholderNode = current
|
||||||
|
backgroundNode = background
|
||||||
|
|
||||||
|
backgroundNode.updateColor(color: self.presentationData.theme.rootController.tabBar.backgroundColor, transition: .immediate)
|
||||||
|
} else {
|
||||||
|
backgroundNode = NavigationBackgroundNode(color: self.presentationData.theme.rootController.tabBar.backgroundColor)
|
||||||
|
if let navigationBar = self.controller?.navigationBar {
|
||||||
|
self.insertSubnode(backgroundNode, belowSubnode: navigationBar)
|
||||||
|
} else {
|
||||||
|
self.addSubnode(backgroundNode)
|
||||||
|
}
|
||||||
|
self.placeholderBackgroundNode = backgroundNode
|
||||||
|
|
||||||
|
placeholderNode = LocationPlaceholderNode(content: .intro)
|
||||||
|
placeholderNode.settingsPressed = { [weak self] in
|
||||||
|
self?.context.sharedContext.applicationBindings.openSettings()
|
||||||
|
}
|
||||||
|
self.insertSubnode(placeholderNode, aboveSubnode: backgroundNode)
|
||||||
|
self.placeholderNode = placeholderNode
|
||||||
|
|
||||||
|
placeholderTransition = .immediate
|
||||||
|
}
|
||||||
|
placeholderNode.update(layout: layout, theme: self.presentationData.theme, strings: self.presentationData.strings, transition: placeholderTransition)
|
||||||
|
placeholderTransition.updateFrame(node: placeholderNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||||
|
|
||||||
|
let placeholderFrame = CGRect(origin: CGPoint(), size: layout.size)
|
||||||
|
backgroundNode.update(size: placeholderFrame.size, transition: placeholderTransition)
|
||||||
|
placeholderTransition.updateFrame(node: placeholderNode, frame: placeholderFrame)
|
||||||
|
} else if let placeholderNode = self.placeholderNode {
|
||||||
|
self.placeholderNode = nil
|
||||||
|
placeholderNode.removeFromSupernode()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateSendActionHighlight(_ highlighted: Bool) {
|
func updateSendActionHighlight(_ highlighted: Bool) {
|
||||||
|
134
submodules/LocationUI/Sources/LocationPlaceholderNode.swift
Normal file
134
submodules/LocationUI/Sources/LocationPlaceholderNode.swift
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import Display
|
||||||
|
import TelegramPresentationData
|
||||||
|
import AnimatedStickerNode
|
||||||
|
import TelegramAnimatedStickerNode
|
||||||
|
import SolidRoundedButtonNode
|
||||||
|
import PresentationDataUtils
|
||||||
|
|
||||||
|
final class LocationPlaceholderNode: ASDisplayNode {
|
||||||
|
enum Content {
|
||||||
|
case intro
|
||||||
|
}
|
||||||
|
|
||||||
|
private let content: Content
|
||||||
|
|
||||||
|
private var animationNode: AnimatedStickerNode
|
||||||
|
private let titleNode: ImmediateTextNode
|
||||||
|
private let textNode: ImmediateTextNode
|
||||||
|
private let buttonNode: SolidRoundedButtonNode
|
||||||
|
private var validLayout: ContainerViewLayout?
|
||||||
|
|
||||||
|
private var cameraTextNode: ImmediateTextNode
|
||||||
|
|
||||||
|
var settingsPressed: () -> Void = {}
|
||||||
|
var cameraPressed: () -> Void = {}
|
||||||
|
|
||||||
|
init(content: Content) {
|
||||||
|
self.content = content
|
||||||
|
|
||||||
|
let name: String
|
||||||
|
let playbackMode: AnimatedStickerPlaybackMode
|
||||||
|
switch content {
|
||||||
|
case .intro:
|
||||||
|
name = "Location"
|
||||||
|
playbackMode = .loop
|
||||||
|
}
|
||||||
|
|
||||||
|
self.animationNode = AnimatedStickerNode()
|
||||||
|
self.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: name), width: 320, height: 320, playbackMode: playbackMode, mode: .direct(cachePathPrefix: nil))
|
||||||
|
self.animationNode.visibility = true
|
||||||
|
|
||||||
|
self.titleNode = ImmediateTextNode()
|
||||||
|
self.titleNode.isUserInteractionEnabled = false
|
||||||
|
self.titleNode.textAlignment = .center
|
||||||
|
self.titleNode.maximumNumberOfLines = 1
|
||||||
|
|
||||||
|
self.textNode = ImmediateTextNode()
|
||||||
|
self.textNode.isUserInteractionEnabled = false
|
||||||
|
self.textNode.lineSpacing = 0.1
|
||||||
|
self.textNode.textAlignment = .center
|
||||||
|
self.textNode.maximumNumberOfLines = 0
|
||||||
|
|
||||||
|
self.buttonNode = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(backgroundColor: .black, foregroundColor: .white), height: 50.0, cornerRadius: 12.0, gloss: true)
|
||||||
|
|
||||||
|
self.cameraTextNode = ImmediateTextNode()
|
||||||
|
self.cameraTextNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.addSubnode(self.animationNode)
|
||||||
|
self.addSubnode(self.textNode)
|
||||||
|
|
||||||
|
if case .intro = self.content {
|
||||||
|
self.addSubnode(self.titleNode)
|
||||||
|
self.addSubnode(self.buttonNode)
|
||||||
|
|
||||||
|
self.buttonNode.pressed = { [weak self] in
|
||||||
|
self?.settingsPressed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var theme: PresentationTheme?
|
||||||
|
func update(layout: ContainerViewLayout, theme: PresentationTheme, strings: PresentationStrings, transition: ContainedViewLayoutTransition) {
|
||||||
|
self.validLayout = layout
|
||||||
|
let themeUpdated = self.theme != theme
|
||||||
|
self.theme = theme
|
||||||
|
|
||||||
|
var imageSize = CGSize(width: 144.0, height: 144.0)
|
||||||
|
var insets = layout.insets(options: [])
|
||||||
|
if layout.size.width == 460.0 {
|
||||||
|
insets.top += -60.0
|
||||||
|
imageSize = CGSize(width: 112.0, height: 112.0)
|
||||||
|
} else {
|
||||||
|
insets.top += -160.0
|
||||||
|
}
|
||||||
|
|
||||||
|
let imageSpacing: CGFloat = 12.0
|
||||||
|
let textSpacing: CGFloat = 12.0
|
||||||
|
let buttonSpacing: CGFloat = 15.0
|
||||||
|
let cameraSpacing: CGFloat = 13.0
|
||||||
|
|
||||||
|
let imageHeight = layout.size.width < layout.size.height ? imageSize.height + imageSpacing : 0.0
|
||||||
|
|
||||||
|
if themeUpdated {
|
||||||
|
self.buttonNode.updateTheme(SolidRoundedButtonTheme(theme: theme))
|
||||||
|
}
|
||||||
|
self.buttonNode.title = strings.Attachment_OpenSettings
|
||||||
|
let buttonWidth: CGFloat = 248.0
|
||||||
|
let buttonHeight = self.buttonNode.updateLayout(width: buttonWidth, transition: transition)
|
||||||
|
|
||||||
|
let title: String
|
||||||
|
let text: String
|
||||||
|
switch self.content {
|
||||||
|
case .intro:
|
||||||
|
title = strings.Attachment_LocationAccessTitle
|
||||||
|
text = strings.Attachment_LocationAccessText
|
||||||
|
}
|
||||||
|
|
||||||
|
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.medium(17.0), textColor: theme.list.itemPrimaryTextColor, paragraphAlignment: .center)
|
||||||
|
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(15.0), textColor: theme.list.freeTextColor, paragraphAlignment: .center)
|
||||||
|
self.cameraTextNode.attributedText = NSAttributedString(string: strings.Attachment_OpenCamera, font: Font.regular(17.0), textColor: theme.list.itemAccentColor, paragraphAlignment: .center)
|
||||||
|
|
||||||
|
let titleSize = self.titleNode.updateLayout(CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 40.0, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
||||||
|
let textSize = self.textNode.updateLayout(CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 40.0, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
||||||
|
let cameraSize = self.cameraTextNode.updateLayout(CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 70.0, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
||||||
|
|
||||||
|
let totalHeight = imageHeight + titleSize.height + textSpacing + textSize.height + buttonSpacing + buttonHeight + cameraSpacing + cameraSize.height
|
||||||
|
let topOffset = insets.top + floor((layout.size.height - insets.top - insets.bottom - totalHeight) / 2.0)
|
||||||
|
|
||||||
|
transition.updateAlpha(node: self.animationNode, alpha: imageHeight > 0.0 ? 1.0 : 0.0)
|
||||||
|
transition.updateFrame(node: self.animationNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - imageSize.width) / 2.0), y: topOffset), size: imageSize))
|
||||||
|
self.animationNode.updateLayout(size: imageSize)
|
||||||
|
|
||||||
|
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + floor((layout.size.width - titleSize.width - layout.safeInsets.left - layout.safeInsets.right) / 2.0), y: topOffset + imageHeight), size: titleSize))
|
||||||
|
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + floor((layout.size.width - textSize.width - layout.safeInsets.left - layout.safeInsets.right) / 2.0), y: self.titleNode.frame.maxY + textSpacing), size: textSize))
|
||||||
|
|
||||||
|
transition.updateFrame(node: self.buttonNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + floor((layout.size.width - buttonWidth - layout.safeInsets.left - layout.safeInsets.right) / 2.0), y: self.textNode.frame.maxY + buttonSpacing), size: CGSize(width: buttonWidth, height: buttonHeight)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -120,6 +120,7 @@ private final class MediaGroupsGridAlbumItemNode : ListViewItemNode {
|
|||||||
self.imageNode = ImageNode()
|
self.imageNode = ImageNode()
|
||||||
self.imageNode.clipsToBounds = true
|
self.imageNode.clipsToBounds = true
|
||||||
self.imageNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 62.0, height: 62.0))
|
self.imageNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 62.0, height: 62.0))
|
||||||
|
self.imageNode.contentMode = .scaleAspectFill
|
||||||
|
|
||||||
self.titleNode = TextNode()
|
self.titleNode = TextNode()
|
||||||
self.titleNode.isUserInteractionEnabled = false
|
self.titleNode.isUserInteractionEnabled = false
|
||||||
@ -332,13 +333,19 @@ private class MediaGroupsAlbumGridItemNode: ListViewItemNode {
|
|||||||
let listInsets = UIEdgeInsets(top: 10.0, left: 0.0, bottom: 10.0, right: 0.0)
|
let listInsets = UIEdgeInsets(top: 10.0, left: 0.0, bottom: 10.0, right: 0.0)
|
||||||
strongSelf.listNode.bounds = CGRect(x: 0.0, y: 0.0, width: contentSize.height, height: contentSize.width - params.leftInset - params.rightInset)
|
strongSelf.listNode.bounds = CGRect(x: 0.0, y: 0.0, width: contentSize.height, height: contentSize.width - params.leftInset - params.rightInset)
|
||||||
strongSelf.listNode.position = CGPoint(x: contentSize.width / 2.0, y: contentSize.height / 2.0)
|
strongSelf.listNode.position = CGPoint(x: contentSize.width / 2.0, y: contentSize.height / 2.0)
|
||||||
strongSelf.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: CGSize(width: contentSize.height, height: contentSize.width), insets: listInsets, duration: 0.0, curve: .Default(duration: nil)), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
strongSelf.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: CGSize(width: contentSize.height, height: contentSize.width - params.leftInset - params.rightInset), insets: listInsets, duration: 0.0, curve: .Default(duration: nil)), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||||
|
|
||||||
var entries: [MediaGroupsGridAlbumEntry] = []
|
var entries: [MediaGroupsGridAlbumEntry] = []
|
||||||
var index: Int = 0
|
var index: Int = 0
|
||||||
for collection in item.collections {
|
for collection in item.collections {
|
||||||
let result = PHAsset.fetchAssets(in: collection, options: nil)
|
let result = PHAsset.fetchAssets(in: collection, options: nil)
|
||||||
if let firstItem = result.firstObject {
|
let firstItem: PHAsset?
|
||||||
|
if collection.assetCollectionSubtype == .smartAlbumUserLibrary {
|
||||||
|
firstItem = result.lastObject
|
||||||
|
} else {
|
||||||
|
firstItem = result.firstObject
|
||||||
|
}
|
||||||
|
if let firstItem = firstItem {
|
||||||
entries.append(MediaGroupsGridAlbumEntry(theme: item.presentationData.theme, index: index, collection: collection, firstItem: firstItem, count: presentationStringsFormattedNumber(Int32(result.count))))
|
entries.append(MediaGroupsGridAlbumEntry(theme: item.presentationData.theme, index: index, collection: collection, firstItem: firstItem, count: presentationStringsFormattedNumber(Int32(result.count))))
|
||||||
index += 1
|
index += 1
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@ import AttachmentUI
|
|||||||
import ContextUI
|
import ContextUI
|
||||||
import WebSearchUI
|
import WebSearchUI
|
||||||
|
|
||||||
|
let overflowInset: CGFloat = 70.0
|
||||||
|
|
||||||
final class MediaPickerInteraction {
|
final class MediaPickerInteraction {
|
||||||
let openMedia: (PHFetchResult<PHAsset>, Int, UIImage?) -> Void
|
let openMedia: (PHFetchResult<PHAsset>, Int, UIImage?) -> Void
|
||||||
let openSelectedMedia: (TGMediaSelectableItem, UIImage?) -> Void
|
let openSelectedMedia: (TGMediaSelectableItem, UIImage?) -> Void
|
||||||
@ -281,6 +283,12 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
self.gridNode.scrollView.alwaysBounceVertical = true
|
self.gridNode.scrollView.alwaysBounceVertical = true
|
||||||
self.gridNode.scrollView.showsVerticalScrollIndicator = false
|
self.gridNode.scrollView.showsVerticalScrollIndicator = false
|
||||||
|
|
||||||
|
if self.controller?.collection != nil {
|
||||||
|
self.gridNode.view.interactiveTransitionGestureRecognizerTest = { point -> Bool in
|
||||||
|
return point.x > 44.0 + overflowInset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if self.controller?.collection == nil {
|
if self.controller?.collection == nil {
|
||||||
let cameraView = TGAttachmentCameraView(forSelfPortrait: false)!
|
let cameraView = TGAttachmentCameraView(forSelfPortrait: false)!
|
||||||
cameraView.clipsToBounds = true
|
cameraView.clipsToBounds = true
|
||||||
@ -315,6 +323,9 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
strongSelf.controller?.interaction?.selectionState?.setItem(asset, selected: selected, animated: true, sender: nil)
|
strongSelf.controller?.interaction?.selectionState?.setItem(asset, selected: selected, animated: true, sender: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if self.controller?.collection != nil {
|
||||||
|
self.selectionGesture?.sideInset = 44.0 + overflowInset
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||||
@ -324,7 +335,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func dismissInput() {
|
fileprivate func dismissInput() {
|
||||||
self.view.window?.endEditing(true)
|
self.view.window?.endEditing(true)
|
||||||
}
|
}
|
||||||
@ -611,13 +622,20 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
|
|
||||||
private var previousContentOffset: GridNodeVisibleContentOffset?
|
private var previousContentOffset: GridNodeVisibleContentOffset?
|
||||||
|
|
||||||
func updateNavigation(transition: ContainedViewLayoutTransition) {
|
func updateNavigation(delayDisappear: Bool = false, transition: ContainedViewLayoutTransition) {
|
||||||
if let selectionNode = self.selectionNode, selectionNode.alpha > 0.0 {
|
if let selectionNode = self.selectionNode, selectionNode.alpha > 0.0 {
|
||||||
self.controller?.navigationBar?.updateBackgroundAlpha(1.0, transition: .immediate)
|
self.controller?.navigationBar?.updateBackgroundAlpha(1.0, transition: .immediate)
|
||||||
self.controller?.updateTabBarAlpha(1.0, transition)
|
self.controller?.updateTabBarAlpha(1.0, transition)
|
||||||
} else if self.placeholderNode != nil {
|
} else if self.placeholderNode != nil {
|
||||||
self.controller?.navigationBar?.updateBackgroundAlpha(0.0, transition: .immediate)
|
self.controller?.navigationBar?.updateBackgroundAlpha(0.0, transition: .immediate)
|
||||||
self.controller?.updateTabBarAlpha(0.0, transition)
|
|
||||||
|
if delayDisappear {
|
||||||
|
Queue.mainQueue().after(0.2) {
|
||||||
|
self.controller?.updateTabBarAlpha(0.0, transition)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.controller?.updateTabBarAlpha(0.0, transition)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
var previousContentOffsetValue: CGFloat?
|
var previousContentOffsetValue: CGFloat?
|
||||||
if let previousContentOffset = self.previousContentOffset, case let .known(value) = previousContentOffset {
|
if let previousContentOffset = self.previousContentOffset, case let .known(value) = previousContentOffset {
|
||||||
@ -637,6 +655,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
case .unknown, .none:
|
case .unknown, .none:
|
||||||
self.controller?.navigationBar?.updateBackgroundAlpha(1.0, transition: .immediate)
|
self.controller?.navigationBar?.updateBackgroundAlpha(1.0, transition: .immediate)
|
||||||
}
|
}
|
||||||
|
self.controller?.updateTabBarAlpha(1.0, transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
let count = Int32(self.controller?.interaction?.selectionState?.count() ?? 0)
|
let count = Int32(self.controller?.interaction?.selectionState?.count() ?? 0)
|
||||||
@ -652,7 +671,6 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
var insets = layout.insets(options: [])
|
var insets = layout.insets(options: [])
|
||||||
insets.top += navigationBarHeight
|
insets.top += navigationBarHeight
|
||||||
|
|
||||||
let overflowInset: CGFloat = 70.0
|
|
||||||
let bounds = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: layout.size.height))
|
let bounds = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: layout.size.height))
|
||||||
let innerBounds = CGRect(origin: CGPoint(x: -overflowInset, y: 0.0), size: CGSize(width: layout.size.width, height: layout.size.height))
|
let innerBounds = CGRect(origin: CGPoint(x: -overflowInset, y: 0.0), size: CGSize(width: layout.size.width, height: layout.size.height))
|
||||||
|
|
||||||
@ -1039,9 +1057,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
public func prepareForReuse() {
|
public func prepareForReuse() {
|
||||||
self.controllerNode.cameraView?.resumePreview()
|
self.controllerNode.cameraView?.resumePreview()
|
||||||
|
|
||||||
Queue.mainQueue().after(0.2, {
|
self.controllerNode.updateNavigation(delayDisappear: true, transition: .immediate)
|
||||||
self.controllerNode.updateNavigation(transition: .animated(duration: 0.15, curve: .easeInOut))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func searchOrMorePressed(node: ContextReferenceContentNode, gesture: ContextGesture?) {
|
@objc private func searchOrMorePressed(node: ContextReferenceContentNode, gesture: ContextGesture?) {
|
||||||
@ -1051,12 +1067,13 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
self.presentWebSearch(MediaGroupsScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, mediaAssetsContext: self.controllerNode.mediaAssetsContext, openGroup: { [weak self] collection in
|
self.presentWebSearch(MediaGroupsScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, mediaAssetsContext: self.controllerNode.mediaAssetsContext, openGroup: { [weak self] collection in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let webSearchController = strongSelf.webSearchController {
|
if let webSearchController = strongSelf.webSearchController {
|
||||||
strongSelf.webSearchController = nil
|
|
||||||
if collection.assetCollectionSubtype != .smartAlbumUserLibrary {
|
if collection.assetCollectionSubtype != .smartAlbumUserLibrary {
|
||||||
Queue.mainQueue().after(0.5) {
|
// strongSelf.webSearchController = nil
|
||||||
webSearchController.cancel()
|
// Queue.mainQueue().after(0.5) {
|
||||||
}
|
// webSearchController.cancel()
|
||||||
|
// }
|
||||||
} else {
|
} else {
|
||||||
|
strongSelf.webSearchController = nil
|
||||||
webSearchController.cancel()
|
webSearchController.cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1205,6 +1222,8 @@ private class MediaPickerGridSelectionGesture: UIPanGestureRecognizer {
|
|||||||
|
|
||||||
private var initialLocation: CGPoint?
|
private var initialLocation: CGPoint?
|
||||||
|
|
||||||
|
var sideInset: CGFloat = 0.0
|
||||||
|
|
||||||
init(target: Any?, action: Selector?, gridNode: GridNode) {
|
init(target: Any?, action: Selector?, gridNode: GridNode) {
|
||||||
self.gridNode = gridNode
|
self.gridNode = gridNode
|
||||||
|
|
||||||
@ -1216,12 +1235,17 @@ private class MediaPickerGridSelectionGesture: UIPanGestureRecognizer {
|
|||||||
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
|
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||||
super.touchesBegan(touches, with: event)
|
super.touchesBegan(touches, with: event)
|
||||||
|
|
||||||
guard let touch = touches.first, let gridNode = self.gridNode else {
|
guard let touch = touches.first, self.numberOfTouches == 1, let gridNode = self.gridNode else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let location = touch.location(in: gridNode.view)
|
let location = touch.location(in: gridNode.view)
|
||||||
self.initialLocation = location
|
|
||||||
|
if location.x > self.sideInset {
|
||||||
|
self.initialLocation = location
|
||||||
|
} else {
|
||||||
|
self.state = .failed
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
|
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||||
|
@ -189,7 +189,7 @@ public final class PermissionContentNode: ASDisplayNode {
|
|||||||
public func updateLayout(size: CGSize, insets: UIEdgeInsets, transition: ContainedViewLayoutTransition) {
|
public func updateLayout(size: CGSize, insets: UIEdgeInsets, transition: ContainedViewLayoutTransition) {
|
||||||
self.validLayout = (size, insets)
|
self.validLayout = (size, insets)
|
||||||
|
|
||||||
let sidePadding: CGFloat
|
var sidePadding: CGFloat
|
||||||
let fontSize: CGFloat
|
let fontSize: CGFloat
|
||||||
if min(size.width, size.height) > 330.0 {
|
if min(size.width, size.height) > 330.0 {
|
||||||
fontSize = 24.0
|
fontSize = 24.0
|
||||||
@ -198,8 +198,9 @@ public final class PermissionContentNode: ASDisplayNode {
|
|||||||
fontSize = 20.0
|
fontSize = 20.0
|
||||||
sidePadding = 20.0
|
sidePadding = 20.0
|
||||||
}
|
}
|
||||||
|
sidePadding += insets.left
|
||||||
|
|
||||||
let smallerSidePadding: CGFloat = 20.0
|
let smallerSidePadding: CGFloat = 20.0 + insets.left
|
||||||
|
|
||||||
self.titleNode.attributedText = NSAttributedString(string: self.title, font: Font.bold(fontSize), textColor: self.theme.list.itemPrimaryTextColor)
|
self.titleNode.attributedText = NSAttributedString(string: self.title, font: Font.bold(fontSize), textColor: self.theme.list.itemPrimaryTextColor)
|
||||||
|
|
||||||
@ -207,7 +208,7 @@ public final class PermissionContentNode: ASDisplayNode {
|
|||||||
let subtitleSize = self.subtitleNode.updateLayout(CGSize(width: size.width - smallerSidePadding * 2.0, height: .greatestFiniteMagnitude))
|
let subtitleSize = self.subtitleNode.updateLayout(CGSize(width: size.width - smallerSidePadding * 2.0, height: .greatestFiniteMagnitude))
|
||||||
let textSize = self.textNode.updateLayout(CGSize(width: size.width - sidePadding * 2.0, height: .greatestFiniteMagnitude))
|
let textSize = self.textNode.updateLayout(CGSize(width: size.width - sidePadding * 2.0, height: .greatestFiniteMagnitude))
|
||||||
let buttonInset: CGFloat = 16.0
|
let buttonInset: CGFloat = 16.0
|
||||||
let buttonWidth = min(size.width, size.height) - buttonInset * 2.0
|
let buttonWidth = min(size.width, size.height) - buttonInset * 2.0 - insets.left - insets.right
|
||||||
let buttonHeight = self.actionButton.updateLayout(width: buttonWidth, transition: transition)
|
let buttonHeight = self.actionButton.updateLayout(width: buttonWidth, transition: transition)
|
||||||
let footerSize = self.footerNode.updateLayout(CGSize(width: size.width - smallerSidePadding * 2.0, height: .greatestFiniteMagnitude))
|
let footerSize = self.footerNode.updateLayout(CGSize(width: size.width - smallerSidePadding * 2.0, height: .greatestFiniteMagnitude))
|
||||||
let privacyButtonSize = self.privacyPolicyButton.measure(CGSize(width: size.width - sidePadding * 2.0, height: .greatestFiniteMagnitude))
|
let privacyButtonSize = self.privacyPolicyButton.measure(CGSize(width: size.width - sidePadding * 2.0, height: .greatestFiniteMagnitude))
|
||||||
|
@ -169,6 +169,8 @@ private class AttachmentFileControllerImpl: ItemListController, AttachmentContai
|
|||||||
public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
|
public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
|
||||||
public var cancelPanGesture: () -> Void = { }
|
public var cancelPanGesture: () -> Void = { }
|
||||||
|
|
||||||
|
var delayDisappear = false
|
||||||
|
|
||||||
var resetForReuseImpl: () -> Void = {}
|
var resetForReuseImpl: () -> Void = {}
|
||||||
public func resetForReuse() {
|
public func resetForReuse() {
|
||||||
self.resetForReuseImpl()
|
self.resetForReuseImpl()
|
||||||
@ -176,7 +178,9 @@ private class AttachmentFileControllerImpl: ItemListController, AttachmentContai
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func prepareForReuse() {
|
public func prepareForReuse() {
|
||||||
|
self.delayDisappear = true
|
||||||
self.visibleBottomContentOffsetChanged?(self.visibleBottomContentOffset)
|
self.visibleBottomContentOffsetChanged?(self.visibleBottomContentOffset)
|
||||||
|
self.delayDisappear = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,13 +304,21 @@ public func attachmentFileController(context: AccountContext, updatedPresentatio
|
|||||||
}
|
}
|
||||||
|
|
||||||
let controller = AttachmentFileControllerImpl(context: context, state: signal)
|
let controller = AttachmentFileControllerImpl(context: context, state: signal)
|
||||||
|
controller.delayDisappear = true
|
||||||
controller.visibleBottomContentOffsetChanged = { [weak controller] offset in
|
controller.visibleBottomContentOffsetChanged = { [weak controller] offset in
|
||||||
switch offset {
|
switch offset {
|
||||||
case let .known(value):
|
case let .known(value):
|
||||||
let backgroundAlpha: CGFloat = min(30.0, value) / 30.0
|
let backgroundAlpha: CGFloat = min(30.0, max(0.0, value)) / 30.0
|
||||||
controller?.updateTabBarAlpha(backgroundAlpha, .immediate)
|
if backgroundAlpha.isZero && controller?.delayDisappear == true {
|
||||||
|
Queue.mainQueue().after(0.2, {
|
||||||
|
controller?.updateTabBarAlpha(backgroundAlpha, .animated(duration: 0.1, curve: .easeInOut))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
controller?.updateTabBarAlpha(backgroundAlpha, .immediate)
|
||||||
|
}
|
||||||
case .unknown, .none:
|
case .unknown, .none:
|
||||||
controller?.updateTabBarAlpha(1.0, .immediate)
|
controller?.updateTabBarAlpha(1.0, .immediate)
|
||||||
|
controller?.delayDisappear = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
controller.resetForReuseImpl = {
|
controller.resetForReuseImpl = {
|
||||||
|
@ -237,6 +237,8 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.displayNodeDidLoad()
|
self.displayNodeDidLoad()
|
||||||
|
|
||||||
|
self.updateTabBarAlpha(1.0, .immediate)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
@ -342,6 +344,10 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
|||||||
public var mediaPickerContext: AttachmentMediaPickerContext {
|
public var mediaPickerContext: AttachmentMediaPickerContext {
|
||||||
return ContactsPickerContext(controller: self)
|
return ContactsPickerContext(controller: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func prepareForReuse() {
|
||||||
|
self.updateTabBarAlpha(1.0, .immediate)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private let searchBarFont = Font.regular(17.0)
|
private let searchBarFont = Font.regular(17.0)
|
||||||
|
@ -496,7 +496,9 @@ class WebSearchControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
insets.top += segmentedHeight
|
insets.top += segmentedHeight
|
||||||
insets.bottom += toolbarHeight
|
insets.bottom += toolbarHeight
|
||||||
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: layout.size, insets: insets, preloadSize: 400.0, type: gridNodeLayoutForContainerLayout(layout)), transition: .immediate), itemTransition: .immediate, stationaryItems: .none,updateFirstIndexInSectionOffset: nil), completion: { _ in })
|
|
||||||
|
let gridInsets = UIEdgeInsets(top: insets.top, left: layout.safeInsets.left, bottom: insets.bottom, right: layout.safeInsets.right)
|
||||||
|
self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: layout.size, insets: gridInsets, preloadSize: 400.0, type: gridNodeLayoutForContainerLayout(layout)), transition: .immediate), itemTransition: .immediate, stationaryItems: .none,updateFirstIndexInSectionOffset: nil), completion: { _ in })
|
||||||
|
|
||||||
let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition)
|
let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user