mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Initial invite requests implementation
This commit is contained in:
@@ -37,6 +37,7 @@ private struct LocationViewTransaction {
|
||||
let deletions: [ListViewDeleteItem]
|
||||
let insertions: [ListViewInsertItem]
|
||||
let updates: [ListViewUpdateItem]
|
||||
let gotTravelTimes: Bool
|
||||
}
|
||||
|
||||
private enum LocationViewEntryId: Hashable {
|
||||
@@ -48,7 +49,7 @@ private enum LocationViewEntryId: Hashable {
|
||||
private enum LocationViewEntry: Comparable, Identifiable {
|
||||
case info(PresentationTheme, TelegramMediaMap, String?, Double?, Double?)
|
||||
case toggleLiveLocation(PresentationTheme, String, String, Double?, Double?)
|
||||
case liveLocation(PresentationTheme, PresentationDateTimeFormat, PresentationPersonNameOrder, Message, Double?, Int)
|
||||
case liveLocation(PresentationTheme, PresentationDateTimeFormat, PresentationPersonNameOrder, Message, Double?, Double?, Double?, Double?, Int)
|
||||
|
||||
var stableId: LocationViewEntryId {
|
||||
switch self {
|
||||
@@ -56,7 +57,7 @@ private enum LocationViewEntry: Comparable, Identifiable {
|
||||
return .info
|
||||
case .toggleLiveLocation:
|
||||
return .toggleLiveLocation
|
||||
case let .liveLocation(_, _, _, message, _, _):
|
||||
case let .liveLocation(_, _, _, message, _, _, _, _, _):
|
||||
return .liveLocation(message.stableId)
|
||||
}
|
||||
}
|
||||
@@ -75,8 +76,8 @@ private enum LocationViewEntry: Comparable, Identifiable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .liveLocation(lhsTheme, lhsDateTimeFormat, lhsNameDisplayOrder, lhsMessage, lhsDistance, lhsIndex):
|
||||
if case let .liveLocation(rhsTheme, rhsDateTimeFormat, rhsNameDisplayOrder, rhsMessage, rhsDistance, rhsIndex) = rhs, lhsTheme === rhsTheme, lhsDateTimeFormat == rhsDateTimeFormat, lhsNameDisplayOrder == rhsNameDisplayOrder, areMessagesEqual(lhsMessage, rhsMessage), lhsDistance == rhsDistance, lhsIndex == rhsIndex {
|
||||
case let .liveLocation(lhsTheme, lhsDateTimeFormat, lhsNameDisplayOrder, lhsMessage, lhsDistance, lhsDrivingTime, lhsTransitTime, lhsWalkingTime, lhsIndex):
|
||||
if case let .liveLocation(rhsTheme, rhsDateTimeFormat, rhsNameDisplayOrder, rhsMessage, rhsDistance, rhsDrivingTime, rhsTransitTime, rhsWalkingTime, rhsIndex) = rhs, lhsTheme === rhsTheme, lhsDateTimeFormat == rhsDateTimeFormat, lhsNameDisplayOrder == rhsNameDisplayOrder, areMessagesEqual(lhsMessage, rhsMessage), lhsDistance == rhsDistance, lhsDrivingTime == rhsDrivingTime, lhsTransitTime == rhsTransitTime, lhsWalkingTime == rhsWalkingTime, lhsIndex == rhsIndex {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@@ -100,11 +101,11 @@ private enum LocationViewEntry: Comparable, Identifiable {
|
||||
case .liveLocation:
|
||||
return true
|
||||
}
|
||||
case let .liveLocation(_, _, _, _, _, lhsIndex):
|
||||
case let .liveLocation(_, _, _, _, _, _, _, _, lhsIndex):
|
||||
switch rhs {
|
||||
case .info, .toggleLiveLocation:
|
||||
return false
|
||||
case let .liveLocation(_, _, _, _, _, rhsIndex):
|
||||
case let .liveLocation(_, _, _, _, _, _, _, _, rhsIndex):
|
||||
return lhsIndex < rhsIndex
|
||||
}
|
||||
}
|
||||
@@ -125,11 +126,14 @@ private enum LocationViewEntry: Comparable, Identifiable {
|
||||
} else {
|
||||
distanceString = nil
|
||||
}
|
||||
let eta = time.flatMap { stringForEstimatedDuration(strings: presentationData.strings, eta: $0) }
|
||||
var eta: String?
|
||||
if let time = time, time < 60.0 * 60.0 * 10.0 {
|
||||
eta = stringForEstimatedDuration(strings: presentationData.strings, time: time, format: { presentationData.strings.Map_DirectionsDriveEta($0).string })
|
||||
}
|
||||
return LocationInfoListItem(presentationData: ItemListPresentationData(presentationData), engine: context.engine, location: location, address: addressString, distance: distanceString, eta: eta, action: {
|
||||
interaction?.goToCoordinate(location.coordinate)
|
||||
}, getDirections: {
|
||||
interaction?.requestDirections()
|
||||
interaction?.requestDirections(location, nil, .driving)
|
||||
})
|
||||
case let .toggleLiveLocation(_, title, subtitle, beginTimstamp, timeout):
|
||||
let beginTimeAndTimeout: (Double, Double)?
|
||||
@@ -147,24 +151,40 @@ private enum LocationViewEntry: Comparable, Identifiable {
|
||||
}, highlighted: { highlight in
|
||||
interaction?.updateSendActionHighlight(highlight)
|
||||
})
|
||||
case let .liveLocation(_, dateTimeFormat, nameDisplayOrder, message, distance, _):
|
||||
return LocationLiveListItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: context, message: message, distance: distance, action: {
|
||||
case let .liveLocation(_, dateTimeFormat, nameDisplayOrder, message, distance, drivingTime, transitTime, walkingTime, _):
|
||||
var title: String?
|
||||
if let author = message.author {
|
||||
title = EnginePeer(author).displayTitle(strings: presentationData.strings, displayOrder: nameDisplayOrder)
|
||||
}
|
||||
return LocationLiveListItem(presentationData: ItemListPresentationData(presentationData), dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: context, message: message, distance: distance, drivingTime: drivingTime, transitTime: transitTime, walkingTime: walkingTime, action: {
|
||||
if let location = getLocation(from: message) {
|
||||
interaction?.goToCoordinate(location.coordinate)
|
||||
}
|
||||
}, longTapAction: {})
|
||||
}, longTapAction: {}, drivingAction: {
|
||||
if let location = getLocation(from: message) {
|
||||
interaction?.requestDirections(location, title, .driving)
|
||||
}
|
||||
}, transitAction: {
|
||||
if let location = getLocation(from: message) {
|
||||
interaction?.requestDirections(location, title, .transit)
|
||||
}
|
||||
}, walkingAction: {
|
||||
if let location = getLocation(from: message) {
|
||||
interaction?.requestDirections(location, title, .walking)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func preparedTransition(from fromEntries: [LocationViewEntry], to toEntries: [LocationViewEntry], context: AccountContext, presentationData: PresentationData, interaction: LocationViewInteraction?) -> LocationViewTransaction {
|
||||
private func preparedTransition(from fromEntries: [LocationViewEntry], to toEntries: [LocationViewEntry], context: AccountContext, presentationData: PresentationData, interaction: LocationViewInteraction?, gotTravelTimes: Bool) -> LocationViewTransaction {
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||
|
||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, interaction: interaction), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, interaction: interaction), directionHint: nil) }
|
||||
|
||||
return LocationViewTransaction(deletions: deletions, insertions: insertions, updates: updates)
|
||||
return LocationViewTransaction(deletions: deletions, insertions: insertions, updates: updates, gotTravelTimes: gotTravelTimes)
|
||||
}
|
||||
|
||||
enum LocationViewLocation: Equatable {
|
||||
@@ -217,6 +237,14 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
|
||||
|
||||
var reportedAnnotationsReady = false
|
||||
var onAnnotationsReady: (() -> Void)?
|
||||
|
||||
private let travelDisposables = DisposableSet()
|
||||
private var travelTimes: [EngineMessage.Id: (Double, Double?, Double?, Double?)] = [:] {
|
||||
didSet {
|
||||
self.travelTimesPromise.set(.single(self.travelTimes))
|
||||
}
|
||||
}
|
||||
private let travelTimesPromise = Promise<[EngineMessage.Id: (Double, Double?, Double?, Double?)]>([:])
|
||||
|
||||
init(context: AccountContext, presentationData: PresentationData, subject: Message, interaction: LocationViewInteraction, locationManager: LocationManager) {
|
||||
self.context = context
|
||||
@@ -263,7 +291,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
|
||||
|
||||
if let location = getLocation(from: subject), location.liveBroadcastingTimeout == nil {
|
||||
eta = .single(nil)
|
||||
|> then(driveEta(coordinate: location.coordinate))
|
||||
|> then(getExpectedTravelTime(coordinate: location.coordinate, transportType: .automobile))
|
||||
|
||||
if let venue = location.venue, let venueAddress = venue.address, !venueAddress.isEmpty {
|
||||
address = .single(venueAddress)
|
||||
@@ -304,13 +332,14 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
|
||||
let previousUserAnnotation = Atomic<LocationPinAnnotation?>(value: nil)
|
||||
let previousAnnotations = Atomic<[LocationPinAnnotation]>(value: [])
|
||||
let previousEntries = Atomic<[LocationViewEntry]?>(value: nil)
|
||||
let previousHadTravelTimes = Atomic<Bool>(value: false)
|
||||
|
||||
let selfPeer = context.account.postbox.transaction { transaction -> Peer? in
|
||||
return transaction.getPeer(context.account.peerId)
|
||||
}
|
||||
|
||||
self.disposable = (combineLatest(self.presentationDataPromise.get(), self.statePromise.get(), selfPeer, liveLocations, self.headerNode.mapNode.userLocation, userLocation, address, eta)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData, state, selfPeer, liveLocations, userLocation, distance, address, eta in
|
||||
|
||||
self.disposable = (combineLatest(self.presentationDataPromise.get(), self.statePromise.get(), selfPeer, liveLocations, self.headerNode.mapNode.userLocation, userLocation, address, eta, self.travelTimesPromise.get())
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData, state, selfPeer, liveLocations, userLocation, distance, address, eta, travelTimes in
|
||||
if let strongSelf = self, let location = getLocation(from: subject) {
|
||||
var entries: [LocationViewEntry] = []
|
||||
var annotations: [LocationPinAnnotation] = []
|
||||
@@ -323,7 +352,10 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
|
||||
var proximityNotificationRadius: Int32?
|
||||
var index: Int = 0
|
||||
|
||||
var isLocationView = false
|
||||
if location.liveBroadcastingTimeout == nil {
|
||||
isLocationView = true
|
||||
|
||||
let subjectLocation = CLLocation(latitude: location.latitude, longitude: location.longitude)
|
||||
let distance = userLocation.flatMap { subjectLocation.distance(from: $0) }
|
||||
|
||||
@@ -414,11 +446,45 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
|
||||
let subjectLocation = CLLocation(latitude: location.latitude, longitude: location.longitude)
|
||||
let distance = userLocation.flatMap { subjectLocation.distance(from: $0) }
|
||||
|
||||
let timestamp = CACurrentMediaTime()
|
||||
if message.localTags.contains(.OutgoingLiveLocation), let selfPeer = selfPeer {
|
||||
userAnnotation = LocationPinAnnotation(context: context, theme: presentationData.theme, message: message, selfPeer: selfPeer, isSelf: true, heading: location.heading)
|
||||
} else {
|
||||
var drivingTime: Double?
|
||||
var transitTime: Double?
|
||||
var walkingTime: Double?
|
||||
if !isLocationView {
|
||||
if let (previousTimestamp, maybeDrivingTime, maybeTransitTime, maybeWalkingTime) = travelTimes[message.id] {
|
||||
drivingTime = maybeDrivingTime
|
||||
transitTime = maybeTransitTime
|
||||
walkingTime = maybeWalkingTime
|
||||
|
||||
if timestamp > previousTimestamp + 60.0 {
|
||||
strongSelf.travelDisposables.add(combineLatest(queue: Queue.mainQueue(), getExpectedTravelTime(coordinate: location.coordinate, transportType: .automobile), getExpectedTravelTime(coordinate: location.coordinate, transportType: .transit), getExpectedTravelTime(coordinate: location.coordinate, transportType: .walking)).start(next: { [weak self] drivingTime, transitTime, walkingTime in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let timestamp = CACurrentMediaTime()
|
||||
var travelTimes = strongSelf.travelTimes
|
||||
travelTimes[message.id] = (timestamp, drivingTime, transitTime, walkingTime)
|
||||
strongSelf.travelTimes = travelTimes
|
||||
}))
|
||||
}
|
||||
} else {
|
||||
strongSelf.travelDisposables.add(combineLatest(queue: Queue.mainQueue(), getExpectedTravelTime(coordinate: location.coordinate, transportType: .automobile), getExpectedTravelTime(coordinate: location.coordinate, transportType: .transit), getExpectedTravelTime(coordinate: location.coordinate, transportType: .walking)).start(next: { [weak self] drivingTime, transitTime, walkingTime in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let timestamp = CACurrentMediaTime()
|
||||
var travelTimes = strongSelf.travelTimes
|
||||
travelTimes[message.id] = (timestamp, drivingTime, transitTime, walkingTime)
|
||||
strongSelf.travelTimes = travelTimes
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
annotations.append(LocationPinAnnotation(context: context, theme: presentationData.theme, message: message, selfPeer: selfPeer, isSelf: message.author?.id == context.account.peerId, heading: location.heading))
|
||||
entries.append(.liveLocation(presentationData.theme, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, message, distance, index))
|
||||
entries.append(.liveLocation(presentationData.theme, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, message, distance, drivingTime, transitTime, walkingTime, index))
|
||||
}
|
||||
index += 1
|
||||
}
|
||||
@@ -441,8 +507,9 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
|
||||
|
||||
let previousEntries = previousEntries.swap(entries)
|
||||
let previousState = previousState.swap(state)
|
||||
|
||||
let transition = preparedTransition(from: previousEntries ?? [], to: entries, context: context, presentationData: presentationData, interaction: strongSelf.interaction)
|
||||
let previousHadTravelTimes = previousHadTravelTimes.swap(!travelTimes.isEmpty)
|
||||
|
||||
let transition = preparedTransition(from: previousEntries ?? [], to: entries, context: context, presentationData: presentationData, interaction: strongSelf.interaction, gotTravelTimes: !travelTimes.isEmpty && !previousHadTravelTimes)
|
||||
strongSelf.enqueueTransition(transition)
|
||||
|
||||
strongSelf.headerNode.updateState(mapMode: state.mapMode, trackingMode: state.trackingMode, displayingMapModeOptions: state.displayingMapModeOptions, displayingPlacesButton: false, proximityNotification: proximityNotification, animated: false)
|
||||
@@ -581,7 +648,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
|
||||
|
||||
deinit {
|
||||
self.disposable?.dispose()
|
||||
|
||||
self.travelDisposables.dispose()
|
||||
self.locationManager.manager.stopUpdatingHeading()
|
||||
}
|
||||
|
||||
@@ -633,17 +700,20 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
|
||||
self.enqueuedTransitions.remove(at: 0)
|
||||
|
||||
let scrollToItem: ListViewScrollToItem?
|
||||
if !self.initialized, transition.insertions.count > 0 {
|
||||
if (!self.initialized && transition.insertions.count > 0) || transition.gotTravelTimes {
|
||||
var index: Int = 0
|
||||
var offset: CGFloat = 0.0
|
||||
if transition.insertions.count > 2 {
|
||||
if transition.gotTravelTimes {
|
||||
index = 1
|
||||
offset = 0.0
|
||||
} else if transition.insertions.count > 2 {
|
||||
index = 2
|
||||
offset = 40.0
|
||||
} else if transition.insertions.count == 2 {
|
||||
index = 1
|
||||
}
|
||||
|
||||
scrollToItem = ListViewScrollToItem(index: index, position: .bottom(offset), animated: false, curve: .Default(duration: nil), directionHint: .Up)
|
||||
scrollToItem = ListViewScrollToItem(index: index, position: .bottom(offset), animated: transition.gotTravelTimes, curve: .Default(duration: 0.3), directionHint: .Up)
|
||||
self.initialized = true
|
||||
} else {
|
||||
scrollToItem = nil
|
||||
|
||||
Reference in New Issue
Block a user