This commit is contained in:
Ilya Laktyushin 2020-02-18 22:15:48 +04:00
parent 6b728791c9
commit 76b4d87922
11 changed files with 240 additions and 119 deletions

View File

@ -565,6 +565,7 @@ public protocol AccountContext: class {
#endif
var liveLocationManager: LiveLocationManager? { get }
var peersNearbyManager: PeersNearbyManager? { get }
var fetchManager: FetchManager { get }
var downloadedMediaStoreManager: DownloadedMediaStoreManager { get }
var peerChannelMemberCategoriesContextsManager: PeerChannelMemberCategoriesContextsManager { get }

View File

@ -0,0 +1,9 @@
import Foundation
import SwiftSignalKit
import TelegramCore
import SyncCore
import TelegramPresentationData
public protocol PeersNearbyManager {
}

View File

@ -21,10 +21,6 @@ open class GalleryItemNode: ASDisplayNode {
}
public var toggleControlsVisibility: () -> Void = { }
public var goToPreviousItem: () -> Void = { }
public var goToNextItem: () -> Void = { }
public var canGoToPreviousItem: () -> Bool = { return false }
public var canGoToNextItem: () -> Bool = { return false }
public var dismiss: () -> Void = { }
public var beginCustomDismiss: () -> Void = { }
public var completeCustomDismiss: () -> Void = { }

View File

@ -5,6 +5,32 @@ import Display
import SwiftSignalKit
import Postbox
private let leftFadeImage = generateImage(CGSize(width: 64.0, height: 1.0), opaque: false, rotatedContext: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
let gradientColors = [UIColor.black.withAlphaComponent(0.35).cgColor, UIColor.black.withAlphaComponent(0.0).cgColor] as CFArray
var locations: [CGFloat] = [0.0, 1.0]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 64.0, y: 0.0), options: CGGradientDrawingOptions())
})
private let rightFadeImage = generateImage(CGSize(width: 64.0, height: 1.0), opaque: false, rotatedContext: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
let gradientColors = [UIColor.black.withAlphaComponent(0.0).cgColor, UIColor.black.withAlphaComponent(0.35).cgColor] as CFArray
var locations: [CGFloat] = [0.0, 1.0]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 64.0, y: 0.0), options: CGGradientDrawingOptions())
})
public struct GalleryPagerInsertItem {
public let index: Int
public let item: GalleryItem
@ -43,11 +69,16 @@ public struct GalleryPagerTransaction {
}
}
public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate {
public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDelegate {
private let pageGap: CGFloat
private let scrollView: UIScrollView
private let leftFadeNode: ASImageNode
private let rightFadeNode: ASImageNode
private var pressGestureRecognizer: UILongPressGestureRecognizer?
public private(set) var items: [GalleryItem] = []
private var itemNodes: [GalleryItemNode] = []
private var ignoreDidScroll = false
@ -78,6 +109,16 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate {
self.scrollView.contentInsetAdjustmentBehavior = .never
}
self.leftFadeNode = ASImageNode()
self.leftFadeNode.contentMode = .scaleToFill
self.leftFadeNode.image = leftFadeImage
self.leftFadeNode.alpha = 0.0
self.rightFadeNode = ASImageNode()
self.rightFadeNode.contentMode = .scaleToFill
self.rightFadeNode.image = rightFadeImage
self.rightFadeNode.alpha = 0.0
super.init()
self.scrollView.showsVerticalScrollIndicator = false
@ -90,6 +131,55 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate {
self.scrollView.scrollsToTop = false
self.scrollView.delaysContentTouches = false
self.view.addSubview(self.scrollView)
self.addSubnode(self.leftFadeNode)
self.addSubnode(self.rightFadeNode)
}
public override func didLoad() {
super.didLoad()
let gestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.pressGesture(_:)))
gestureRecognizer.delegate = self
gestureRecognizer.minimumPressDuration = 0.01
self.view.addGestureRecognizer(gestureRecognizer)
self.pressGestureRecognizer = gestureRecognizer
}
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
@objc private func pressGesture(_ gestureRecognizer: UILongPressGestureRecognizer) {
let edgeWidth: CGFloat = 44.0
let location = gestureRecognizer.location(in: gestureRecognizer.view)
switch gestureRecognizer.state {
case .began:
let transition: ContainedViewLayoutTransition = .animated(duration: 0.07, curve: .easeInOut)
if location.x < edgeWidth && self.canGoToPreviousItem() {
transition.updateAlpha(node: self.leftFadeNode, alpha: 1.0)
} else if location.x > self.frame.width - edgeWidth && self.canGoToNextItem() {
transition.updateAlpha(node: self.rightFadeNode, alpha: 1.0)
}
case .ended:
let transition: ContainedViewLayoutTransition = .animated(duration: 0.1, curve: .easeInOut)
if location.x < edgeWidth && self.canGoToPreviousItem() {
transition.updateAlpha(node: self.leftFadeNode, alpha: 0.0)
self.goToPreviousItem()
} else if location.x > self.frame.width - edgeWidth && self.canGoToNextItem() {
transition.updateAlpha(node: self.rightFadeNode, alpha: 0.0)
self.goToNextItem()
}
case .cancelled:
let transition: ContainedViewLayoutTransition = .animated(duration: 0.1, curve: .easeInOut)
if location.x < edgeWidth {
transition.updateAlpha(node: self.leftFadeNode, alpha: 0.0)
} else if location.x > self.frame.width - edgeWidth {
transition.updateAlpha(node: self.rightFadeNode, alpha: 0.0)
}
default:
break
}
}
public var isScrollEnabled: Bool {
@ -134,6 +224,10 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate {
transition.animatePosition(node: centralItemNode, from: centralItemNode.position.offsetBy(dx: -updatedCentralPoint.x + centralPoint.x, dy: -updatedCentralPoint.y + centralPoint.y))
}
let fadeWidth = min(72.0, layout.size.width * 0.2)
self.leftFadeNode.frame = CGRect(x: 0.0, y: 0.0, width: fadeWidth, height: layout.size.height)
self.rightFadeNode.frame = CGRect(x: layout.size.width - fadeWidth, y: 0.0, width: fadeWidth, height: layout.size.height)
}
public func ready() -> Signal<Void, NoError> {
@ -238,35 +332,37 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate {
}
}
private func canGoToPreviousItem() -> Bool {
if let index = self.centralItemIndex, index > 0 {
return true
} else {
return false
}
}
private func canGoToNextItem() -> Bool {
if let index = self.centralItemIndex, index < self.items.count - 1 {
return true
} else {
return false
}
}
private func goToPreviousItem() {
if let index = self.centralItemIndex, index > 0 {
self.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: index - 1))
}
}
private func goToNextItem() {
if let index = self.centralItemIndex, index < self.items.count - 1 {
self.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: index + 1))
}
}
private func makeNodeForItem(at index: Int) -> GalleryItemNode {
let node = self.items[index].node()
node.toggleControlsVisibility = self.toggleControlsVisibility
node.goToPreviousItem = { [weak self] in
if let strongSelf = self {
if let index = strongSelf.centralItemIndex, index > 0 {
strongSelf.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: index - 1))
}
}
}
node.goToNextItem = { [weak self] in
if let strongSelf = self {
if let index = strongSelf.centralItemIndex, index < strongSelf.items.count - 1 {
strongSelf.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: index + 1))
}
}
}
node.canGoToPreviousItem = { [weak self] in
if let strongSelf = self, let index = strongSelf.centralItemIndex, index > 0 {
return true
}
return false
}
node.canGoToNextItem = { [weak self] in
if let strongSelf = self, let index = strongSelf.centralItemIndex, index < strongSelf.items.count - 1 {
return true
}
return false
}
node.dismiss = self.dismiss
node.beginCustomDismiss = self.beginCustomDismiss
node.completeCustomDismiss = self.completeCustomDismiss

