mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' into experimental-2
This commit is contained in:
commit
6d1ee760e3
@ -314,6 +314,8 @@ public protocol PresentationGroupCall: class {
|
||||
var incomingVideoSources: Signal<[PeerId: UInt32], NoError> { get }
|
||||
|
||||
func makeIncomingVideoView(source: UInt32, completion: @escaping (PresentationCallVideoView?) -> Void)
|
||||
|
||||
func loadMoreMembers(token: String)
|
||||
}
|
||||
|
||||
public protocol PresentationCallManager: class {
|
||||
|
@ -1982,7 +1982,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
|
||||
let signal: Signal<Void, NoError> = strongSelf.context.account.postbox.transaction { transaction -> Void in
|
||||
for peerId in peerIds {
|
||||
removePeerChat(account: context.account, transaction: transaction, mediaBox: context.account.postbox.mediaBox, peerId: peerId, reportChatSpam: false, deleteGloballyIfPossible: false)
|
||||
removePeerChat(account: context.account, transaction: transaction, mediaBox: context.account.postbox.mediaBox, peerId: peerId, reportChatSpam: false, deleteGloballyIfPossible: peerId.namespace == Namespaces.Peer.SecretChat)
|
||||
}
|
||||
}
|
||||
|> afterDisposed {
|
||||
|
@ -1,20 +1,14 @@
|
||||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
objc_library(
|
||||
swift_library(
|
||||
name = "Reachability",
|
||||
enable_modules = True,
|
||||
module_name = "Reachability",
|
||||
srcs = glob([
|
||||
"Sources/*.m",
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
hdrs = glob([
|
||||
"PublicHeaders/**/*.h",
|
||||
]),
|
||||
includes = [
|
||||
"PublicHeaders",
|
||||
],
|
||||
sdk_frameworks = [
|
||||
"Foundation",
|
||||
"SystemConfiguration",
|
||||
deps = [
|
||||
"//submodules/Reachability/LegacyReachability:LegacyReachability",
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
22
submodules/Reachability/LegacyReachability/BUILD
Normal file
22
submodules/Reachability/LegacyReachability/BUILD
Normal file
@ -0,0 +1,22 @@
|
||||
|
||||
objc_library(
|
||||
name = "LegacyReachability",
|
||||
enable_modules = True,
|
||||
module_name = "LegacyReachability",
|
||||
srcs = glob([
|
||||
"Sources/*.m",
|
||||
]),
|
||||
hdrs = glob([
|
||||
"PublicHeaders/**/*.h",
|
||||
]),
|
||||
includes = [
|
||||
"PublicHeaders",
|
||||
],
|
||||
sdk_frameworks = [
|
||||
"Foundation",
|
||||
"SystemConfiguration",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
@ -24,7 +24,7 @@ typedef enum : NSInteger {
|
||||
extern NSString *kReachabilityChangedNotification;
|
||||
|
||||
|
||||
@interface Reachability : NSObject
|
||||
@interface LegacyReachability : NSObject
|
||||
|
||||
@property (nonatomic, copy) void (^reachabilityChanged)(NetworkStatus status);
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#import <Reachability/Reachability.h>
|
||||
#import <LegacyReachability/LegacyReachability.h>
|
||||
|
||||
#import <pthread.h>
|
||||
#import <libkern/OSAtomic.h>
|
||||
@ -126,14 +126,14 @@ static ReachabilityAtomic *contexts() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
static void withContext(int32_t key, void (^f)(Reachability *)) {
|
||||
Reachability *reachability = [contexts() with:^id(NSDictionary *dict) {
|
||||
static void withContext(int32_t key, void (^f)(LegacyReachability *)) {
|
||||
LegacyReachability *reachability = [contexts() with:^id(NSDictionary *dict) {
|
||||
return dict[@(key)];
|
||||
}];
|
||||
f(reachability);
|
||||
}
|
||||
|
||||
static int32_t addContext(Reachability *context) {
|
||||
static int32_t addContext(LegacyReachability *context) {
|
||||
int32_t key = OSAtomicIncrement32(&nextKey);
|
||||
[contexts() modify:^id(NSMutableDictionary *dict) {
|
||||
NSMutableDictionary *updatedDict = [[NSMutableDictionary alloc] initWithDictionary:dict];
|
||||
@ -155,19 +155,19 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
|
||||
{
|
||||
#pragma unused (target, flags)
|
||||
//NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
|
||||
//NSCAssert([(__bridge NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
|
||||
//NSCAssert([(__bridge NSObject*) info isKindOfClass: [LegacyReachability class]], @"info was wrong class in ReachabilityCallback");
|
||||
|
||||
int32_t key = (int32_t)((intptr_t)info);
|
||||
withContext(key, ^(Reachability *context) {
|
||||
if ([context isKindOfClass:[Reachability class]] && context.reachabilityChanged != nil)
|
||||
withContext(key, ^(LegacyReachability *context) {
|
||||
if ([context isKindOfClass:[LegacyReachability class]] && context.reachabilityChanged != nil)
|
||||
context.reachabilityChanged(context.currentReachabilityStatus);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Reachability implementation
|
||||
#pragma mark - LegacyReachability implementation
|
||||
|
||||
@implementation Reachability
|
||||
@implementation LegacyReachability
|
||||
{
|
||||
int32_t _key;
|
||||
SCNetworkReachabilityRef _reachabilityRef;
|
||||
@ -175,7 +175,7 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
|
||||
|
||||
+ (instancetype)reachabilityWithHostName:(NSString *)hostName
|
||||
{
|
||||
Reachability* returnValue = NULL;
|
||||
LegacyReachability* returnValue = NULL;
|
||||
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
|
||||
if (reachability != NULL)
|
||||
{
|
||||
@ -199,7 +199,7 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
|
||||
{
|
||||
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, hostAddress);
|
||||
|
||||
Reachability* returnValue = NULL;
|
||||
LegacyReachability* returnValue = NULL;
|
||||
|
||||
if (reachability != NULL)
|
||||
{
|
180
submodules/Reachability/Sources/Reachability.swift
Normal file
180
submodules/Reachability/Sources/Reachability.swift
Normal file
@ -0,0 +1,180 @@
|
||||
import Foundation
|
||||
import SwiftSignalKit
|
||||
|
||||
import LegacyReachability
|
||||
import Network
|
||||
|
||||
private final class WrappedLegacyReachability: NSObject {
|
||||
@objc private static func threadImpl() {
|
||||
while true {
|
||||
RunLoop.current.run(until: .distantFuture)
|
||||
}
|
||||
}
|
||||
|
||||
private static let thread: Thread = {
|
||||
let thread = Thread(target: Reachability.self, selector: #selector(WrappedLegacyReachability.threadImpl), object: nil)
|
||||
thread.start()
|
||||
return thread
|
||||
}()
|
||||
|
||||
@objc private static func dispatchOnThreadImpl(_ f: @escaping () -> Void) {
|
||||
f()
|
||||
}
|
||||
|
||||
private static func dispatchOnThread(_ f: @escaping @convention(block) () -> Void) {
|
||||
WrappedLegacyReachability.perform(#selector(WrappedLegacyReachability.dispatchOnThreadImpl(_:)), on: WrappedLegacyReachability.thread, with: f, waitUntilDone: false)
|
||||
}
|
||||
|
||||
private let reachability: LegacyReachability
|
||||
|
||||
let value: ValuePromise<Reachability.NetworkType>
|
||||
|
||||
override init() {
|
||||
assert(Thread.current === WrappedLegacyReachability.thread)
|
||||
self.reachability = LegacyReachability.forInternetConnection()
|
||||
let type: Reachability.NetworkType
|
||||
switch self.reachability.currentReachabilityStatus() {
|
||||
case NotReachable:
|
||||
type = .none
|
||||
case ReachableViaWiFi:
|
||||
type = .wifi
|
||||
case ReachableViaWWAN:
|
||||
type = .cellular
|
||||
default:
|
||||
type = .none
|
||||
}
|
||||
self.value = ValuePromise<Reachability.NetworkType>(type)
|
||||
|
||||
super.init()
|
||||
|
||||
self.reachability.reachabilityChanged = { [weak self] status in
|
||||
WrappedLegacyReachability.dispatchOnThread {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let internalNetworkType: Reachability.NetworkType
|
||||
switch status {
|
||||
case NotReachable:
|
||||
internalNetworkType = .none
|
||||
case ReachableViaWiFi:
|
||||
internalNetworkType = .wifi
|
||||
case ReachableViaWWAN:
|
||||
internalNetworkType = .cellular
|
||||
default:
|
||||
internalNetworkType = .none
|
||||
}
|
||||
strongSelf.value.set(internalNetworkType)
|
||||
}
|
||||
}
|
||||
self.reachability.startNotifier()
|
||||
}
|
||||
|
||||
private static var valueRef: Unmanaged<WrappedLegacyReachability>?
|
||||
|
||||
static func withInstance(_ f: @escaping (WrappedLegacyReachability) -> Void) {
|
||||
WrappedLegacyReachability.dispatchOnThread {
|
||||
if self.valueRef == nil {
|
||||
self.valueRef = Unmanaged.passRetained(WrappedLegacyReachability())
|
||||
}
|
||||
if let valueRef = self.valueRef {
|
||||
let value = valueRef.takeUnretainedValue()
|
||||
f(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension 12.0, iOS 12.0, *)
|
||||
private final class PathMonitor {
|
||||
private let queue: Queue
|
||||
private let monitor: NWPathMonitor
|
||||
|
||||
let networkType = Promise<Reachability.NetworkType>()
|
||||
|
||||
init(queue: Queue) {
|
||||
self.queue = queue
|
||||
self.monitor = NWPathMonitor()
|
||||
|
||||
self.monitor.pathUpdateHandler = { [weak self] path in
|
||||
queue.async {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let networkType: Reachability.NetworkType
|
||||
if path.status == .satisfied {
|
||||
if path.usesInterfaceType(.cellular) {
|
||||
networkType = .cellular
|
||||
} else {
|
||||
networkType = .wifi
|
||||
}
|
||||
} else {
|
||||
networkType = .none
|
||||
}
|
||||
|
||||
strongSelf.networkType.set(.single(networkType))
|
||||
}
|
||||
}
|
||||
|
||||
self.monitor.start(queue: self.queue.queue)
|
||||
|
||||
let networkType: Reachability.NetworkType
|
||||
let path = self.monitor.currentPath
|
||||
if path.status == .satisfied {
|
||||
if path.usesInterfaceType(.cellular) {
|
||||
networkType = .cellular
|
||||
} else {
|
||||
networkType = .wifi
|
||||
}
|
||||
} else {
|
||||
networkType = .none
|
||||
}
|
||||
|
||||
self.networkType.set(.single(networkType))
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension 12.0, iOS 12.0, *)
|
||||
private final class SharedPathMonitor {
|
||||
static let queue = Queue()
|
||||
static let impl = QueueLocalObject<PathMonitor>(queue: queue, generate: {
|
||||
return PathMonitor(queue: queue)
|
||||
})
|
||||
}
|
||||
|
||||
public enum Reachability {
|
||||
public enum NetworkType: Equatable {
|
||||
case none
|
||||
case wifi
|
||||
case cellular
|
||||
}
|
||||
|
||||
public static var networkType: Signal<NetworkType, NoError> {
|
||||
if #available(iOSApplicationExtension 12.0, iOS 12.0, *) {
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
SharedPathMonitor.impl.with { impl in
|
||||
disposable.set(impl.networkType.get().start(next: { value in
|
||||
subscriber.putNext(value)
|
||||
}))
|
||||
}
|
||||
|
||||
return disposable
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
} else {
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
WrappedLegacyReachability.withInstance({ impl in
|
||||
disposable.set(impl.value.get().start(next: { next in
|
||||
subscriber.putNext(next)
|
||||
}))
|
||||
})
|
||||
|
||||
return disposable
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
}
|
||||
}
|
||||
}
|
@ -78,7 +78,7 @@ public final class AccountGroupCallContextImpl: AccountGroupCallContext {
|
||||
groupCall: nil
|
||||
)))
|
||||
|
||||
self.disposable = (getGroupCallParticipants(account: account, callId: call.id, accessHash: call.accessHash, offset: "", limit: 100)
|
||||
self.disposable = (getGroupCallParticipants(account: account, callId: call.id, accessHash: call.accessHash, offset: "", ssrcs: [], limit: 100)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<GroupCallParticipantsContext.State?, NoError> in
|
||||
return .single(nil)
|
||||
@ -94,6 +94,7 @@ public final class AccountGroupCallContextImpl: AccountGroupCallContext {
|
||||
accessHash: call.accessHash,
|
||||
state: state
|
||||
)
|
||||
|
||||
strongSelf.participantsContext = context
|
||||
strongSelf.panelDataPromise.set(combineLatest(queue: .mainQueue(),
|
||||
context.state,
|
||||
@ -248,13 +249,14 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
private let silentTimeout: Int32 = 2
|
||||
|
||||
struct Participant {
|
||||
let ssrc: UInt32
|
||||
let timestamp: Int32
|
||||
let level: Float
|
||||
}
|
||||
|
||||
private var participants: [PeerId: Participant] = [:]
|
||||
private let speakingParticipantsPromise = ValuePromise<Set<PeerId>>()
|
||||
private var speakingParticipants = Set<PeerId>() {
|
||||
private let speakingParticipantsPromise = ValuePromise<[PeerId: UInt32]>()
|
||||
private var speakingParticipants = [PeerId: UInt32]() {
|
||||
didSet {
|
||||
self.speakingParticipantsPromise.set(self.speakingParticipants)
|
||||
}
|
||||
@ -271,11 +273,11 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
|
||||
var validSpeakers: [PeerId: Participant] = [:]
|
||||
var silentParticipants = Set<PeerId>()
|
||||
var speakingParticipants = Set<PeerId>()
|
||||
for (peerId, _, level, hasVoice) in levels {
|
||||
var speakingParticipants = [PeerId: UInt32]()
|
||||
for (peerId, ssrc, level, hasVoice) in levels {
|
||||
if level > speakingLevelThreshold && hasVoice {
|
||||
validSpeakers[peerId] = Participant(timestamp: timestamp, level: level)
|
||||
speakingParticipants.insert(peerId)
|
||||
validSpeakers[peerId] = Participant(ssrc: ssrc, timestamp: timestamp, level: level)
|
||||
speakingParticipants[peerId] = ssrc
|
||||
} else {
|
||||
silentParticipants.insert(peerId)
|
||||
}
|
||||
@ -288,11 +290,11 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
if silentParticipants.contains(peerId) {
|
||||
if delta < silentTimeout {
|
||||
validSpeakers[peerId] = participant
|
||||
speakingParticipants.insert(peerId)
|
||||
speakingParticipants[peerId] = participant.ssrc
|
||||
}
|
||||
} else if delta < cutoffTimeout {
|
||||
validSpeakers[peerId] = participant
|
||||
speakingParticipants.insert(peerId)
|
||||
speakingParticipants[peerId] = participant.ssrc
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -309,8 +311,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
self.audioLevelsPromise.set(.single(audioLevels))
|
||||
}
|
||||
|
||||
func get() -> Signal<Set<PeerId>, NoError> {
|
||||
return self.speakingParticipantsPromise.get() |> distinctUntilChanged
|
||||
func get() -> Signal<[PeerId: UInt32], NoError> {
|
||||
return self.speakingParticipantsPromise.get()
|
||||
}
|
||||
|
||||
func getAudioLevels() -> Signal<[(PeerId, UInt32, Float, Bool)], NoError> {
|
||||
@ -976,15 +978,15 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
var myLevel: Float = 0.0
|
||||
var myLevelHasVoice: Bool = false
|
||||
for (ssrcKey, level, hasVoice) in levels {
|
||||
let source: UInt32
|
||||
let peerId: PeerId?
|
||||
var peerId: PeerId?
|
||||
let ssrcValue: UInt32
|
||||
switch ssrcKey {
|
||||
case .local:
|
||||
peerId = strongSelf.accountContext.account.peerId
|
||||
source = 0
|
||||
ssrcValue = 0
|
||||
case let .source(ssrc):
|
||||
peerId = strongSelf.ssrcMapping[ssrc]
|
||||
source = ssrc
|
||||
ssrcValue = ssrc
|
||||
}
|
||||
if let peerId = peerId {
|
||||
if case .local = ssrcKey {
|
||||
@ -993,7 +995,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
myLevelHasVoice = hasVoice
|
||||
}
|
||||
}
|
||||
result.append((peerId, source, level, hasVoice))
|
||||
result.append((peerId, ssrcValue, level, hasVoice))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1065,9 +1067,9 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
|
||||
var topParticipants: [GroupCallParticipantsContext.Participant] = []
|
||||
|
||||
var reportSpeakingParticipants: [PeerId] = []
|
||||
var reportSpeakingParticipants: [PeerId: UInt32] = [:]
|
||||
let timestamp = CACurrentMediaTime()
|
||||
for peerId in speakingParticipants {
|
||||
for (peerId, ssrc) in speakingParticipants {
|
||||
let shouldReport: Bool
|
||||
if let previousTimestamp = strongSelf.speakingParticipantsReportTimestamp[peerId] {
|
||||
shouldReport = previousTimestamp + 1.0 < timestamp
|
||||
@ -1076,7 +1078,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
}
|
||||
if shouldReport {
|
||||
strongSelf.speakingParticipantsReportTimestamp[peerId] = timestamp
|
||||
reportSpeakingParticipants.append(peerId)
|
||||
reportSpeakingParticipants[peerId] = ssrc
|
||||
}
|
||||
}
|
||||
|
||||
@ -1088,7 +1090,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
|
||||
var members = PresentationGroupCallMembers(
|
||||
participants: [],
|
||||
speakingParticipants: speakingParticipants,
|
||||
speakingParticipants: Set(speakingParticipants.keys),
|
||||
totalCount: 0,
|
||||
loadMoreToken: nil
|
||||
)
|
||||
@ -1127,6 +1129,12 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
strongSelf.stateValue.muteState = GroupCallParticipantsContext.Participant.MuteState(canUnmute: true, mutedByYou: false)
|
||||
strongSelf.callContext?.setIsMuted(true)
|
||||
}
|
||||
} else {
|
||||
if let volume = participant.volume {
|
||||
strongSelf.callContext?.setVolume(ssrc: participant.ssrc, volume: Double(volume) / 10000.0)
|
||||
} else if participant.muteState?.mutedByYou == true {
|
||||
strongSelf.callContext?.setVolume(ssrc: participant.ssrc, volume: 0.0)
|
||||
}
|
||||
}
|
||||
|
||||
if let index = updatedInvitedPeers.firstIndex(of: participant.peer.id) {
|
||||
@ -1369,11 +1377,11 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
case let .muted(isPushToTalkActive):
|
||||
isEffectivelyMuted = !isPushToTalkActive
|
||||
isVisuallyMuted = true
|
||||
self.updateMuteState(peerId: self.accountContext.account.peerId, isMuted: true)
|
||||
let _ = self.updateMuteState(peerId: self.accountContext.account.peerId, isMuted: true)
|
||||
case .unmuted:
|
||||
isEffectivelyMuted = false
|
||||
isVisuallyMuted = false
|
||||
self.updateMuteState(peerId: self.accountContext.account.peerId, isMuted: false)
|
||||
let _ = self.updateMuteState(peerId: self.accountContext.account.peerId, isMuted: false)
|
||||
}
|
||||
self.callContext?.setIsMuted(isEffectivelyMuted)
|
||||
|
||||
@ -1511,6 +1519,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
} else if self.stateValue.adminIds.contains(self.accountContext.account.peerId) {
|
||||
canThenUnmute = true
|
||||
} else {
|
||||
self.setVolume(peerId: peerId, volume: 0, sync: false)
|
||||
mutedByYou = true
|
||||
canThenUnmute = true
|
||||
}
|
||||
@ -1526,6 +1535,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
self.participantsContext?.updateMuteState(peerId: peerId, muteState: muteState, volume: nil)
|
||||
return muteState
|
||||
} else {
|
||||
self.setVolume(peerId: peerId, volume: 10000, sync: true)
|
||||
self.participantsContext?.updateMuteState(peerId: peerId, muteState: nil, volume: nil)
|
||||
return nil
|
||||
}
|
||||
@ -1726,4 +1736,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public func loadMoreMembers(token: String) {
|
||||
self.participantsContext?.loadMore(token: token)
|
||||
}
|
||||
}
|
||||
|
@ -547,14 +547,14 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
private func preparedTransition(from fromEntries: [ListEntry], to toEntries: [ListEntry], isLoading: Bool, isEmpty: Bool, crossFade: Bool, context: AccountContext, presentationData: PresentationData, interaction: Interaction) -> ListTransition {
|
||||
private func preparedTransition(from fromEntries: [ListEntry], to toEntries: [ListEntry], isLoading: Bool, isEmpty: Bool, crossFade: Bool, animated: Bool, context: AccountContext, presentationData: PresentationData, interaction: Interaction) -> ListTransition {
|
||||
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 ListTransition(deletions: deletions, insertions: insertions, updates: updates, isLoading: isLoading, isEmpty: isEmpty, crossFade: crossFade, count: toEntries.count, animated: true)
|
||||
return ListTransition(deletions: deletions, insertions: insertions, updates: updates, isLoading: isLoading, isEmpty: isEmpty, crossFade: crossFade, count: toEntries.count, animated: animated)
|
||||
}
|
||||
|
||||
private weak var controller: VoiceChatController?
|
||||
@ -598,7 +598,7 @@ public final class VoiceChatController: ViewController {
|
||||
|
||||
private var currentTitle: String = ""
|
||||
private var currentSubtitle: String = ""
|
||||
private var currentCallMembers: [GroupCallParticipantsContext.Participant]?
|
||||
private var currentCallMembers: ([GroupCallParticipantsContext.Participant], String?)?
|
||||
private var currentInvitedPeers: [Peer]?
|
||||
private var currentSpeakingPeers: Set<PeerId>?
|
||||
private var currentContentOffset: CGFloat?
|
||||
@ -619,6 +619,8 @@ public final class VoiceChatController: ViewController {
|
||||
|
||||
private var callState: PresentationGroupCallState?
|
||||
|
||||
private var currentLoadToken: String?
|
||||
|
||||
private var effectiveMuteState: GroupCallParticipantsContext.Participant.MuteState? {
|
||||
if self.pushingToTalk {
|
||||
return nil
|
||||
@ -788,7 +790,7 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
|
||||
var filters: [ChannelMembersSearchFilter] = []
|
||||
if let currentCallMembers = strongSelf.currentCallMembers {
|
||||
if let (currentCallMembers, _) = strongSelf.currentCallMembers {
|
||||
filters.append(.disable(Array(currentCallMembers.map { $0.peer.id })))
|
||||
}
|
||||
if let groupPeer = groupPeer as? TelegramChannel {
|
||||
@ -1253,7 +1255,7 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: callMembers?.participants ?? [], invitedPeers: invitedPeers, speakingPeers: callMembers?.speakingParticipants ?? [])
|
||||
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: (callMembers?.participants ?? [], callMembers?.loadMoreToken), invitedPeers: invitedPeers, speakingPeers: callMembers?.speakingParticipants ?? [])
|
||||
|
||||
let subtitle = strongSelf.presentationData.strings.VoiceChat_Panel_Members(Int32(max(1, callMembers?.totalCount ?? 0)))
|
||||
strongSelf.currentSubtitle = subtitle
|
||||
@ -1282,7 +1284,7 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
if !strongSelf.didSetDataReady {
|
||||
strongSelf.accountPeer = accountPeer
|
||||
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: strongSelf.currentCallMembers ?? [], invitedPeers: strongSelf.currentInvitedPeers ?? [], speakingPeers: strongSelf.currentSpeakingPeers ?? Set())
|
||||
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: strongSelf.currentCallMembers ?? ([], nil), invitedPeers: strongSelf.currentInvitedPeers ?? [], speakingPeers: strongSelf.currentSpeakingPeers ?? Set())
|
||||
|
||||
strongSelf.didSetDataReady = true
|
||||
strongSelf.controller?.dataReady.set(true)
|
||||
@ -1468,6 +1470,18 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
self.listNode.visibleBottomContentOffsetChanged = { [weak self] offset in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if case let .known(value) = offset, value < 100.0 {
|
||||
if let loadMoreToken = strongSelf.currentCallMembers?.1 {
|
||||
strongSelf.currentLoadToken = loadMoreToken
|
||||
strongSelf.call.loadMoreMembers(token: loadMoreToken)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.memberEventsDisposable.set((self.call.memberEvents
|
||||
|> deliverOnMainQueue).start(next: { [weak self] event in
|
||||
guard let strongSelf = self else {
|
||||
@ -1667,7 +1681,7 @@ public final class VoiceChatController: ViewController {
|
||||
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .spring))
|
||||
}
|
||||
|
||||
self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? [], invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set())
|
||||
self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? ([], nil), invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set())
|
||||
}
|
||||
|
||||
@objc private func actionButtonPressGesture(_ gestureRecognizer: UILongPressGestureRecognizer) {
|
||||
@ -1712,7 +1726,7 @@ public final class VoiceChatController: ViewController {
|
||||
if let (layout, navigationHeight) = self.validLayout {
|
||||
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .spring))
|
||||
}
|
||||
self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? [], invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set())
|
||||
self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? ([], nil), invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set())
|
||||
default:
|
||||
break
|
||||
}
|
||||
@ -2404,7 +2418,12 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
private func updateMembers(muteState: GroupCallParticipantsContext.Participant.MuteState?, callMembers: [GroupCallParticipantsContext.Participant], invitedPeers: [Peer], speakingPeers: Set<PeerId>) {
|
||||
private func updateMembers(muteState: GroupCallParticipantsContext.Participant.MuteState?, callMembers: ([GroupCallParticipantsContext.Participant], String?), invitedPeers: [Peer], speakingPeers: Set<PeerId>) {
|
||||
var disableAnimation = false
|
||||
if self.currentCallMembers?.1 != callMembers.1 {
|
||||
disableAnimation = true
|
||||
}
|
||||
|
||||
self.currentCallMembers = callMembers
|
||||
self.currentSpeakingPeers = speakingPeers
|
||||
self.currentInvitedPeers = invitedPeers
|
||||
@ -2418,7 +2437,7 @@ public final class VoiceChatController: ViewController {
|
||||
|
||||
entries.append(.invite(self.presentationData.theme, self.presentationData.strings, self.presentationData.strings.VoiceChat_InviteMember))
|
||||
|
||||
for member in callMembers {
|
||||
for member in callMembers.0 {
|
||||
if processedPeerIds.contains(member.peer.id) {
|
||||
continue
|
||||
}
|
||||
@ -2486,7 +2505,7 @@ public final class VoiceChatController: ViewController {
|
||||
self.currentEntries = entries
|
||||
|
||||
let presentationData = self.presentationData.withUpdated(theme: self.darkTheme)
|
||||
let transition = preparedTransition(from: previousEntries, to: entries, isLoading: false, isEmpty: false, crossFade: false, context: self.context, presentationData: presentationData, interaction: self.itemInteraction!)
|
||||
let transition = preparedTransition(from: previousEntries, to: entries, isLoading: false, isEmpty: false, crossFade: false, animated: !disableAnimation, context: self.context, presentationData: presentationData, interaction: self.itemInteraction!)
|
||||
self.enqueueTransition(transition)
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@ public enum ChatHistoryImport {
|
||||
}
|
||||
|
||||
public static func initSession(account: Account, peerId: PeerId, file: TempBoxFile, mediaCount: Int32) -> Signal<Session, InitImportError> {
|
||||
return multipartUpload(network: account.network, postbox: account.postbox, source: .tempFile(file), encrypt: false, tag: nil, hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false, useLargerParts: true, increaseParallelParts: true, useMultiplexedRequests: false, useCompression: true)
|
||||
return multipartUpload(network: account.network, postbox: account.postbox, source: .tempFile(file), encrypt: false, tag: nil, hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: true, useLargerParts: true, increaseParallelParts: true, useMultiplexedRequests: false, useCompression: true)
|
||||
|> mapError { _ -> InitImportError in
|
||||
return .generic
|
||||
}
|
||||
|
@ -195,10 +195,8 @@ public enum GetGroupCallParticipantsError {
|
||||
case generic
|
||||
}
|
||||
|
||||
public func getGroupCallParticipants(account: Account, callId: Int64, accessHash: Int64, ssrcs: [UInt32] = [], offset: String, limit: Int32) -> Signal<GroupCallParticipantsContext.State, GetGroupCallParticipantsError> {
|
||||
return account.network.request(Api.functions.phone.getGroupParticipants(call: .inputGroupCall(id: callId, accessHash: accessHash), ids: [], sources: ssrcs.map {
|
||||
Int32(bitPattern: $0)
|
||||
}, offset: offset, limit: limit))
|
||||
public func getGroupCallParticipants(account: Account, callId: Int64, accessHash: Int64, offset: String, ssrcs: [UInt32], limit: Int32) -> Signal<GroupCallParticipantsContext.State, GetGroupCallParticipantsError> {
|
||||
return account.network.request(Api.functions.phone.getGroupParticipants(call: .inputGroupCall(id: callId, accessHash: accessHash), ids: [], sources: ssrcs.map { Int32(bitPattern: $0) }, offset: offset, limit: limit))
|
||||
|> mapError { _ -> GetGroupCallParticipantsError in
|
||||
return .generic
|
||||
}
|
||||
@ -386,7 +384,7 @@ public func joinGroupCall(account: Account, peerId: PeerId, callId: Int64, acces
|
||||
|> mapError { _ -> JoinGroupCallError in
|
||||
return .generic
|
||||
},
|
||||
getGroupCallParticipants(account: account, callId: callId, accessHash: accessHash, offset: "", limit: 100)
|
||||
getGroupCallParticipants(account: account, callId: callId, accessHash: accessHash, offset: "", ssrcs: [], limit: 100)
|
||||
|> mapError { _ -> JoinGroupCallError in
|
||||
return .generic
|
||||
},
|
||||
@ -760,7 +758,7 @@ public final class GroupCallParticipantsContext {
|
||||
private let id: Int64
|
||||
private let accessHash: Int64
|
||||
|
||||
private var hasReceivedSpeackingParticipantsReport: Bool = false
|
||||
private var hasReceivedSpeakingParticipantsReport: Bool = false
|
||||
|
||||
private var stateValue: InternalState {
|
||||
didSet {
|
||||
@ -812,6 +810,10 @@ public final class GroupCallParticipantsContext {
|
||||
private let updatesDisposable = MetaDisposable()
|
||||
private var activitiesDisposable: Disposable?
|
||||
|
||||
private var isLoadingMore: Bool = false
|
||||
private var shouldResetStateFromServer: Bool = false
|
||||
private var missingSsrcs = Set<UInt32>()
|
||||
|
||||
private let updateDefaultMuteDisposable = MetaDisposable()
|
||||
|
||||
public init(account: Account, peerId: PeerId, id: Int64, accessHash: Int64, state: State) {
|
||||
@ -844,11 +846,12 @@ public final class GroupCallParticipantsContext {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.activeSpeakersValue = Set(activities.map { item -> PeerId in
|
||||
let peerIds = Set(activities.map { item -> PeerId in
|
||||
item.0
|
||||
})
|
||||
strongSelf.activeSpeakersValue = peerIds
|
||||
|
||||
if !strongSelf.hasReceivedSpeackingParticipantsReport {
|
||||
if !strongSelf.hasReceivedSpeakingParticipantsReport {
|
||||
var updatedParticipants = strongSelf.stateValue.state.participants
|
||||
var indexMap: [PeerId: Int] = [:]
|
||||
for i in 0 ..< updatedParticipants.count {
|
||||
@ -925,9 +928,9 @@ public final class GroupCallParticipantsContext {
|
||||
}
|
||||
}
|
||||
|
||||
public func reportSpeakingParticipants(ids: [PeerId]) {
|
||||
public func reportSpeakingParticipants(ids: [PeerId: UInt32]) {
|
||||
if !ids.isEmpty {
|
||||
self.hasReceivedSpeackingParticipantsReport = true
|
||||
self.hasReceivedSpeakingParticipantsReport = true
|
||||
}
|
||||
|
||||
let strongSelf = self
|
||||
@ -941,7 +944,7 @@ public final class GroupCallParticipantsContext {
|
||||
|
||||
let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970
|
||||
|
||||
for activityPeerId in ids {
|
||||
for (activityPeerId, _) in ids {
|
||||
if let index = indexMap[activityPeerId] {
|
||||
var updateTimestamp = false
|
||||
if let activityTimestamp = updatedParticipants[index].activityTimestamp {
|
||||
@ -982,6 +985,77 @@ public final class GroupCallParticipantsContext {
|
||||
overlayState: strongSelf.stateValue.overlayState
|
||||
)
|
||||
}
|
||||
|
||||
self.ensureHaveParticipants(ssrcs: Set(ids.map { $0.1 }))
|
||||
}
|
||||
|
||||
private func ensureHaveParticipants(ssrcs: Set<UInt32>) {
|
||||
var missingSsrcs = Set<UInt32>()
|
||||
|
||||
var existingSsrcs = Set<UInt32>()
|
||||
for participant in self.stateValue.state.participants {
|
||||
existingSsrcs.insert(participant.ssrc)
|
||||
}
|
||||
|
||||
for ssrc in ssrcs {
|
||||
if !existingSsrcs.contains(ssrc) {
|
||||
missingSsrcs.insert(ssrc)
|
||||
}
|
||||
}
|
||||
|
||||
if !missingSsrcs.isEmpty {
|
||||
self.missingSsrcs.formUnion(missingSsrcs)
|
||||
self.loadMissingSsrcs()
|
||||
}
|
||||
}
|
||||
|
||||
private func loadMissingSsrcs() {
|
||||
if self.missingSsrcs.isEmpty {
|
||||
return
|
||||
}
|
||||
if self.isLoadingMore {
|
||||
return
|
||||
}
|
||||
self.isLoadingMore = true
|
||||
|
||||
let ssrcs = self.missingSsrcs
|
||||
|
||||
self.disposable.set((getGroupCallParticipants(account: self.account, callId: self.id, accessHash: self.accessHash, offset: "", ssrcs: Array(ssrcs), limit: 100)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] state in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.isLoadingMore = false
|
||||
|
||||
strongSelf.missingSsrcs.subtract(ssrcs)
|
||||
|
||||
var updatedState = strongSelf.stateValue.state
|
||||
|
||||
var existingParticipantIds = Set<PeerId>()
|
||||
for participant in updatedState.participants {
|
||||
existingParticipantIds.insert(participant.peer.id)
|
||||
}
|
||||
for participant in state.participants {
|
||||
if existingParticipantIds.contains(participant.peer.id) {
|
||||
continue
|
||||
}
|
||||
existingParticipantIds.insert(participant.peer.id)
|
||||
updatedState.participants.append(participant)
|
||||
}
|
||||
|
||||
updatedState.participants.sort()
|
||||
|
||||
updatedState.totalCount = max(updatedState.totalCount, state.totalCount)
|
||||
updatedState.version = max(updatedState.version, updatedState.version)
|
||||
|
||||
strongSelf.stateValue.state = updatedState
|
||||
|
||||
if strongSelf.shouldResetStateFromServer {
|
||||
strongSelf.resetStateFromServer()
|
||||
} else {
|
||||
strongSelf.loadMissingSsrcs()
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
private func beginProcessingUpdatesIfNeeded() {
|
||||
@ -1123,13 +1197,22 @@ public final class GroupCallParticipantsContext {
|
||||
}
|
||||
|
||||
private func resetStateFromServer() {
|
||||
if self.isLoadingMore {
|
||||
self.shouldResetStateFromServer = true
|
||||
return
|
||||
}
|
||||
|
||||
self.isLoadingMore = true
|
||||
|
||||
self.updateQueue.removeAll()
|
||||
|
||||
self.disposable.set((getGroupCallParticipants(account: self.account, callId: self.id, accessHash: self.accessHash, offset: "", limit: 100)
|
||||
self.disposable.set((getGroupCallParticipants(account: self.account, callId: self.id, accessHash: self.accessHash, offset: "", ssrcs: [], limit: 100)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] state in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.isLoadingMore = false
|
||||
strongSelf.shouldResetStateFromServer = false
|
||||
strongSelf.stateValue.state = state
|
||||
strongSelf.endedProcessingUpdate()
|
||||
}))
|
||||
@ -1232,6 +1315,49 @@ public final class GroupCallParticipantsContext {
|
||||
strongSelf.account.stateManager.addUpdates(updates)
|
||||
}))
|
||||
}
|
||||
|
||||
public func loadMore(token: String) {
|
||||
if token != self.stateValue.state.nextParticipantsFetchOffset {
|
||||
Logger.shared.log("GroupCallParticipantsContext", "loadMore called with an invalid token \(token) (the valid one is \(String(describing: self.stateValue.state.nextParticipantsFetchOffset)))")
|
||||
return
|
||||
}
|
||||
if self.isLoadingMore {
|
||||
return
|
||||
}
|
||||
self.isLoadingMore = true
|
||||
|
||||
self.disposable.set((getGroupCallParticipants(account: self.account, callId: self.id, accessHash: self.accessHash, offset: token, ssrcs: [], limit: 100)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] state in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.isLoadingMore = false
|
||||
|
||||
var updatedState = strongSelf.stateValue.state
|
||||
|
||||
var existingParticipantIds = Set<PeerId>()
|
||||
for participant in updatedState.participants {
|
||||
existingParticipantIds.insert(participant.peer.id)
|
||||
}
|
||||
for participant in state.participants {
|
||||
if existingParticipantIds.contains(participant.peer.id) {
|
||||
continue
|
||||
}
|
||||
existingParticipantIds.insert(participant.peer.id)
|
||||
updatedState.participants.append(participant)
|
||||
}
|
||||
|
||||
updatedState.nextParticipantsFetchOffset = state.nextParticipantsFetchOffset
|
||||
updatedState.totalCount = max(updatedState.totalCount, state.totalCount)
|
||||
updatedState.version = max(updatedState.version, updatedState.version)
|
||||
|
||||
strongSelf.stateValue.state = updatedState
|
||||
|
||||
if strongSelf.shouldResetStateFromServer {
|
||||
strongSelf.resetStateFromServer()
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
extension GroupCallParticipantsContext.Update.StateUpdate.ParticipantUpdate {
|
||||
|
@ -34,12 +34,6 @@ extension CellularNetworkType {
|
||||
|
||||
#endif
|
||||
|
||||
enum InternalNetworkType: Equatable {
|
||||
case none
|
||||
case wifi
|
||||
case cellular
|
||||
}
|
||||
|
||||
public enum NetworkType: Equatable {
|
||||
case none
|
||||
case wifi
|
||||
@ -50,7 +44,7 @@ public enum NetworkType: Equatable {
|
||||
|
||||
extension NetworkType {
|
||||
#if os(iOS)
|
||||
init(internalType: InternalNetworkType, cellularType: CellularNetworkType) {
|
||||
init(internalType: Reachability.NetworkType, cellularType: CellularNetworkType) {
|
||||
switch internalType {
|
||||
case .none:
|
||||
self = .none
|
||||
@ -61,7 +55,7 @@ extension NetworkType {
|
||||
}
|
||||
}
|
||||
#else
|
||||
init(internalType: InternalNetworkType) {
|
||||
init(internalType: Reachability.NetworkType) {
|
||||
switch internalType {
|
||||
case .none:
|
||||
self = .none
|
||||
@ -72,91 +66,11 @@ extension NetworkType {
|
||||
#endif
|
||||
}
|
||||
|
||||
private final class WrappedReachability: NSObject {
|
||||
@objc private static func threadImpl() {
|
||||
while true {
|
||||
RunLoop.current.run(until: .distantFuture)
|
||||
}
|
||||
}
|
||||
|
||||
static let thread: Thread = {
|
||||
let thread = Thread(target: WrappedReachability.self, selector: #selector(WrappedReachability.threadImpl), object: nil)
|
||||
thread.start()
|
||||
return thread
|
||||
}()
|
||||
|
||||
@objc private static func dispatchOnThreadImpl(_ f: @escaping () -> Void) {
|
||||
f()
|
||||
}
|
||||
|
||||
private static func dispatchOnThread(_ f: @escaping @convention(block) () -> Void) {
|
||||
WrappedReachability.perform(#selector(WrappedReachability.dispatchOnThreadImpl(_:)), on: WrappedReachability.thread, with: f, waitUntilDone: false)
|
||||
}
|
||||
|
||||
private let reachability: Reachability
|
||||
|
||||
let value: ValuePromise<InternalNetworkType>
|
||||
|
||||
override init() {
|
||||
assert(Thread.current === WrappedReachability.thread)
|
||||
self.reachability = Reachability.forInternetConnection()
|
||||
let type: InternalNetworkType
|
||||
switch self.reachability.currentReachabilityStatus() {
|
||||
case NotReachable:
|
||||
type = .none
|
||||
case ReachableViaWiFi:
|
||||
type = .wifi
|
||||
case ReachableViaWWAN:
|
||||
type = .cellular
|
||||
default:
|
||||
type = .none
|
||||
}
|
||||
self.value = ValuePromise<InternalNetworkType>(type)
|
||||
|
||||
super.init()
|
||||
|
||||
self.reachability.reachabilityChanged = { [weak self] status in
|
||||
WrappedReachability.dispatchOnThread {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let internalNetworkType: InternalNetworkType
|
||||
switch status {
|
||||
case NotReachable:
|
||||
internalNetworkType = .none
|
||||
case ReachableViaWiFi:
|
||||
internalNetworkType = .wifi
|
||||
case ReachableViaWWAN:
|
||||
internalNetworkType = .cellular
|
||||
default:
|
||||
internalNetworkType = .none
|
||||
}
|
||||
strongSelf.value.set(internalNetworkType)
|
||||
}
|
||||
}
|
||||
self.reachability.startNotifier()
|
||||
}
|
||||
|
||||
static var valueRef: Unmanaged<WrappedReachability>?
|
||||
|
||||
static func withInstance(_ f: @escaping (WrappedReachability) -> Void) {
|
||||
WrappedReachability.dispatchOnThread {
|
||||
if self.valueRef == nil {
|
||||
self.valueRef = Unmanaged.passRetained(WrappedReachability())
|
||||
}
|
||||
if let valueRef = self.valueRef {
|
||||
let value = valueRef.takeUnretainedValue()
|
||||
f(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class NetworkTypeManagerImpl {
|
||||
let queue: Queue
|
||||
let updated: (NetworkType) -> Void
|
||||
var networkTypeDisposable: Disposable?
|
||||
var currentNetworkType: InternalNetworkType?
|
||||
var currentNetworkType: Reachability.NetworkType?
|
||||
var networkType: NetworkType?
|
||||
#if os(iOS)
|
||||
var currentCellularType: CellularNetworkType
|
||||
@ -196,29 +110,27 @@ private final class NetworkTypeManagerImpl {
|
||||
|
||||
let networkTypeDisposable = MetaDisposable()
|
||||
self.networkTypeDisposable = networkTypeDisposable
|
||||
|
||||
WrappedReachability.withInstance({ [weak self] impl in
|
||||
networkTypeDisposable.set((impl.value.get()
|
||||
|> deliverOn(queue)).start(next: { networkStatus in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
|
||||
networkTypeDisposable.set((Reachability.networkType
|
||||
|> deliverOn(queue)).start(next: { [weak self] networkStatus in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if strongSelf.currentNetworkType != networkStatus {
|
||||
strongSelf.currentNetworkType = networkStatus
|
||||
|
||||
let networkType: NetworkType
|
||||
#if os(iOS)
|
||||
networkType = NetworkType(internalType: networkStatus, cellularType: strongSelf.currentCellularType)
|
||||
#else
|
||||
networkType = NetworkType(internalType: networkStatus)
|
||||
#endif
|
||||
if strongSelf.networkType != networkType {
|
||||
strongSelf.networkType = networkType
|
||||
updated(networkType)
|
||||
}
|
||||
if strongSelf.currentNetworkType != networkStatus {
|
||||
strongSelf.currentNetworkType = networkStatus
|
||||
|
||||
let networkType: NetworkType
|
||||
#if os(iOS)
|
||||
networkType = NetworkType(internalType: networkStatus, cellularType: strongSelf.currentCellularType)
|
||||
#else
|
||||
networkType = NetworkType(internalType: networkStatus)
|
||||
#endif
|
||||
if strongSelf.networkType != networkType {
|
||||
strongSelf.networkType = networkType
|
||||
updated(networkType)
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
func stop() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"app": "7.4.1",
|
||||
"app": "7.4.2",
|
||||
"bazel": "3.7.0",
|
||||
"xcode": "12.3"
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user