mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Stories
This commit is contained in:
@@ -240,6 +240,7 @@ public struct PresentationGroupCallState: Equatable {
|
||||
public var isVideoWatchersLimitReached: Bool
|
||||
public var isMyVideoActive: Bool
|
||||
public var isUnifiedStream: Bool
|
||||
public var defaultSendAs: EnginePeer.Id?
|
||||
|
||||
public init(
|
||||
myPeerId: EnginePeer.Id,
|
||||
@@ -260,7 +261,8 @@ public struct PresentationGroupCallState: Equatable {
|
||||
isVideoEnabled: Bool,
|
||||
isVideoWatchersLimitReached: Bool,
|
||||
isMyVideoActive: Bool,
|
||||
isUnifiedStream: Bool
|
||||
isUnifiedStream: Bool,
|
||||
defaultSendAs: EnginePeer.Id?
|
||||
) {
|
||||
self.myPeerId = myPeerId
|
||||
self.networkState = networkState
|
||||
@@ -281,6 +283,7 @@ public struct PresentationGroupCallState: Equatable {
|
||||
self.isVideoWatchersLimitReached = isVideoWatchersLimitReached
|
||||
self.isMyVideoActive = isMyVideoActive
|
||||
self.isUnifiedStream = isUnifiedStream
|
||||
self.defaultSendAs = defaultSendAs
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,8 @@ private extension PresentationGroupCallState {
|
||||
isVideoEnabled: false,
|
||||
isVideoWatchersLimitReached: false,
|
||||
isMyVideoActive: false,
|
||||
isUnifiedStream: false
|
||||
isUnifiedStream: false,
|
||||
defaultSendAs: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1565,6 +1566,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
isVideoEnabled: callInfo.isVideoEnabled,
|
||||
unmutedVideoLimit: callInfo.unmutedVideoLimit,
|
||||
isStream: callInfo.isStream,
|
||||
sendPaidMessagesStars: self.stateValue.sendPaidMessageStars,
|
||||
defaultSendAs: self.stateValue.defaultSendAs,
|
||||
version: 0
|
||||
),
|
||||
previousServiceState: nil,
|
||||
@@ -2282,19 +2285,23 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
if case let .established(callInfo, _, _, _, initialState) = internalState {
|
||||
self.summaryInfoState.set(.single(SummaryInfoState(info: callInfo)))
|
||||
|
||||
self.stateValue.canManageCall = initialState.isCreator || initialState.adminIds.contains(self.accountContext.account.peerId)
|
||||
if self.stateValue.canManageCall && initialState.defaultParticipantsAreMuted.canChange {
|
||||
self.stateValue.defaultParticipantMuteState = initialState.defaultParticipantsAreMuted.isMuted ? .muted : .unmuted
|
||||
var stateValue = self.stateValue
|
||||
|
||||
stateValue.canManageCall = initialState.isCreator || initialState.adminIds.contains(self.accountContext.account.peerId)
|
||||
if stateValue.canManageCall && initialState.defaultParticipantsAreMuted.canChange {
|
||||
stateValue.defaultParticipantMuteState = initialState.defaultParticipantsAreMuted.isMuted ? .muted : .unmuted
|
||||
}
|
||||
if self.stateValue.recordingStartTimestamp != initialState.recordingStartTimestamp {
|
||||
self.stateValue.recordingStartTimestamp = initialState.recordingStartTimestamp
|
||||
if stateValue.recordingStartTimestamp != initialState.recordingStartTimestamp {
|
||||
stateValue.recordingStartTimestamp = initialState.recordingStartTimestamp
|
||||
}
|
||||
if self.stateValue.title != initialState.title {
|
||||
self.stateValue.title = initialState.title
|
||||
if stateValue.title != initialState.title {
|
||||
stateValue.title = initialState.title
|
||||
}
|
||||
if self.stateValue.scheduleTimestamp != initialState.scheduleTimestamp {
|
||||
self.stateValue.scheduleTimestamp = initialState.scheduleTimestamp
|
||||
if stateValue.scheduleTimestamp != initialState.scheduleTimestamp {
|
||||
stateValue.scheduleTimestamp = initialState.scheduleTimestamp
|
||||
}
|
||||
stateValue.defaultSendAs = initialState.defaultSendAs
|
||||
self.stateValue = stateValue
|
||||
|
||||
let accountContext = self.accountContext
|
||||
let peerId = self.peerId
|
||||
@@ -2667,21 +2674,24 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
|
||||
self.membersValue = members
|
||||
|
||||
self.stateValue.adminIds = adminIds
|
||||
var stateValue = self.stateValue
|
||||
stateValue.adminIds = adminIds
|
||||
|
||||
self.stateValue.canManageCall = state.isCreator || adminIds.contains(self.accountContext.account.peerId)
|
||||
if (state.isCreator || self.stateValue.adminIds.contains(self.accountContext.account.peerId)) && state.defaultParticipantsAreMuted.canChange {
|
||||
self.stateValue.defaultParticipantMuteState = state.defaultParticipantsAreMuted.isMuted ? .muted : .unmuted
|
||||
stateValue.canManageCall = state.isCreator || adminIds.contains(self.accountContext.account.peerId)
|
||||
if (state.isCreator || stateValue.adminIds.contains(self.accountContext.account.peerId)) && state.defaultParticipantsAreMuted.canChange {
|
||||
stateValue.defaultParticipantMuteState = state.defaultParticipantsAreMuted.isMuted ? .muted : .unmuted
|
||||
}
|
||||
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
|
||||
self.stateValue.isVideoEnabled = state.isVideoEnabled && otherParticipantsWithVideo < state.unmutedVideoLimit
|
||||
self.stateValue.isVideoWatchersLimitReached = videoWatchingParticipants >= configuration.videoParticipantsMaxCount
|
||||
self.stateValue.isUnifiedStream = state.isStream
|
||||
stateValue.messagesAreEnabled = state.messagesAreEnabled.isEnabled
|
||||
stateValue.canEnableMessages = state.messagesAreEnabled.canChange
|
||||
stateValue.sendPaidMessageStars = state.messagesAreEnabled.sendPaidMessagesStars
|
||||
stateValue.recordingStartTimestamp = state.recordingStartTimestamp
|
||||
stateValue.title = state.title
|
||||
stateValue.scheduleTimestamp = state.scheduleTimestamp
|
||||
stateValue.isVideoEnabled = state.isVideoEnabled && otherParticipantsWithVideo < state.unmutedVideoLimit
|
||||
stateValue.isVideoWatchersLimitReached = videoWatchingParticipants >= configuration.videoParticipantsMaxCount
|
||||
stateValue.isUnifiedStream = state.isStream
|
||||
stateValue.defaultSendAs = state.defaultSendAs
|
||||
self.stateValue = stateValue
|
||||
|
||||
self.summaryInfoState.set(.single(SummaryInfoState(info: GroupCallInfo(
|
||||
id: callInfo.id,
|
||||
|
||||
@@ -1220,7 +1220,8 @@ final class VideoChatScreenComponent: Component {
|
||||
isVideoEnabled: true,
|
||||
isVideoWatchersLimitReached: false,
|
||||
isMyVideoActive: false,
|
||||
isUnifiedStream: false
|
||||
isUnifiedStream: false,
|
||||
defaultSendAs: nil
|
||||
)
|
||||
|
||||
return .single((callState, invitedPeers.compactMap({ peer -> VideoChatScreenComponent.InvitedPeer? in
|
||||
|
||||
@@ -595,6 +595,8 @@ func _internal_getGroupCallParticipants(account: Account, reference: InternalGro
|
||||
isVideoEnabled: isVideoEnabled,
|
||||
unmutedVideoLimit: unmutedVideoLimit,
|
||||
isStream: isStream,
|
||||
sendPaidMessagesStars: nil,
|
||||
defaultSendAs: nil,
|
||||
version: version
|
||||
)
|
||||
}
|
||||
@@ -1479,6 +1481,8 @@ public final class GroupCallParticipantsContext {
|
||||
isVideoEnabled: Bool,
|
||||
unmutedVideoLimit: Int,
|
||||
isStream: Bool,
|
||||
sendPaidMessagesStars: Int64?,
|
||||
defaultSendAs: PeerId?,
|
||||
version: Int32
|
||||
) {
|
||||
self.participants = participants
|
||||
@@ -1496,6 +1500,8 @@ public final class GroupCallParticipantsContext {
|
||||
self.isVideoEnabled = isVideoEnabled
|
||||
self.unmutedVideoLimit = unmutedVideoLimit
|
||||
self.isStream = isStream
|
||||
self.sendPaidMessagesStars = sendPaidMessagesStars
|
||||
self.defaultSendAs = defaultSendAs
|
||||
self.version = version
|
||||
}
|
||||
}
|
||||
@@ -1871,6 +1877,8 @@ public final class GroupCallParticipantsContext {
|
||||
isVideoEnabled: strongSelf.stateValue.state.isVideoEnabled,
|
||||
unmutedVideoLimit: strongSelf.stateValue.state.unmutedVideoLimit,
|
||||
isStream: strongSelf.stateValue.state.isStream,
|
||||
sendPaidMessagesStars: strongSelf.stateValue.state.sendPaidMessagesStars,
|
||||
defaultSendAs: strongSelf.stateValue.state.defaultSendAs,
|
||||
version: strongSelf.stateValue.state.version
|
||||
),
|
||||
overlayState: strongSelf.stateValue.overlayState,
|
||||
@@ -2102,6 +2110,8 @@ public final class GroupCallParticipantsContext {
|
||||
isVideoEnabled: strongSelf.stateValue.state.isVideoEnabled,
|
||||
unmutedVideoLimit: strongSelf.stateValue.state.unmutedVideoLimit,
|
||||
isStream: strongSelf.stateValue.state.isStream,
|
||||
sendPaidMessagesStars: strongSelf.stateValue.state.sendPaidMessagesStars,
|
||||
defaultSendAs: strongSelf.stateValue.state.defaultSendAs,
|
||||
version: strongSelf.stateValue.state.version
|
||||
),
|
||||
overlayState: strongSelf.stateValue.overlayState,
|
||||
@@ -2328,6 +2338,8 @@ public final class GroupCallParticipantsContext {
|
||||
let isVideoEnabled = strongSelf.stateValue.state.isVideoEnabled
|
||||
let isStream = strongSelf.stateValue.state.isStream
|
||||
let unmutedVideoLimit = strongSelf.stateValue.state.unmutedVideoLimit
|
||||
let sendPaidMessagesStars = strongSelf.stateValue.state.sendPaidMessagesStars
|
||||
let defaultSendAs = strongSelf.stateValue.state.defaultSendAs
|
||||
|
||||
updatedParticipants.sort(by: { GroupCallParticipantsContext.Participant.compare(lhs: $0, rhs: $1, sortAscending: strongSelf.stateValue.state.sortAscending) })
|
||||
|
||||
@@ -2348,6 +2360,8 @@ public final class GroupCallParticipantsContext {
|
||||
isVideoEnabled: isVideoEnabled,
|
||||
unmutedVideoLimit: unmutedVideoLimit,
|
||||
isStream: isStream,
|
||||
sendPaidMessagesStars: sendPaidMessagesStars,
|
||||
defaultSendAs: defaultSendAs,
|
||||
version: update.version
|
||||
),
|
||||
overlayState: updatedOverlayState,
|
||||
@@ -4300,7 +4314,7 @@ public final class GroupCallMessagesContext {
|
||||
flags |= 1 << 0
|
||||
}
|
||||
var sendAs: Api.InputPeer?
|
||||
if fromId != self.account.peerId {
|
||||
if fromId != self.account.peerId || self.isLiveStream {
|
||||
guard let fromPeer else {
|
||||
return
|
||||
}
|
||||
@@ -4364,7 +4378,7 @@ public final class GroupCallMessagesContext {
|
||||
var flags: Int32 = 0
|
||||
flags |= 1 << 0
|
||||
var sendAs: Api.InputPeer?
|
||||
if pendingSendStars.fromPeer.id != self.account.peerId {
|
||||
if pendingSendStars.fromPeer.id != self.account.peerId || self.isLiveStream {
|
||||
sendAs = apiInputPeer(pendingSendStars.fromPeer)
|
||||
}
|
||||
if sendAs != nil {
|
||||
|
||||
@@ -1531,10 +1531,11 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
||||
shouldDisplayMenuButton = true
|
||||
}
|
||||
|
||||
var displaySendAsAvatarButton = false
|
||||
let mediaRecordingState = interfaceState.inputTextPanelState.mediaRecordingState
|
||||
if let sendAsPeers = interfaceState.sendAsPeers, !sendAsPeers.isEmpty && interfaceState.editMessageState == nil {
|
||||
menuButtonExpanded = false
|
||||
self.sendAsAvatarButtonNode.isHidden = false
|
||||
displaySendAsAvatarButton = true
|
||||
|
||||
var currentPeer = sendAsPeers.first(where: { $0.peer.id == interfaceState.currentSendAsPeerId})?.peer
|
||||
if currentPeer == nil {
|
||||
@@ -1554,9 +1555,6 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
||||
break
|
||||
}
|
||||
}
|
||||
self.sendAsAvatarButtonNode.isHidden = true
|
||||
} else {
|
||||
self.sendAsAvatarButtonNode.isHidden = true
|
||||
}
|
||||
if mediaRecordingState != nil || interfaceState.interfaceState.mediaDraftState != nil {
|
||||
hasMenuButton = false
|
||||
@@ -2968,11 +2966,13 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
|
||||
}
|
||||
transition.updateFrame(node: self.textPlaceholderNode, frame: textPlaceholderFrame)
|
||||
|
||||
|
||||
let sendAsButtonFrame = CGRect(origin: CGPoint(x: 3.0, y: textInputContainerBackgroundFrame.height - 3.0 - 34.0), size: CGSize(width: 34.0, height: 34.0))
|
||||
let sendAsAvatarButtonAlpha: CGFloat = audioRecordingItemsAlpha * (displaySendAsAvatarButton ? 1.0 : 0.0)
|
||||
transition.updatePosition(node: self.sendAsAvatarButtonNode, position: sendAsButtonFrame.center)
|
||||
transition.updateBounds(node: self.sendAsAvatarButtonNode, bounds: CGRect(origin: CGPoint(), size: sendAsButtonFrame.size))
|
||||
transition.updateAlpha(layer: self.sendAsAvatarButtonNode.layer, alpha: audioRecordingItemsAlpha)
|
||||
transition.updateTransformScale(layer: self.sendAsAvatarButtonNode.layer, scale: audioRecordingItemsAlpha == 0.0 ? 0.001 : 1.0)
|
||||
transition.updateAlpha(layer: self.sendAsAvatarButtonNode.layer, alpha: sendAsAvatarButtonAlpha)
|
||||
transition.updateTransformScale(layer: self.sendAsAvatarButtonNode.layer, scale: sendAsAvatarButtonAlpha == 0.0 ? 0.001 : 1.0)
|
||||
transition.updateFrame(node: self.sendAsAvatarContainerNode, frame: CGRect(origin: CGPoint(), size: sendAsButtonFrame.size))
|
||||
transition.updateFrame(node: self.sendAsAvatarReferenceNode, frame: CGRect(origin: CGPoint(), size: sendAsButtonFrame.size))
|
||||
transition.updatePosition(node: self.sendAsAvatarNode, position: CGRect(origin: CGPoint(), size: sendAsButtonFrame.size).center)
|
||||
|
||||
@@ -118,8 +118,9 @@ final class StoryItemContentComponent: Component {
|
||||
var minMessagePrice: Int64?
|
||||
var starStats: StarStats?
|
||||
var isAdmin: Bool
|
||||
var defaultSendAs: EnginePeer.Id?
|
||||
|
||||
init(isExpanded: Bool, isEmpty: Bool, hasUnseenMessages: Bool, areMessagesEnabled: Bool, minMessagePrice: Int64?, starStats: StarStats?, isAdmin: Bool) {
|
||||
init(isExpanded: Bool, isEmpty: Bool, hasUnseenMessages: Bool, areMessagesEnabled: Bool, minMessagePrice: Int64?, starStats: StarStats?, isAdmin: Bool, defaultSendAs: EnginePeer.Id?) {
|
||||
self.isExpanded = isExpanded
|
||||
self.isEmpty = isEmpty
|
||||
self.hasUnseenMessages = hasUnseenMessages
|
||||
@@ -127,6 +128,7 @@ final class StoryItemContentComponent: Component {
|
||||
self.minMessagePrice = minMessagePrice
|
||||
self.starStats = starStats
|
||||
self.isAdmin = isAdmin
|
||||
self.defaultSendAs = defaultSendAs
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,12 +136,14 @@ final class StoryItemContentComponent: Component {
|
||||
var areMessagesEnabled: Bool
|
||||
var minMessagePrice: Int64?
|
||||
var isAdmin: Bool
|
||||
var defaultSendAs: EnginePeer.Id?
|
||||
var isUnifiedStream: Bool
|
||||
|
||||
init(areMessagesEnabled: Bool, minMessagePrice: Int64?, isAdmin: Bool, isUnifiedStream: Bool) {
|
||||
init(areMessagesEnabled: Bool, minMessagePrice: Int64?, isAdmin: Bool, defaultSendAs: EnginePeer.Id?, isUnifiedStream: Bool) {
|
||||
self.areMessagesEnabled = areMessagesEnabled
|
||||
self.minMessagePrice = minMessagePrice
|
||||
self.isAdmin = isAdmin
|
||||
self.defaultSendAs = defaultSendAs
|
||||
self.isUnifiedStream = isUnifiedStream
|
||||
}
|
||||
}
|
||||
@@ -229,7 +233,8 @@ final class StoryItemContentComponent: Component {
|
||||
areMessagesEnabled: mediaStreamCallState?.areMessagesEnabled ?? false,
|
||||
minMessagePrice: mediaStreamCallState?.minMessagePrice,
|
||||
starStats: starStats,
|
||||
isAdmin: mediaStreamCallState?.isAdmin ?? false
|
||||
isAdmin: mediaStreamCallState?.isAdmin ?? false,
|
||||
defaultSendAs: mediaStreamCallState?.defaultSendAs
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1116,6 +1121,7 @@ final class StoryItemContentComponent: Component {
|
||||
areMessagesEnabled: state.messagesAreEnabled,
|
||||
minMessagePrice: state.sendPaidMessageStars,
|
||||
isAdmin: state.canManageCall,
|
||||
defaultSendAs: state.defaultSendAs,
|
||||
isUnifiedStream: state.isUnifiedStream
|
||||
)
|
||||
if self.mediaStreamCallState != mappedState {
|
||||
|
||||
@@ -103,7 +103,9 @@ final class StoryItemLoadingEffectView: UIView {
|
||||
}
|
||||
|
||||
func update(size: CGSize, transition: ComponentTransition) {
|
||||
if self.backgroundView.bounds.size != size {
|
||||
let backgroundSize = CGSize(width: self.gradientWidth, height: size.height)
|
||||
|
||||
if self.backgroundView.bounds.size != backgroundSize {
|
||||
self.backgroundView.layer.removeAllAnimations()
|
||||
|
||||
if !self.hasCustomBorder {
|
||||
@@ -115,7 +117,7 @@ final class StoryItemLoadingEffectView: UIView {
|
||||
}
|
||||
}
|
||||
|
||||
transition.setFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(x: -self.gradientWidth, y: 0.0), size: CGSize(width: self.gradientWidth, height: size.height)))
|
||||
transition.setFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(x: -self.gradientWidth, y: 0.0), size: backgroundSize))
|
||||
|
||||
transition.setFrame(view: self.borderContainerView, frame: CGRect(origin: CGPoint(), size: size))
|
||||
transition.setFrame(view: self.borderGradientView, frame: CGRect(origin: CGPoint(x: -self.gradientWidth, y: 0.0), size: CGSize(width: self.gradientWidth, height: size.height)))
|
||||
|
||||
@@ -3004,7 +3004,16 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
sendAsConfiguration = self.sendMessageContext.currentSendAsPeer.flatMap { value in
|
||||
var sendAsPeer: SendAsPeer?
|
||||
if let currentSendAsPeer = self.sendMessageContext.currentSendAsPeer {
|
||||
sendAsPeer = currentSendAsPeer
|
||||
} else {
|
||||
sendAsPeer = liveChatStateValue.defaultSendAs.flatMap { defaultSendAs in
|
||||
return self.sendMessageContext.sendAsData?.availablePeers.first(where: { $0.peer.id == defaultSendAs })
|
||||
}
|
||||
}
|
||||
|
||||
sendAsConfiguration = sendAsPeer.flatMap { value in
|
||||
return MessageInputPanelComponent.SendAsConfiguration(
|
||||
currentPeer: EnginePeer(value.peer),
|
||||
subscriberCount: value.subscribers.flatMap(Int.init),
|
||||
@@ -6307,8 +6316,14 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
return .complete()
|
||||
}
|
||||
|
||||
var isLiveStream = false
|
||||
if case .liveStream = component.slice.item.storyItem.media {
|
||||
isLiveStream = true
|
||||
}
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
if !isLiveStream {
|
||||
items.append(.action(ContextMenuActionItem(text: component.strings.Stories_MenuAddToAlbum, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddToFolder"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
|
||||
guard let self, let c else {
|
||||
f(.default)
|
||||
@@ -6403,6 +6418,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
c.pushItems(items: .single(ContextController.Items(content: .list(items))))
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
||||
if case .file = component.slice.item.storyItem.media {
|
||||
var speedValue: String = presentationData.strings.PlaybackSpeed_Normal
|
||||
@@ -6466,6 +6482,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
self.openItemPrivacySettings()
|
||||
})))
|
||||
|
||||
if !isLiveStream {
|
||||
items.append(.action(ContextMenuActionItem(text: component.strings.Story_Context_Edit, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, a in
|
||||
@@ -6553,6 +6570,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
}
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
if component.slice.item.storyItem.isPublic && (component.slice.effectivePeer.addressName != nil || !component.slice.effectivePeer._asPeer().usernames.isEmpty) && (component.slice.item.storyItem.expirationTimestamp > Int32(Date().timeIntervalSince1970) || component.slice.item.storyItem.isPinned) {
|
||||
items.append(.action(ContextMenuActionItem(text: component.strings.Story_Context_CopyLink, icon: { theme in
|
||||
@@ -6645,6 +6663,11 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
return .complete()
|
||||
}
|
||||
|
||||
var isLiveStream = false
|
||||
if case .liveStream = component.slice.item.storyItem.media {
|
||||
isLiveStream = true
|
||||
}
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
if case .file = component.slice.item.storyItem.media {
|
||||
var speedValue: String = presentationData.strings.PlaybackSpeed_Normal
|
||||
@@ -6676,7 +6699,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
items.append(.separator)
|
||||
}
|
||||
|
||||
if (component.slice.item.storyItem.isMy && channel.hasPermission(.postStories)) || channel.hasPermission(.editStories) {
|
||||
if !isLiveStream && ((component.slice.item.storyItem.isMy && channel.hasPermission(.postStories)) || channel.hasPermission(.editStories)) {
|
||||
items.append(.action(ContextMenuActionItem(text: component.strings.Story_Context_Edit, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, a in
|
||||
@@ -6706,7 +6729,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
items.append(.separator)
|
||||
}
|
||||
|
||||
if channel.hasPermission(.editStories) {
|
||||
if !isLiveStream && channel.hasPermission(.editStories) {
|
||||
items.append(.action(ContextMenuActionItem(text: component.slice.item.storyItem.isPinned ? component.strings.Story_Context_RemoveFromChannel : component.strings.Story_Context_SaveToChannel, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: component.slice.item.storyItem.isPinned ? "Stories/Context Menu/Unpin" : "Stories/Context Menu/Pin"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, a in
|
||||
@@ -6746,7 +6769,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
})))
|
||||
}
|
||||
|
||||
if component.slice.additionalPeerData.canViewStats {
|
||||
if !isLiveStream && component.slice.additionalPeerData.canViewStats {
|
||||
items.append(.action(ContextMenuActionItem(text: component.strings.Story_Context_ViewStats, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Statistics"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, a in
|
||||
@@ -6768,6 +6791,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
})))
|
||||
}
|
||||
|
||||
if !isLiveStream {
|
||||
let saveText: String = component.strings.Story_Context_SaveToGallery
|
||||
items.append(.action(ContextMenuActionItem(text: saveText, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Save"), color: theme.contextMenu.primaryColor)
|
||||
@@ -6779,6 +6803,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
}
|
||||
self.requestSave()
|
||||
})))
|
||||
}
|
||||
|
||||
if component.slice.item.storyItem.isPublic && (component.slice.effectivePeer.addressName != nil || !component.slice.effectivePeer._asPeer().usernames.isEmpty) && (component.slice.item.storyItem.expirationTimestamp > Int32(Date().timeIntervalSince1970) || component.slice.item.storyItem.isPinned) {
|
||||
items.append(.action(ContextMenuActionItem(text: component.strings.Story_Context_CopyLink, icon: { theme in
|
||||
|
||||
@@ -107,7 +107,17 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) {
|
||||
var currentLiveStreamStarsIsActive: Bool = false
|
||||
var currentLiveStreamStarsIsActiveTimer: Foundation.Timer?
|
||||
|
||||
var sendAsData: (isPremium: Bool, availablePeers: [SendAsPeer])?
|
||||
struct SendAsData: Equatable {
|
||||
var isPremium: Bool
|
||||
var availablePeers: [SendAsPeer]
|
||||
|
||||
init(isPremium: Bool, availablePeers: [SendAsPeer]) {
|
||||
self.isPremium = isPremium
|
||||
self.availablePeers = availablePeers
|
||||
}
|
||||
}
|
||||
|
||||
var sendAsData: SendAsData?
|
||||
var currentSendAsPeer: SendAsPeer?
|
||||
var isSelectingSendAsPeer: Bool = false
|
||||
var sendAsDisposable: Disposable?
|
||||
@@ -244,26 +254,16 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) {
|
||||
availablePeers.append(peer)
|
||||
}
|
||||
|
||||
self.sendAsData = (
|
||||
let sendAsData = SendAsData(
|
||||
isPremium: isPremium,
|
||||
availablePeers: availablePeers
|
||||
)
|
||||
|
||||
if availablePeers.count > 1 {
|
||||
if self.currentSendAsPeer == nil {
|
||||
self.currentSendAsPeer = availablePeers.first
|
||||
if self.sendAsData != sendAsData {
|
||||
self.sendAsData = sendAsData
|
||||
if !view.isUpdatingComponent {
|
||||
view.state?.updated(transition: .spring(duration: 0.4))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if self.currentSendAsPeer != nil {
|
||||
self.currentSendAsPeer = nil
|
||||
if !view.isUpdatingComponent {
|
||||
view.state?.updated(transition: .spring(duration: 0.4))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -684,6 +684,7 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) {
|
||||
|
||||
var sendPaidMessageStars = self.currentLiveStreamMessageStars
|
||||
var isAdmin = false
|
||||
var sendAsPeer: SendAsPeer?
|
||||
if let visibleItemView = view.visibleItems[component.slice.item.id]?.view.view as? StoryItemContentComponent.View {
|
||||
if let liveChatStateValue = visibleItemView.liveChatState {
|
||||
if let minMessagePrice = liveChatStateValue.minMessagePrice {
|
||||
@@ -696,6 +697,14 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) {
|
||||
}
|
||||
}
|
||||
isAdmin = liveChatStateValue.isAdmin
|
||||
|
||||
if let currentSendAsPeer = self.currentSendAsPeer {
|
||||
sendAsPeer = currentSendAsPeer
|
||||
} else {
|
||||
sendAsPeer = liveChatStateValue.defaultSendAs.flatMap { defaultSendAs in
|
||||
return self.sendAsData?.availablePeers.first(where: { $0.peer.id == defaultSendAs })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -758,7 +767,7 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) {
|
||||
|
||||
let entities = generateChatInputTextEntities(text)
|
||||
|
||||
call.sendMessage(fromId: self.currentSendAsPeer?.peer.id, isAdmin: isAdmin, text: text.string, entities: entities, paidStars: sendPaidMessageStars?.value)
|
||||
call.sendMessage(fromId: sendAsPeer?.peer.id, isAdmin: isAdmin, text: text.string, entities: entities, paidStars: sendPaidMessageStars?.value)
|
||||
|
||||
component.storyItemSharedState.replyDrafts.removeValue(forKey: StoryId(peerId: peerId, id: focusedItem.storyItem.id))
|
||||
inputPanelView.clearSendMessageInput(updateState: true)
|
||||
@@ -3991,6 +4000,7 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) {
|
||||
|
||||
var topPeers: [ReactionsMessageAttribute.TopPeer] = []
|
||||
var minAmount: Int64 = 1
|
||||
var sendAsPeer: SendAsPeer?
|
||||
if let visibleItemView = view.visibleItems[component.slice.item.id]?.view.view as? StoryItemContentComponent.View {
|
||||
if let topItems = visibleItemView.liveChatState?.starStats?.topItems {
|
||||
topPeers = topItems.map { item -> ReactionsMessageAttribute.TopPeer in
|
||||
@@ -4007,12 +4017,20 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) {
|
||||
if let minMessagePrice = visibleItemView.liveChatState?.minMessagePrice {
|
||||
minAmount = minMessagePrice
|
||||
}
|
||||
|
||||
if let currentSendAsPeer = self.currentSendAsPeer {
|
||||
sendAsPeer = currentSendAsPeer
|
||||
} else {
|
||||
sendAsPeer = visibleItemView.liveChatState?.defaultSendAs.flatMap { defaultSendAs in
|
||||
return self.sendAsData?.availablePeers.first(where: { $0.peer.id == defaultSendAs })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let initialData = await ChatSendStarsScreen.initialData(
|
||||
context: component.context,
|
||||
peerId: peerId,
|
||||
myPeer: (self.currentSendAsPeer?.peer).flatMap(EnginePeer.init),
|
||||
myPeer: (sendAsPeer?.peer).flatMap(EnginePeer.init),
|
||||
reactSubject: .liveStream(peerId: peerId, storyId: focusedItem.storyItem.id, minAmount: Int(minAmount), liveChatMessageParams: LiveChatMessageParams(appConfig: component.context.currentAppConfiguration.with({ $0 }))),
|
||||
topPeers: topPeers,
|
||||
completion: { [weak self, weak view] amount, _, _, _ in
|
||||
@@ -4245,17 +4263,38 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) {
|
||||
guard let call = itemView.mediaStreamCall else {
|
||||
return
|
||||
}
|
||||
var sendAsPeer: SendAsPeer?
|
||||
if let liveChatStateValue = itemView.liveChatState {
|
||||
isAdmin = liveChatStateValue.isAdmin
|
||||
|
||||
if let currentSendAsPeer = self.currentSendAsPeer {
|
||||
sendAsPeer = currentSendAsPeer
|
||||
} else {
|
||||
sendAsPeer = liveChatStateValue.defaultSendAs.flatMap { defaultSendAs in
|
||||
return self.sendAsData?.availablePeers.first(where: { $0.peer.id == defaultSendAs })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
call.sendStars(fromId: self.currentSendAsPeer?.peer.id, isAdmin: isAdmin, amount: Int64(count), delay: delay)
|
||||
call.sendStars(fromId: sendAsPeer?.peer.id, isAdmin: isAdmin, amount: Int64(count), delay: delay)
|
||||
}
|
||||
|
||||
func openSendAsSelection(view: StoryItemSetContainerComponent.View, sourceView: UIView, gesture: ContextGesture?) {
|
||||
guard let component = view.component, let sendAsData = self.sendAsData, let currentSendAsPeer = self.currentSendAsPeer, let controller = component.controller() else {
|
||||
guard let component = view.component, let sendAsData = self.sendAsData, let controller = component.controller() else {
|
||||
return
|
||||
}
|
||||
guard let visibleItemView = view.visibleItems[component.slice.item.id]?.view.view as? StoryItemContentComponent.View else {
|
||||
return
|
||||
}
|
||||
|
||||
var currentSendAsPeer: SendAsPeer?
|
||||
if let currentSendAsPeerValue = self.currentSendAsPeer {
|
||||
currentSendAsPeer = currentSendAsPeerValue
|
||||
} else {
|
||||
currentSendAsPeer = visibleItemView.liveChatState?.defaultSendAs.flatMap { defaultSendAs in
|
||||
return self.sendAsData?.availablePeers.first(where: { $0.peer.id == defaultSendAs })
|
||||
}
|
||||
}
|
||||
|
||||
let focusedItem = component.slice.item
|
||||
guard let peerId = focusedItem.peerId else {
|
||||
@@ -4269,7 +4308,7 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) {
|
||||
context: component.context,
|
||||
chatPeerId: peerId,
|
||||
peers: sendAsData.availablePeers,
|
||||
selectedPeerId: currentSendAsPeer.peer.id,
|
||||
selectedPeerId: currentSendAsPeer?.peer.id,
|
||||
isPremium: isPremium,
|
||||
action: { [weak self, weak view] peer in
|
||||
guard let self, let view else {
|
||||
|
||||
Reference in New Issue
Block a user