View File

@ -3,36 +3,8 @@ import UIKit
import Display
import AsyncDisplayKit
private let leftFadeImage = generateImage(CGSize(width: 64.0, height: 1.0), opaque: false, rotatedContext: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
let gradientColors = [UIColor.black.withAlphaComponent(0.35).cgColor, UIColor.black.withAlphaComponent(0.0).cgColor] as CFArray
var locations: [CGFloat] = [0.0, 1.0]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 64.0, y: 0.0), options: CGGradientDrawingOptions())
})
private let rightFadeImage = generateImage(CGSize(width: 64.0, height: 1.0), opaque: false, rotatedContext: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
context.clear(bounds)
let gradientColors = [UIColor.black.withAlphaComponent(0.0).cgColor, UIColor.black.withAlphaComponent(0.35).cgColor] as CFArray
var locations: [CGFloat] = [0.0, 1.0]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 64.0, y: 0.0), options: CGGradientDrawingOptions())
})
open class ZoomableContentGalleryItemNode: GalleryItemNode, UIScrollViewDelegate {
public let scrollNode: ASScrollNode
private let leftFadeNode: ASImageNode
private let rightFadeNode: ASImageNode
private var containerLayout: ContainerViewLayout?
@ -59,17 +31,7 @@ open class ZoomableContentGalleryItemNode: GalleryItemNode, UIScrollViewDelegate
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
self.scrollNode.view.contentInsetAdjustmentBehavior = .never
}
self.leftFadeNode = ASImageNode()
self.leftFadeNode.contentMode = .scaleToFill
self.leftFadeNode.image = leftFadeImage
self.leftFadeNode.alpha = 0.0
self.rightFadeNode = ASImageNode()
self.rightFadeNode.contentMode = .scaleToFill
self.rightFadeNode.image = rightFadeImage
self.rightFadeNode.alpha = 0.0
super.init()
self.scrollNode.view.delegate = self
@ -91,38 +53,17 @@ open class ZoomableContentGalleryItemNode: GalleryItemNode, UIScrollViewDelegate
}
return .waitForDoubleTap
}
tapRecognizer.highlight = { [weak self] location in
if let strongSelf = self {
let pointInNode = location.flatMap { strongSelf.scrollNode.view.convert($0, to: strongSelf.view) }
let transition: ContainedViewLayoutTransition = .animated(duration: 0.07, curve: .easeInOut)
if let location = pointInNode, location.x < edgeWidth && strongSelf.canGoToPreviousItem() {
transition.updateAlpha(node: strongSelf.leftFadeNode, alpha: 1.0)
} else {
transition.updateAlpha(node: strongSelf.leftFadeNode, alpha: 0.0)
}
if let location = pointInNode, location.x > strongSelf.frame.width - edgeWidth && strongSelf.canGoToNextItem() {
transition.updateAlpha(node: strongSelf.rightFadeNode, alpha: 1.0)
} else {
transition.updateAlpha(node: strongSelf.rightFadeNode, alpha: 0.0)
}
}
}
self.scrollNode.view.addGestureRecognizer(tapRecognizer)
self.addSubnode(self.scrollNode)
self.addSubnode(self.leftFadeNode)
self.addSubnode(self.rightFadeNode)
}
@objc open func contentTap(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
if recognizer.state == .ended {
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
let pointInNode = self.scrollNode.view.convert(location, to: self.view)
if pointInNode.x < 44.0 {
self.goToPreviousItem()
} else if pointInNode.x > self.frame.width - 44.0 {
self.goToNextItem()
if pointInNode.x < 44.0 || pointInNode.x > self.frame.width - 44.0 {
} else {
switch gesture {
case .tap:
@ -164,10 +105,6 @@ open class ZoomableContentGalleryItemNode: GalleryItemNode, UIScrollViewDelegate
}
self.containerLayout = layout
let fadeWidth = min(72.0, layout.size.width * 0.2)
self.leftFadeNode.frame = CGRect(x: 0.0, y: 0.0, width: fadeWidth, height: layout.size.height)
self.rightFadeNode.frame = CGRect(x: layout.size.width - fadeWidth, y: 0.0, width: fadeWidth, height: layout.size.height)
if shouldResetContents {
var previousFrame: CGRect?
var previousScale: CGFloat?

View File

@ -324,7 +324,7 @@ private func peersNearbyControllerEntries(data: PeersNearbyData?, state: PeersNe
entries.append(.visibility(presentationData.theme, visible ? presentationData.strings.PeopleNearby_MakeInvisible : presentationData.strings.PeopleNearby_MakeVisible, visible))
if let data = data, !data.users.isEmpty {
var i: Int32 = 0
var index: Int32 = 0
var users = data.users
var effectiveExpanded = expanded
if users.count > maxUsersDisplayedLimit && !expanded {
@ -335,8 +335,8 @@ private func peersNearbyControllerEntries(data: PeersNearbyData?, state: PeersNe
for user in users {
if user.peer.0.id != data.accountPeerId {
entries.append(.user(i, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, user))
i += 1
entries.append(.user(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, user))
index += 1
}
}
@ -475,14 +475,14 @@ public func peersNearbyController(context: AccountContext) -> ViewController {
let _ = (coordinatePromise.get()
|> deliverOnMainQueue).start(next: { coordinate in
if let coordinate = coordinate {
let _ = peersNearbyUpdateVisibility(account: context.account, update: .visible(latitude: coordinate.latitude, longitude: coordinate.longitude), background: false).start()
let _ = updatePeersNearbyVisibility(account: context.account, update: .visible(latitude: coordinate.latitude, longitude: coordinate.longitude), background: false).start()
}
})
})]), nil)
} else {
let _ = peersNearbyUpdateVisibility(account: context.account, update: .invisible, background: false).start()
let _ = updatePeersNearbyVisibility(account: context.account, update: .invisible, background: false).start()
}
}, openProfile: { peer in
navigateToProfileImpl?(peer)
@ -642,11 +642,7 @@ public func peersNearbyController(context: AccountContext) -> ViewController {
}
navigateToChatImpl = { [weak controller] peer in
if let navigationController = controller?.navigationController as? NavigationController {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer.id), keepStack: .always, purposefulAction: { [weak navigationController] in
if let navigationController = navigationController, let chatController = navigationController.viewControllers.last as? ChatController {
replaceAllButRootControllerImpl?(chatController, false)
}
}))
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer.id), keepStack: .always, purposefulAction: {}))
}
}
pushControllerImpl = { [weak controller] c in

View File

@ -25,7 +25,7 @@ public enum PeerNearbyVisibilityUpdate {
case invisible
}
public func peersNearbyUpdateVisibility(account: Account, update: PeerNearbyVisibilityUpdate, background: Bool) -> Signal<Void, NoError> {
public func updatePeersNearbyVisibility(account: Account, update: PeerNearbyVisibilityUpdate, background: Bool) -> Signal<Void, NoError> {
var flags: Int32 = 0
var geoPoint: Api.InputGeoPoint
var selfExpires: Int32?
@ -61,8 +61,12 @@ public func peersNearbyUpdateVisibility(account: Account, update: PeerNearbyVisi
return account.network.request(Api.functions.contacts.getLocated(flags: flags, geoPoint: geoPoint, selfExpires: selfExpires))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
return .single(nil)
|> `catch` { error -> Signal<Api.Updates?, NoError> in
if error.errorCode == 406 {
return .single(nil)
} else {
return .single(nil)
}
}
|> mapToSignal { updates -> Signal<Void, NoError> in
if let updates = updates {

View File

@ -120,6 +120,7 @@ public final class AccountContextImpl: AccountContext {
public let downloadedMediaStoreManager: DownloadedMediaStoreManager
public let liveLocationManager: LiveLocationManager?
public let peersNearbyManager: PeersNearbyManager?
public let wallpaperUploadManager: WallpaperUploadManager?
private let themeUpdateManager: ThemeUpdateManager?
@ -197,6 +198,12 @@ public final class AccountContextImpl: AccountContext {
self.themeUpdateManager = nil
}
if let locationManager = self.sharedContextImpl.locationManager, sharedContext.applicationBindings.isMainApp && !temp {
self.peersNearbyManager = PeersNearbyManagerImpl(account: account, locationManager: locationManager)
} else {
self.peersNearbyManager = nil
}
let updatedLimitsConfiguration = account.postbox.preferencesView(keys: [PreferencesKeys.limitsConfiguration])
|> map { preferences -> LimitsConfiguration in
return preferences.values[PreferencesKeys.limitsConfiguration] as? LimitsConfiguration ?? LimitsConfiguration.defaultValue

View File

@ -933,7 +933,9 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|> deliverOnMainQueue
}
if let text = self.item?.message.text, let firstScalar = text.unicodeScalars.first, firstScalar.value == 0x2764 {
let beatingHearts: [UInt32] = [0x2764, 0x1F90E, 0x1F9E1, 0x1F49A, 0x1F49C, 0x1F49B, 0x1F5A4, 0x1F90D]
if let text = self.item?.message.text, let firstScalar = text.unicodeScalars.first, beatingHearts.contains(firstScalar.value) {
let _ = startTime.start(next: { [weak self] time in
guard let strongSelf = self else {
return

View File

@ -0,0 +1,80 @@
import Foundation
import SwiftSignalKit
import Postbox
import SyncCore
import TelegramCore
import TelegramApi
import DeviceLocationManager
import CoreLocation
import AccountContext
private let locationUpdateTimePeriod: Double = 1.0 * 60.0 * 60.0
private let locationDistanceUpdateThreshold: Double = 1000
final class PeersNearbyManagerImpl: PeersNearbyManager {
private let account: Account
private let locationManager: DeviceLocationManager
private var preferencesDisposable: Disposable?
private var locationDisposable = MetaDisposable()
private var updateDisposable = MetaDisposable()
private var previousLocation: CLLocation?
init(account: Account, locationManager: DeviceLocationManager) {
self.account = account
self.locationManager = locationManager
self.preferencesDisposable = (account.postbox.preferencesView(keys: [PreferencesKeys.peersNearby])
|> map { view -> Int32? in
let state = view.values[PreferencesKeys.peersNearby] as? PeersNearbyState ?? .default
return state.visibilityExpires
}
|> distinctUntilChanged).start(next: { [weak self] visibility in
if let strongSelf = self {
strongSelf.visibilityUpdated(visible: visibility != nil)
}
})
}
deinit {
self.preferencesDisposable?.dispose()
self.locationDisposable.dispose()
self.updateDisposable.dispose()
}
private func visibilityUpdated(visible: Bool) {
if visible {
let account = self.account
let poll = currentLocationManagerCoordinate(manager: self.locationManager, timeout: 5.0)
let signal = (poll |> then(.complete() |> suspendAwareDelay(locationUpdateTimePeriod, queue: Queue.concurrentDefaultQueue()))) |> restart
self.locationDisposable.set(signal.start(next: { [weak self] coordinate in
if let strongSelf = self, let coordinate = coordinate {
let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
var update = true
if let previousLocation = strongSelf.previousLocation, location.distance(from: previousLocation) < locationDistanceUpdateThreshold {
update = false
}
if update {
strongSelf.updateLocation(location)
strongSelf.previousLocation = location
}
}
}))
} else {
self.previousLocation = nil
self.locationDisposable.set(nil)
self.updateDisposable.set(nil)
}
}
private func updateLocation(_ location: CLLocation) {
self.updateDisposable.set(updatePeersNearbyVisibility(account: self.account, update: .location(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude), background: true).start(error: { [weak self] _ in
if let strongSelf = self {
let _ = updatePeersNearbyVisibility(account: strongSelf.account, update: .invisible, background: false).start()
strongSelf.locationDisposable.set(nil)
strongSelf.updateDisposable.set(nil)
}
}))
}
}

View File

@ -153,11 +153,7 @@ final class WalletTransactionInfoScreen: ViewController {
private var walletStateDisposable: Disposable?
private var combinedState: CombinedWalletState?
private var reloadingState = false
private var previousScreenBrightness: CGFloat?
private var displayLinkAnimator: DisplayLinkAnimator?
private let idleTimerExtensionDisposable: Disposable
public init(context: WalletContext, walletInfo: WalletInfo?, walletTransaction: WalletInfoTransaction, walletState: Signal<(CombinedWalletState, Bool), NoError>, enableDebugActions: Bool) {
self.context = context
self.walletInfo = walletInfo
@ -168,9 +164,7 @@ final class WalletTransactionInfoScreen: ViewController {
let defaultTheme = self.presentationData.theme.navigationBar
let navigationBarTheme = NavigationBarTheme(buttonColor: defaultTheme.buttonColor, disabledButtonColor: defaultTheme.disabledButtonColor, primaryTextColor: defaultTheme.primaryTextColor, backgroundColor: .clear, separatorColor: .clear, badgeBackgroundColor: defaultTheme.badgeBackgroundColor, badgeStrokeColor: defaultTheme.badgeStrokeColor, badgeTextColor: defaultTheme.badgeTextColor)
self.idleTimerExtensionDisposable = context.idleTimerExtension()
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: navigationBarTheme, strings: NavigationBarStrings(back: self.presentationData.strings.Wallet_Navigation_Back, close: self.presentationData.strings.Wallet_Navigation_Close)))
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
@ -193,7 +187,6 @@ final class WalletTransactionInfoScreen: ViewController {
}
deinit {
self.idleTimerExtensionDisposable.dispose()
self.walletStateDisposable?.dispose()
}