mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Update
This commit is contained in:
parent
d3d1b0ee39
commit
84171b89f4
9 changed files with 251 additions and 117 deletions
|
|
@ -2669,6 +2669,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||
}
|
||||
self.stateValue.messagesAreEnabled = state.messagesAreEnabled.isEnabled
|
||||
self.stateValue.canEnableMessages = state.messagesAreEnabled.canChange
|
||||
self.stateValue.sendPaidMessageStars = state.messagesAreEnabled.sendPaidMessagesStars
|
||||
self.stateValue.recordingStartTimestamp = state.recordingStartTimestamp
|
||||
self.stateValue.title = state.title
|
||||
self.stateValue.scheduleTimestamp = state.scheduleTimestamp
|
||||
|
|
|
|||
|
|
@ -371,7 +371,8 @@ public final class ConferenceCallE2EContext {
|
|||
offset: "",
|
||||
ssrcs: [],
|
||||
limit: 100,
|
||||
sortAscending: true
|
||||
sortAscending: true,
|
||||
isStream: false
|
||||
)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<GroupCallParticipantsContext.State?, NoError> in
|
||||
|
|
|
|||
|
|
@ -507,7 +507,7 @@ public enum GetGroupCallParticipantsError {
|
|||
case generic
|
||||
}
|
||||
|
||||
func _internal_getGroupCallParticipants(account: Account, reference: InternalGroupCallReference, offset: String, ssrcs: [UInt32], limit: Int32, sortAscending: Bool?) -> Signal<GroupCallParticipantsContext.State, GetGroupCallParticipantsError> {
|
||||
func _internal_getGroupCallParticipants(account: Account, reference: InternalGroupCallReference, offset: String, ssrcs: [UInt32], limit: Int32, sortAscending: Bool?, isStream: Bool) -> Signal<GroupCallParticipantsContext.State, GetGroupCallParticipantsError> {
|
||||
let accountPeerId = account.peerId
|
||||
|
||||
let sortAscendingValue: Signal<(Bool, Int32?, Bool, GroupCallParticipantsContext.State.DefaultParticipantsAreMuted?, GroupCallParticipantsContext.State.MessagesAreEnabled?, Bool, Int, Bool, Bool), GetGroupCallParticipantsError>
|
||||
|
|
@ -525,8 +525,15 @@ func _internal_getGroupCallParticipants(account: Account, reference: InternalGro
|
|||
|
||||
return combineLatest(
|
||||
account.network.request(Api.functions.phone.getGroupParticipants(call: reference.apiInputGroupCall, ids: [], sources: ssrcs.map { Int32(bitPattern: $0) }, offset: offset, limit: limit))
|
||||
|> map(Optional.init)
|
||||
|> mapError { _ -> GetGroupCallParticipantsError in
|
||||
return .generic
|
||||
}
|
||||
|> `catch` { error -> Signal<Api.phone.GroupParticipants?, GetGroupCallParticipantsError> in
|
||||
if isStream {
|
||||
return .single(nil)
|
||||
}
|
||||
return .fail(error)
|
||||
},
|
||||
sortAscendingValue
|
||||
)
|
||||
|
|
@ -539,21 +546,27 @@ func _internal_getGroupCallParticipants(account: Account, reference: InternalGro
|
|||
|
||||
let (sortAscendingValue, scheduleTimestamp, subscribedToScheduled, defaultParticipantsAreMuted, messagesAreEnabled, isVideoEnabled, unmutedVideoLimit, isStream, isCreator) = sortAscendingAndScheduleTimestamp
|
||||
|
||||
switch result {
|
||||
case let .groupParticipants(count, participants, nextOffset, chats, users, apiVersion):
|
||||
totalCount = Int(count)
|
||||
version = apiVersion
|
||||
|
||||
if participants.count != 0 && !nextOffset.isEmpty {
|
||||
nextParticipantsFetchOffset = nextOffset
|
||||
} else {
|
||||
nextParticipantsFetchOffset = nil
|
||||
if let result {
|
||||
switch result {
|
||||
case let .groupParticipants(count, participants, nextOffset, chats, users, apiVersion):
|
||||
totalCount = Int(count)
|
||||
version = apiVersion
|
||||
|
||||
if participants.count != 0 && !nextOffset.isEmpty {
|
||||
nextParticipantsFetchOffset = nextOffset
|
||||
} else {
|
||||
nextParticipantsFetchOffset = nil
|
||||
}
|
||||
|
||||
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
|
||||
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
|
||||
|
||||
parsedParticipants = participants.compactMap { GroupCallParticipantsContext.Participant($0, transaction: transaction) }
|
||||
}
|
||||
|
||||
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
|
||||
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
|
||||
|
||||
parsedParticipants = participants.compactMap { GroupCallParticipantsContext.Participant($0, transaction: transaction) }
|
||||
} else {
|
||||
totalCount = 0
|
||||
version = 0
|
||||
nextParticipantsFetchOffset = nil
|
||||
}
|
||||
|
||||
parsedParticipants.sort(by: { GroupCallParticipantsContext.Participant.compare(lhs: $0, rhs: $1, sortAscending: sortAscendingValue) })
|
||||
|
|
@ -645,7 +658,7 @@ func _internal_joinGroupCall(account: Account, peerId: PeerId?, joinAs: PeerId?,
|
|||
|> castError(InternalJoinError.self)
|
||||
|> mapToSignal { e2eData -> Signal<JoinGroupCallResult, InternalJoinError> in
|
||||
return account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||
if let joinAs = joinAs {
|
||||
if let joinAs {
|
||||
return transaction.getPeer(joinAs).flatMap(apiInputPeer)
|
||||
} else {
|
||||
return .inputPeerSelf
|
||||
|
|
@ -653,7 +666,7 @@ func _internal_joinGroupCall(account: Account, peerId: PeerId?, joinAs: PeerId?,
|
|||
}
|
||||
|> castError(InternalJoinError.self)
|
||||
|> mapToSignal { inputJoinAs -> Signal<JoinGroupCallResult, InternalJoinError> in
|
||||
guard let inputJoinAs = inputJoinAs else {
|
||||
guard let inputJoinAs else {
|
||||
return .fail(.error(.generic))
|
||||
}
|
||||
|
||||
|
|
@ -719,38 +732,13 @@ func _internal_joinGroupCall(account: Account, peerId: PeerId?, joinAs: PeerId?,
|
|||
}
|
||||
}
|
||||
|
||||
let getParticipantsRequest: Signal<GroupCallParticipantsContext.State, InternalJoinError>
|
||||
if isStream {
|
||||
getParticipantsRequest = .single(GroupCallParticipantsContext.State(
|
||||
participants: [],
|
||||
nextParticipantsFetchOffset: nil,
|
||||
adminIds: Set(),
|
||||
isCreator: false,
|
||||
defaultParticipantsAreMuted: .init(isMuted: true, canChange: false),
|
||||
messagesAreEnabled: .init(isEnabled: true, canChange: false, sendPaidMessagesStars: nil),
|
||||
sortAscending: true,
|
||||
recordingStartTimestamp: nil,
|
||||
title: nil,
|
||||
scheduleTimestamp: nil,
|
||||
subscribedToScheduled: false,
|
||||
totalCount: 0,
|
||||
isVideoEnabled: false,
|
||||
unmutedVideoLimit: 0,
|
||||
isStream: true,
|
||||
version: 0
|
||||
))
|
||||
} else {
|
||||
getParticipantsRequest = _internal_getGroupCallParticipants(account: account, reference: reference, offset: "", ssrcs: [], limit: 100, sortAscending: true)
|
||||
|> mapError { _ -> InternalJoinError in
|
||||
return .error(.generic)
|
||||
}
|
||||
let getParticipantsRequest = _internal_getGroupCallParticipants(account: account, reference: reference, offset: "", ssrcs: [], limit: 100, sortAscending: true, isStream: isStream)
|
||||
|> mapError { _ -> InternalJoinError in
|
||||
return .error(.generic)
|
||||
}
|
||||
|
||||
return combineLatest(
|
||||
joinRequest,
|
||||
getParticipantsRequest
|
||||
)
|
||||
|> mapToSignal { updates, participantsState -> Signal<JoinGroupCallResult, InternalJoinError> in
|
||||
return joinRequest
|
||||
|> mapToSignal { updates -> Signal<JoinGroupCallResult, InternalJoinError> in
|
||||
let peer = account.postbox.transaction { transaction -> Peer? in
|
||||
return peerId.flatMap(transaction.getPeer)
|
||||
}
|
||||
|
|
@ -758,9 +746,10 @@ func _internal_joinGroupCall(account: Account, peerId: PeerId?, joinAs: PeerId?,
|
|||
|
||||
return combineLatest(
|
||||
peerAdminIds |> castError(InternalJoinError.self) |> take(1),
|
||||
peer
|
||||
peer,
|
||||
getParticipantsRequest
|
||||
)
|
||||
|> mapToSignal { peerAdminIds, peer -> Signal<JoinGroupCallResult, InternalJoinError> in
|
||||
|> mapToSignal { peerAdminIds, peer, participantsState -> Signal<JoinGroupCallResult, InternalJoinError> in
|
||||
var state = participantsState
|
||||
if let peer {
|
||||
if let channel = peer as? TelegramChannel {
|
||||
|
|
@ -2149,7 +2138,7 @@ public final class GroupCallParticipantsContext {
|
|||
|
||||
Logger.shared.log("GroupCallParticipantsContext", "will request ssrcs=\(ssrcs)")
|
||||
|
||||
self.disposable.set((_internal_getGroupCallParticipants(account: self.account, reference: self.reference, offset: "", ssrcs: Array(ssrcs), limit: 100, sortAscending: true)
|
||||
self.disposable.set((_internal_getGroupCallParticipants(account: self.account, reference: self.reference, offset: "", ssrcs: Array(ssrcs), limit: 100, sortAscending: true, isStream: false)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] state in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
|
|
@ -2367,7 +2356,7 @@ public final class GroupCallParticipantsContext {
|
|||
|
||||
self.updateQueue.removeAll()
|
||||
|
||||
self.disposable.set((_internal_getGroupCallParticipants(account: self.account, reference: self.reference, offset: "", ssrcs: [], limit: 100, sortAscending: self.stateValue.state.sortAscending)
|
||||
self.disposable.set((_internal_getGroupCallParticipants(account: self.account, reference: self.reference, offset: "", ssrcs: [], limit: 100, sortAscending: self.stateValue.state.sortAscending, isStream: false)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] state in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
|
|
@ -2672,7 +2661,7 @@ public final class GroupCallParticipantsContext {
|
|||
}
|
||||
self.isLoadingMore = true
|
||||
|
||||
self.disposable.set((_internal_getGroupCallParticipants(account: self.account, reference: self.reference, offset: token, ssrcs: [], limit: 100, sortAscending: self.stateValue.state.sortAscending)
|
||||
self.disposable.set((_internal_getGroupCallParticipants(account: self.account, reference: self.reference, offset: token, ssrcs: [], limit: 100, sortAscending: self.stateValue.state.sortAscending, isStream: false)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] state in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ public extension TelegramEngine {
|
|||
}
|
||||
|
||||
public func getGroupCallParticipants(reference: InternalGroupCallReference, offset: String, ssrcs: [UInt32], limit: Int32, sortAscending: Bool?) -> Signal<GroupCallParticipantsContext.State, GetGroupCallParticipantsError> {
|
||||
return _internal_getGroupCallParticipants(account: self.account, reference: reference, offset: offset, ssrcs: ssrcs, limit: limit, sortAscending: sortAscending)
|
||||
return _internal_getGroupCallParticipants(account: self.account, reference: reference, offset: offset, ssrcs: ssrcs, limit: limit, sortAscending: sortAscending, isStream: false)
|
||||
}
|
||||
|
||||
public func joinGroupCall(peerId: PeerId?, joinAs: PeerId?, callId: Int64, reference: InternalGroupCallReference, isStream: Bool, preferMuted: Bool, joinPayload: String, peerAdminIds: Signal<[PeerId], NoError>, inviteHash: String? = nil, generateE2E: ((Data?) -> JoinGroupCallE2E?)?) -> Signal<JoinGroupCallResult, JoinGroupCallError> {
|
||||
|
|
|
|||
|
|
@ -788,6 +788,7 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||
|
||||
private struct Amount: Equatable {
|
||||
private let sliderSteps: [Int]
|
||||
private let minRealValue: Int
|
||||
private let maxRealValue: Int
|
||||
let maxSliderValue: Int
|
||||
private let isLogarithmic: Bool
|
||||
|
|
@ -795,14 +796,16 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||
private(set) var realValue: Int
|
||||
private(set) var sliderValue: Int
|
||||
|
||||
private static func makeSliderSteps(maxRealValue: Int, isLogarithmic: Bool) -> [Int] {
|
||||
private static func makeSliderSteps(minRealValue: Int, maxRealValue: Int, isLogarithmic: Bool) -> [Int] {
|
||||
if isLogarithmic {
|
||||
var sliderSteps: [Int] = [ 1, 10, 50, 100, 500, 1_000, 2_000, 5_000, 7_500, 10_000 ]
|
||||
var sliderSteps: [Int] = [1, 10, 50, 100, 500, 1_000, 2_000, 5_000, 7_500, 10_000 ]
|
||||
sliderSteps.removeAll(where: { $0 <= minRealValue })
|
||||
sliderSteps.insert(minRealValue, at: 0)
|
||||
sliderSteps.removeAll(where: { $0 >= maxRealValue })
|
||||
sliderSteps.append(maxRealValue)
|
||||
return sliderSteps
|
||||
} else {
|
||||
return [1, maxRealValue]
|
||||
return [minRealValue, maxRealValue]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -834,8 +837,9 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||
}
|
||||
}
|
||||
|
||||
init(realValue: Int, maxRealValue: Int, maxSliderValue: Int, isLogarithmic: Bool) {
|
||||
self.sliderSteps = Amount.makeSliderSteps(maxRealValue: maxRealValue, isLogarithmic: isLogarithmic)
|
||||
init(realValue: Int, minRealValue: Int, maxRealValue: Int, maxSliderValue: Int, isLogarithmic: Bool) {
|
||||
self.sliderSteps = Amount.makeSliderSteps(minRealValue: minRealValue, maxRealValue: maxRealValue, isLogarithmic: isLogarithmic)
|
||||
self.minRealValue = minRealValue
|
||||
self.maxRealValue = maxRealValue
|
||||
self.maxSliderValue = maxSliderValue
|
||||
self.isLogarithmic = isLogarithmic
|
||||
|
|
@ -844,8 +848,9 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||
self.sliderValue = Amount.remapValueToSlider(realValue: self.realValue, maxSliderValue: self.maxSliderValue, steps: self.sliderSteps)
|
||||
}
|
||||
|
||||
init(sliderValue: Int, maxRealValue: Int, maxSliderValue: Int, isLogarithmic: Bool) {
|
||||
self.sliderSteps = Amount.makeSliderSteps(maxRealValue: maxRealValue, isLogarithmic: isLogarithmic)
|
||||
init(sliderValue: Int, minRealValue: Int, maxRealValue: Int, maxSliderValue: Int, isLogarithmic: Bool) {
|
||||
self.sliderSteps = Amount.makeSliderSteps(minRealValue: minRealValue, maxRealValue: maxRealValue, isLogarithmic: isLogarithmic)
|
||||
self.minRealValue = minRealValue
|
||||
self.maxRealValue = maxRealValue
|
||||
self.maxSliderValue = maxSliderValue
|
||||
self.isLogarithmic = isLogarithmic
|
||||
|
|
@ -855,11 +860,11 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||
}
|
||||
|
||||
func withRealValue(_ realValue: Int) -> Amount {
|
||||
return Amount(realValue: realValue, maxRealValue: self.maxRealValue, maxSliderValue: self.maxSliderValue, isLogarithmic: self.isLogarithmic)
|
||||
return Amount(realValue: realValue, minRealValue: self.minRealValue, maxRealValue: self.maxRealValue, maxSliderValue: self.maxSliderValue, isLogarithmic: self.isLogarithmic)
|
||||
}
|
||||
|
||||
func withSliderValue(_ sliderValue: Int) -> Amount {
|
||||
return Amount(sliderValue: sliderValue, maxRealValue: self.maxRealValue, maxSliderValue: self.maxSliderValue, isLogarithmic: self.isLogarithmic)
|
||||
return Amount(sliderValue: sliderValue, minRealValue: self.minRealValue, maxRealValue: self.maxRealValue, maxSliderValue: self.maxSliderValue, isLogarithmic: self.isLogarithmic)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -926,7 +931,7 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||
|
||||
private var balance: StarsAmount?
|
||||
|
||||
private var amount: Amount = Amount(realValue: 1, maxRealValue: 1000, maxSliderValue: 1000, isLogarithmic: true)
|
||||
private var amount: Amount = Amount(realValue: 1, minRealValue: 1, maxRealValue: 1000, maxSliderValue: 1000, isLogarithmic: true)
|
||||
private var didChangeAmount: Bool = false
|
||||
|
||||
private var privacyPeer: PrivacyPeer = .account
|
||||
|
|
@ -1423,7 +1428,7 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||
switch component.initialData.subjectInitialData {
|
||||
case let .react(reactData):
|
||||
self.currentMyPeer = reactData.myPeer
|
||||
self.amount = Amount(realValue: 50, maxRealValue: reactData.maxAmount, maxSliderValue: 999, isLogarithmic: true)
|
||||
self.amount = Amount(realValue: max(reactData.minAmount, 50), minRealValue: reactData.minAmount, maxRealValue: reactData.maxAmount, maxSliderValue: 999, isLogarithmic: true)
|
||||
|
||||
if let myTopPeer = reactData.myTopPeer {
|
||||
if myTopPeer.isAnonymous {
|
||||
|
|
@ -1460,7 +1465,9 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||
})
|
||||
case let .liveStreamMessage(liveStreamMessageData):
|
||||
self.currentMyPeer = nil
|
||||
self.amount = Amount(realValue: 50, maxRealValue: liveStreamMessageData.maxAmount, maxSliderValue: 999, isLogarithmic: true)
|
||||
|
||||
let currentValue: Int = liveStreamMessageData.currentAmount ?? 50
|
||||
self.amount = Amount(realValue: max(currentValue, liveStreamMessageData.minAmount), minRealValue: liveStreamMessageData.minAmount, maxRealValue: liveStreamMessageData.maxAmount, maxSliderValue: 999, isLogarithmic: true)
|
||||
|
||||
self.privacyPeer = .account
|
||||
}
|
||||
|
|
@ -2614,7 +2621,7 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||
public class ChatSendStarsScreen: ViewControllerComponentContainer {
|
||||
public enum ReactSubject {
|
||||
case message(EngineMessage.Id)
|
||||
case liveStream(peerId: EnginePeer.Id, storyId: Int32)
|
||||
case liveStream(peerId: EnginePeer.Id, storyId: Int32, minAmount: Int)
|
||||
}
|
||||
|
||||
fileprivate enum SubjectInitialData {
|
||||
|
|
@ -2627,10 +2634,11 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
|
|||
let currentSentAmount: Int?
|
||||
let topPeers: [ChatSendStarsScreen.TopPeer]
|
||||
let myTopPeer: ChatSendStarsScreen.TopPeer?
|
||||
let minAmount: Int
|
||||
let maxAmount: Int
|
||||
let completion: (Int64, TelegramPaidReactionPrivacy, Bool, ChatSendStarsScreen.TransitionOut) -> Void
|
||||
|
||||
init(peer: EnginePeer, myPeer: EnginePeer, defaultPrivacyPeer: ChatSendStarsScreenComponent.PrivacyPeer, channelsForPublicReaction: [EnginePeer], reactSubject: ReactSubject, currentSentAmount: Int?, topPeers: [ChatSendStarsScreen.TopPeer], myTopPeer: ChatSendStarsScreen.TopPeer?, maxAmount: Int, completion: @escaping (Int64, TelegramPaidReactionPrivacy, Bool, ChatSendStarsScreen.TransitionOut) -> Void) {
|
||||
init(peer: EnginePeer, myPeer: EnginePeer, defaultPrivacyPeer: ChatSendStarsScreenComponent.PrivacyPeer, channelsForPublicReaction: [EnginePeer], reactSubject: ReactSubject, currentSentAmount: Int?, topPeers: [ChatSendStarsScreen.TopPeer], myTopPeer: ChatSendStarsScreen.TopPeer?, minAmount: Int, maxAmount: Int, completion: @escaping (Int64, TelegramPaidReactionPrivacy, Bool, ChatSendStarsScreen.TransitionOut) -> Void) {
|
||||
self.peer = peer
|
||||
self.myPeer = myPeer
|
||||
self.defaultPrivacyPeer = defaultPrivacyPeer
|
||||
|
|
@ -2639,6 +2647,7 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
|
|||
self.currentSentAmount = currentSentAmount
|
||||
self.topPeers = topPeers
|
||||
self.myTopPeer = myTopPeer
|
||||
self.minAmount = minAmount
|
||||
self.maxAmount = maxAmount
|
||||
self.completion = completion
|
||||
}
|
||||
|
|
@ -2647,20 +2656,26 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
|
|||
final class LiveStreamMessage {
|
||||
let peer: EnginePeer
|
||||
let myPeer: EnginePeer
|
||||
let minAmount: Int
|
||||
let maxAmount: Int
|
||||
let currentAmount: Int?
|
||||
let text: NSAttributedString
|
||||
let completion: (Int64, ChatSendStarsScreen.TransitionOut) -> Void
|
||||
|
||||
init(
|
||||
peer: EnginePeer,
|
||||
myPeer: EnginePeer,
|
||||
minAmount: Int,
|
||||
maxAmount: Int,
|
||||
currentAmount: Int?,
|
||||
text: NSAttributedString,
|
||||
completion: @escaping (Int64, ChatSendStarsScreen.TransitionOut) -> Void
|
||||
) {
|
||||
self.peer = peer
|
||||
self.myPeer = myPeer
|
||||
self.minAmount = minAmount
|
||||
self.maxAmount = maxAmount
|
||||
self.currentAmount = currentAmount
|
||||
self.text = text
|
||||
self.completion = completion
|
||||
}
|
||||
|
|
@ -2838,6 +2853,11 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
|
|||
maxAmount = Int(value)
|
||||
}
|
||||
|
||||
var minAmount = 1
|
||||
if case let .liveStream(_, _, minAmountValue) = reactSubject {
|
||||
minAmount = minAmountValue
|
||||
}
|
||||
|
||||
return combineLatest(
|
||||
context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId),
|
||||
|
|
@ -2911,6 +2931,7 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
|
|||
count: Int(topPeer.count)
|
||||
)
|
||||
},
|
||||
minAmount: minAmount,
|
||||
maxAmount: maxAmount,
|
||||
completion: completion
|
||||
)),
|
||||
|
|
@ -2923,6 +2944,8 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
|
|||
context: AccountContext,
|
||||
peerId: EnginePeer.Id,
|
||||
text: NSAttributedString,
|
||||
minAmount: Int,
|
||||
currentAmount: Int?,
|
||||
completion: @escaping (Int64, TransitionOut) -> Void
|
||||
) -> Signal<InitialData?, NoError> {
|
||||
let balance: Signal<StarsAmount?, NoError>
|
||||
|
|
@ -2958,7 +2981,9 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
|
|||
subjectInitialData: .liveStreamMessage(SubjectInitialData.LiveStreamMessage(
|
||||
peer: peer,
|
||||
myPeer: myPeer,
|
||||
minAmount: minAmount,
|
||||
maxAmount: maxAmount,
|
||||
currentAmount: currentAmount,
|
||||
text: text,
|
||||
completion: completion
|
||||
)),
|
||||
|
|
|
|||
|
|
@ -421,6 +421,32 @@ final class StoryContentLiveChatComponent: Component {
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
struct StarStats {
|
||||
var myStars: Int64
|
||||
var pendingMyStars: Int64
|
||||
var totalStars: Int64
|
||||
var topItems: [GroupCallMessagesContext.TopStarsItem]
|
||||
|
||||
init(myStars: Int64, pendingMyStars: Int64, totalStars: Int64, topItems: [GroupCallMessagesContext.TopStarsItem]) {
|
||||
self.myStars = myStars
|
||||
self.pendingMyStars = pendingMyStars
|
||||
self.totalStars = totalStars
|
||||
self.topItems = topItems
|
||||
}
|
||||
}
|
||||
|
||||
struct Info {
|
||||
var starStats: StarStats?
|
||||
var isChatEmpty: Bool
|
||||
var isChatExpanded: Bool
|
||||
|
||||
init(starStats: StarStats?, isChatEmpty: Bool, isChatExpanded: Bool) {
|
||||
self.starStats = starStats
|
||||
self.isChatEmpty = isChatEmpty
|
||||
self.isChatExpanded = isChatExpanded
|
||||
}
|
||||
}
|
||||
|
||||
final class View: UIView {
|
||||
private let listContainer: UIView
|
||||
|
|
@ -443,23 +469,26 @@ final class StoryContentLiveChatComponent: Component {
|
|||
private var currentListIsEmpty: Bool = true
|
||||
private var isMessageContextMenuOpen: Bool = false
|
||||
|
||||
public var isChatEmpty: Bool {
|
||||
guard let messagesState = self.messagesState else {
|
||||
return true
|
||||
}
|
||||
return messagesState.messages.isEmpty
|
||||
}
|
||||
private(set) var isChatExpanded: Bool = false
|
||||
private var isChatExpanded: Bool = false
|
||||
|
||||
public var starStars: (myStars: Int64, pendingMyStars: Int64, totalStars: Int64, topItems: [GroupCallMessagesContext.TopStarsItem])? {
|
||||
guard let messagesState = self.messagesState else {
|
||||
return nil
|
||||
public var currentInfo: Info {
|
||||
var starStats: StoryContentLiveChatComponent.StarStats?
|
||||
var isChatEmpty = true
|
||||
if let messagesState = self.messagesState {
|
||||
isChatEmpty = messagesState.messages.isEmpty
|
||||
|
||||
var myStars: Int64 = 0
|
||||
if let item = messagesState.topStars.first(where: { $0.isMy }) {
|
||||
myStars = item.amount
|
||||
}
|
||||
starStats = StoryContentLiveChatComponent.StarStats(myStars: myStars + messagesState.pendingMyStars, pendingMyStars: messagesState.pendingMyStars, totalStars: messagesState.totalStars + messagesState.pendingMyStars, topItems: messagesState.topStars)
|
||||
}
|
||||
var myStars: Int64 = 0
|
||||
if let item = messagesState.topStars.first(where: { $0.isMy }) {
|
||||
myStars = item.amount
|
||||
}
|
||||
return (myStars + messagesState.pendingMyStars, pendingMyStars: messagesState.pendingMyStars, messagesState.totalStars + messagesState.pendingMyStars, messagesState.topStars)
|
||||
|
||||
return Info(
|
||||
starStats: starStats,
|
||||
isChatEmpty: isChatEmpty,
|
||||
isChatExpanded: self.isChatExpanded
|
||||
)
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
|
|
@ -643,10 +672,8 @@ final class StoryContentLiveChatComponent: Component {
|
|||
|
||||
let state = await (component.call.state |> take(1)).get()
|
||||
|
||||
var isAdmin = state.canManageCall
|
||||
if component.storyPeerId == component.context.account.peerId {
|
||||
isAdmin = true
|
||||
}
|
||||
var isAdmin = false
|
||||
isAdmin = state.canManageCall
|
||||
var canDelete = isAdmin
|
||||
var isMyMessage = false
|
||||
guard let messagesState = self.messagesState, let message = messagesState.messages.first(where: { $0.id == id }) else {
|
||||
|
|
|
|||
|
|
@ -96,13 +96,43 @@ final class StoryItemContentComponent: Component {
|
|||
return true
|
||||
}
|
||||
|
||||
struct StarStats {
|
||||
var myStars: Int64
|
||||
var pendingMyStars: Int64
|
||||
var totalStars: Int64
|
||||
var topItems: [GroupCallMessagesContext.TopStarsItem]
|
||||
|
||||
init(myStars: Int64, pendingMyStars: Int64, totalStars: Int64, topItems: [GroupCallMessagesContext.TopStarsItem]) {
|
||||
self.myStars = myStars
|
||||
self.pendingMyStars = pendingMyStars
|
||||
self.totalStars = totalStars
|
||||
self.topItems = topItems
|
||||
}
|
||||
}
|
||||
|
||||
struct LiveChatState {
|
||||
var isExpanded: Bool
|
||||
var hasUnseenMessages: Bool
|
||||
var areMessagesEnabled: Bool
|
||||
var minMessagePrice: Int64?
|
||||
var starStats: StarStats?
|
||||
|
||||
init(isExpanded: Bool, hasUnseenMessages: Bool) {
|
||||
init(isExpanded: Bool, hasUnseenMessages: Bool, areMessagesEnabled: Bool, minMessagePrice: Int64?, starStats: StarStats?) {
|
||||
self.isExpanded = isExpanded
|
||||
self.hasUnseenMessages = hasUnseenMessages
|
||||
self.areMessagesEnabled = areMessagesEnabled
|
||||
self.minMessagePrice = minMessagePrice
|
||||
self.starStats = starStats
|
||||
}
|
||||
}
|
||||
|
||||
private struct MediaStreamCallState: Equatable {
|
||||
var areMessagesEnabled: Bool
|
||||
var minMessagePrice: Int64?
|
||||
|
||||
init(areMessagesEnabled: Bool, minMessagePrice: Int64?) {
|
||||
self.areMessagesEnabled = areMessagesEnabled
|
||||
self.minMessagePrice = minMessagePrice
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -111,7 +141,9 @@ final class StoryItemContentComponent: Component {
|
|||
private let overlaysView: StoryItemOverlaysView
|
||||
private var videoNode: UniversalVideoNode?
|
||||
private(set) var mediaStreamCall: PresentationGroupCallImpl?
|
||||
private var mediaStreamCallState: MediaStreamCallState?
|
||||
private var liveCallStateDisposable: Disposable?
|
||||
private var liveCallStatsDisposable: Disposable?
|
||||
private var mediaStream: ComponentView<Empty>?
|
||||
private var loadingEffectView: StoryItemLoadingEffectView?
|
||||
private var loadingEffectAppearanceTimer: SwiftSignalKit.Timer?
|
||||
|
|
@ -160,22 +192,28 @@ final class StoryItemContentComponent: Component {
|
|||
guard let liveChatView = self.liveChat?.view as? StoryContentLiveChatComponent.View else {
|
||||
return nil
|
||||
}
|
||||
if liveChatView.isChatEmpty {
|
||||
return nil
|
||||
|
||||
let currentInfo = liveChatView.currentInfo
|
||||
let mediaStreamCallState = self.mediaStreamCallState
|
||||
|
||||
let starStats = currentInfo.starStats.flatMap { starStats in
|
||||
return StarStats(
|
||||
myStars: starStats.myStars,
|
||||
pendingMyStars: starStats.pendingMyStars,
|
||||
totalStars: starStats.totalStars,
|
||||
topItems: starStats.topItems
|
||||
)
|
||||
}
|
||||
|
||||
return LiveChatState(
|
||||
isExpanded: liveChatView.isChatExpanded,
|
||||
hasUnseenMessages: self.liveChatExternal.hasUnseenMessages
|
||||
isExpanded: currentInfo.isChatExpanded,
|
||||
hasUnseenMessages: self.liveChatExternal.hasUnseenMessages,
|
||||
areMessagesEnabled: mediaStreamCallState?.areMessagesEnabled ?? false,
|
||||
minMessagePrice: mediaStreamCallState?.minMessagePrice,
|
||||
starStats: starStats
|
||||
)
|
||||
}
|
||||
|
||||
public var starStars: (myStars: Int64, pendingMyStars: Int64, totalStars: Int64, topItems: [GroupCallMessagesContext.TopStarsItem])? {
|
||||
guard let liveChatView = self.liveChat?.view as? StoryContentLiveChatComponent.View else {
|
||||
return nil
|
||||
}
|
||||
return liveChatView.starStars
|
||||
}
|
||||
|
||||
public func toggleLiveChatExpanded() {
|
||||
guard let liveChatView = self.liveChat?.view as? StoryContentLiveChatComponent.View else {
|
||||
return
|
||||
|
|
@ -227,6 +265,7 @@ final class StoryItemContentComponent: Component {
|
|||
self.videoProgressDisposable?.dispose()
|
||||
self.currentFetchPriority?.disposable.dispose()
|
||||
self.liveCallStateDisposable?.dispose()
|
||||
self.liveCallStatsDisposable?.dispose()
|
||||
}
|
||||
|
||||
func allowsInstantPauseOnTouch(point: CGPoint) -> Bool {
|
||||
|
|
@ -1015,7 +1054,27 @@ final class StoryItemContentComponent: Component {
|
|||
|
||||
if let mediaStreamCall = self.mediaStreamCall {
|
||||
if self.liveCallStateDisposable == nil {
|
||||
self.liveCallStateDisposable = (mediaStreamCall.members
|
||||
self.liveCallStateDisposable = (mediaStreamCall.state
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] state in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
let mappedState = MediaStreamCallState(
|
||||
areMessagesEnabled: state.messagesAreEnabled,
|
||||
minMessagePrice: state.sendPaidMessageStars
|
||||
)
|
||||
if self.mediaStreamCallState != mappedState {
|
||||
self.mediaStreamCallState = mappedState
|
||||
if !self.isUpdating {
|
||||
self.state?.updated(transition: .spring(duration: 0.4))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if self.liveCallStatsDisposable == nil {
|
||||
self.liveCallStatsDisposable = (mediaStreamCall.members
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self] members in
|
||||
guard let self, let environment = self.environment else {
|
||||
return
|
||||
|
|
@ -1033,9 +1092,15 @@ final class StoryItemContentComponent: Component {
|
|||
}
|
||||
})
|
||||
}
|
||||
} else if let liveCallStateDisposable = self.liveCallStateDisposable {
|
||||
self.liveCallStateDisposable = nil
|
||||
liveCallStateDisposable.dispose()
|
||||
} else {
|
||||
if let liveCallStateDisposable = self.liveCallStateDisposable {
|
||||
self.liveCallStateDisposable = nil
|
||||
liveCallStateDisposable.dispose()
|
||||
}
|
||||
if let liveCallStatsDisposable = self.liveCallStatsDisposable {
|
||||
self.liveCallStatsDisposable = nil
|
||||
liveCallStatsDisposable.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
switch selectedMedia {
|
||||
|
|
|
|||
|
|
@ -2971,18 +2971,28 @@ public final class StoryItemSetContainerComponent: Component {
|
|||
|
||||
var liveChatState: MessageInputPanelComponent.LiveChatState?
|
||||
var starStats: MessageInputPanelComponent.StarStats?
|
||||
var sendPaidMessageStars = isLiveStream ? self.sendMessageContext.currentLiveStreamMessageStars : component.slice.additionalPeerData.sendPaidMessageStars
|
||||
if let visibleItemView = self.visibleItems[component.slice.item.id]?.view.view as? StoryItemContentComponent.View {
|
||||
liveChatState = visibleItemView.liveChatState.flatMap { liveChatState in
|
||||
return MessageInputPanelComponent.LiveChatState(
|
||||
isExpanded: liveChatState.isExpanded,
|
||||
hasUnseenMessages: liveChatState.hasUnseenMessages
|
||||
)
|
||||
}
|
||||
starStats = visibleItemView.starStars.flatMap { starStats in
|
||||
return MessageInputPanelComponent.StarStats(
|
||||
myStars: starStats.myStars,
|
||||
totalStars: starStats.totalStars
|
||||
if let liveChatStateValue = visibleItemView.liveChatState {
|
||||
liveChatState = MessageInputPanelComponent.LiveChatState(
|
||||
isExpanded: liveChatStateValue.isExpanded,
|
||||
hasUnseenMessages: liveChatStateValue.hasUnseenMessages
|
||||
)
|
||||
starStats = liveChatStateValue.starStats.flatMap { starStats in
|
||||
return MessageInputPanelComponent.StarStats(
|
||||
myStars: starStats.myStars,
|
||||
totalStars: starStats.totalStars
|
||||
)
|
||||
}
|
||||
if let minMessagePrice = liveChatStateValue.minMessagePrice {
|
||||
if let current = sendPaidMessageStars {
|
||||
if current < StarsAmount(value: minMessagePrice, nanos: 0) {
|
||||
sendPaidMessageStars = StarsAmount(value: minMessagePrice, nanos: 0)
|
||||
}
|
||||
} else {
|
||||
sendPaidMessageStars = StarsAmount(value: minMessagePrice, nanos: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2995,7 +3005,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||
strings: component.strings,
|
||||
style: .story,
|
||||
placeholder: inputPlaceholder,
|
||||
sendPaidMessageStars: isLiveStream ? self.sendMessageContext.currentLiveStreamMessageStars : component.slice.additionalPeerData.sendPaidMessageStars,
|
||||
sendPaidMessageStars: sendPaidMessageStars,
|
||||
maxLength: maxInputLength,
|
||||
maxEmojiCount: maxEmojiCount,
|
||||
queryTypes: [.mention, .hashtag, .emoji],
|
||||
|
|
|
|||
|
|
@ -1335,10 +1335,21 @@ final class StoryItemSetContainerSendMessage {
|
|||
inputText = text
|
||||
}
|
||||
|
||||
guard let visibleItemView = view.visibleItems[component.slice.item.id]?.view.view as? StoryItemContentComponent.View else {
|
||||
return
|
||||
}
|
||||
|
||||
var minAmount: Int64 = 1
|
||||
if let minMessagePrice = visibleItemView.liveChatState?.minMessagePrice {
|
||||
minAmount = minMessagePrice
|
||||
}
|
||||
|
||||
let initialData = await ChatSendStarsScreen.initialDataLiveStreamMessage(
|
||||
context: component.context,
|
||||
peerId: peerId,
|
||||
text: inputText,
|
||||
minAmount: Int(minAmount),
|
||||
currentAmount: (self.currentLiveStreamMessageStars?.value).flatMap { Int($0) },
|
||||
completion: { [weak self, weak view] amount, _ in
|
||||
guard let self, let view else {
|
||||
return
|
||||
|
|
@ -3893,8 +3904,9 @@ final class StoryItemSetContainerSendMessage {
|
|||
}
|
||||
|
||||
var topPeers: [ReactionsMessageAttribute.TopPeer] = []
|
||||
var minAmount: Int64 = 1
|
||||
if let visibleItemView = view.visibleItems[component.slice.item.id]?.view.view as? StoryItemContentComponent.View {
|
||||
if let topItems = visibleItemView.starStars?.topItems {
|
||||
if let topItems = visibleItemView.liveChatState?.starStats?.topItems {
|
||||
topPeers = topItems.map { item -> ReactionsMessageAttribute.TopPeer in
|
||||
return ReactionsMessageAttribute.TopPeer(
|
||||
peerId: item.peerId,
|
||||
|
|
@ -3905,12 +3917,16 @@ final class StoryItemSetContainerSendMessage {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
if let minMessagePrice = visibleItemView.liveChatState?.minMessagePrice {
|
||||
minAmount = minMessagePrice
|
||||
}
|
||||
}
|
||||
|
||||
let initialData = await ChatSendStarsScreen.initialData(
|
||||
context: component.context,
|
||||
peerId: peerId,
|
||||
reactSubject: .liveStream(peerId: peerId, storyId: focusedItem.storyItem.id),
|
||||
reactSubject: .liveStream(peerId: peerId, storyId: focusedItem.storyItem.id, minAmount: Int(minAmount)),
|
||||
topPeers: topPeers,
|
||||
completion: { [weak view] amount, privacy, isBecomingTop, transitionOut in
|
||||
guard let view, let component = view.component else {
|
||||
|
|
@ -4024,7 +4040,7 @@ final class StoryItemSetContainerSendMessage {
|
|||
|
||||
var totalStars = count
|
||||
if let visibleItemView = view.visibleItems[component.slice.item.id]?.view.view as? StoryItemContentComponent.View {
|
||||
if let pendingMyStars = visibleItemView.starStars?.pendingMyStars {
|
||||
if let pendingMyStars = visibleItemView.liveChatState?.starStats?.pendingMyStars {
|
||||
totalStars += Int(pendingMyStars)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue