mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Stories
This commit is contained in:
parent
d11fe92d67
commit
b427a8d4ca
8 changed files with 217 additions and 151 deletions
|
|
@ -17,13 +17,16 @@ final class TabBarControllerNode: ASDisplayNode {
|
|||
private struct Params: Equatable {
|
||||
let layout: ContainerViewLayout
|
||||
let toolbar: Toolbar?
|
||||
let isTabBarHidden: Bool
|
||||
|
||||
init(
|
||||
layout: ContainerViewLayout,
|
||||
toolbar: Toolbar?
|
||||
toolbar: Toolbar?,
|
||||
isTabBarHidden: Bool
|
||||
) {
|
||||
self.layout = layout
|
||||
self.toolbar = toolbar
|
||||
self.isTabBarHidden = isTabBarHidden
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -160,7 +163,7 @@ final class TabBarControllerNode: ASDisplayNode {
|
|||
}
|
||||
|
||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, toolbar: Toolbar?, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||
let params = Params(layout: layout, toolbar: toolbar)
|
||||
let params = Params(layout: layout, toolbar: toolbar, isTabBarHidden: self.tabBarHidden)
|
||||
if let layoutResult = self.layoutResult, layoutResult.params == params {
|
||||
return layoutResult.bottomInset
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -950,7 +950,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||
|
||||
var sharedAudioContext = sharedAudioContext
|
||||
if sharedAudioContext == nil {
|
||||
var useSharedAudio = true
|
||||
var useSharedAudio = !isStream
|
||||
var canReuseCurrent = true
|
||||
if let data = self.accountContext.currentAppConfiguration.with({ $0 }).data {
|
||||
if data["ios_killswitch_group_shared_audio"] != nil {
|
||||
|
|
|
|||
|
|
@ -178,6 +178,7 @@ final class CameraLiveStreamComponent: Component {
|
|||
hideUI: false,
|
||||
visibilityFraction: 1.0,
|
||||
isPanning: false,
|
||||
isCentral: true,
|
||||
pinchState: nil,
|
||||
presentController: { c, a in
|
||||
// guard let self, let environment = self.environment else {
|
||||
|
|
|
|||
|
|
@ -1624,6 +1624,7 @@ private final class StoryContainerScreenComponent: Component {
|
|||
hideUI: (i == focusedIndex && (self.itemSetPanState?.didBegin == false || self.itemSetPinchState != nil)),
|
||||
visibilityFraction: 1.0 - abs(panFraction + cubeAdditionalRotationFraction),
|
||||
isPanning: self.itemSetPanState?.didBegin == true,
|
||||
isCentral: i == focusedIndex,
|
||||
pinchState: self.itemSetPinchState,
|
||||
presentController: { [weak self] c, a in
|
||||
guard let self, let environment = self.environment else {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ public final class StoryContentItem: Equatable {
|
|||
}
|
||||
|
||||
open class View: UIView {
|
||||
open func setProgressMode(_ progressMode: ProgressMode) {
|
||||
open func setProgressMode(mode: StoryContentItem.ProgressMode, isCentral: Bool) {
|
||||
}
|
||||
|
||||
open func rewind() {
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ final class StoryItemContentComponent: Component {
|
|||
private var unsupportedText: ComponentView<Empty>?
|
||||
private var unsupportedButton: ComponentView<Empty>?
|
||||
|
||||
private var progressMode: StoryContentItem.ProgressMode = .pause
|
||||
private var progressMode: (mode: StoryContentItem.ProgressMode, isCentral: Bool) = (.pause, false)
|
||||
private var currentProgressTimer: SwiftSignalKit.Timer?
|
||||
private var currentProgressTimerValue: Double = 0.0
|
||||
private var videoProgressDisposable: Disposable?
|
||||
|
|
@ -302,7 +302,7 @@ final class StoryItemContentComponent: Component {
|
|||
if self.videoNode != nil {
|
||||
return
|
||||
}
|
||||
if case .pause = self.progressMode {
|
||||
if case .pause = self.progressMode.mode {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -357,7 +357,7 @@ final class StoryItemContentComponent: Component {
|
|||
}
|
||||
|
||||
var shouldLoop = false
|
||||
if self.progressMode == .blurred {
|
||||
if self.progressMode.mode == .blurred {
|
||||
shouldLoop = true
|
||||
} else if let component = self.component, component.item.isPending {
|
||||
shouldLoop = true
|
||||
|
|
@ -410,11 +410,62 @@ final class StoryItemContentComponent: Component {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
if case let .liveStream(liveStream) = currentMessageMedia {
|
||||
let mediaStreamCall: PresentationGroupCallImpl
|
||||
if let current = self.mediaStreamCall {
|
||||
mediaStreamCall = current
|
||||
} else {
|
||||
let initialCall = EngineGroupCallDescription(
|
||||
id: liveStream.call.id,
|
||||
accessHash: liveStream.call.accessHash,
|
||||
title: nil,
|
||||
scheduleTimestamp: nil,
|
||||
subscribedToScheduled: false,
|
||||
isStream: true
|
||||
)
|
||||
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 })
|
||||
mediaStreamCall = PresentationGroupCallImpl(
|
||||
accountContext: component.context,
|
||||
audioSession: component.context.sharedContext.mediaManager.audioSession,
|
||||
callKitIntegration: nil,
|
||||
getDeviceAccessData: {
|
||||
(
|
||||
presentationData: presentationData,
|
||||
present: { c, a in
|
||||
|
||||
},
|
||||
openSettings: {
|
||||
|
||||
}
|
||||
)
|
||||
},
|
||||
initialCall: (initialCall, .id(id: liveStream.call.id, accessHash: liveStream.call.accessHash)),
|
||||
internalId: CallSessionInternalId(),
|
||||
peerId: nil,
|
||||
isChannel: false,
|
||||
invite: nil,
|
||||
joinAsPeerId: nil,
|
||||
isStream: true,
|
||||
keyPair: nil,
|
||||
conferenceSourceId: nil,
|
||||
isConference: false,
|
||||
beginWithVideo: false,
|
||||
sharedAudioContext: nil,
|
||||
unmuteByDefault: false
|
||||
)
|
||||
self.mediaStreamCall = mediaStreamCall
|
||||
|
||||
if update && !self.isUpdating {
|
||||
self.state?.updated(transition: .immediate, isLocal: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func setProgressMode(_ progressMode: StoryContentItem.ProgressMode) {
|
||||
if self.progressMode != progressMode {
|
||||
self.progressMode = progressMode
|
||||
override func setProgressMode(mode: StoryContentItem.ProgressMode, isCentral: Bool) {
|
||||
if self.progressMode.mode != mode || self.progressMode.isCentral != isCentral {
|
||||
self.progressMode = (mode, isCentral)
|
||||
self.updateProgressMode(update: true)
|
||||
|
||||
if let component = self.component, !self.overlaysView.bounds.isEmpty {
|
||||
|
|
@ -459,8 +510,10 @@ final class StoryItemContentComponent: Component {
|
|||
|
||||
private func updateProgressMode(update: Bool) {
|
||||
if let videoNode = self.videoNode {
|
||||
let canPlay = self.progressMode != .pause && self.contentLoaded && self.hierarchyTrackingLayer.isInHierarchy
|
||||
|
||||
var canPlay = self.contentLoaded && self.hierarchyTrackingLayer.isInHierarchy
|
||||
if case .pause = self.progressMode.mode {
|
||||
canPlay = false
|
||||
}
|
||||
if canPlay {
|
||||
videoNode.play()
|
||||
} else {
|
||||
|
|
@ -468,13 +521,32 @@ final class StoryItemContentComponent: Component {
|
|||
}
|
||||
}
|
||||
|
||||
var shouldUpdate = false
|
||||
if let mediaStreamCall = self.mediaStreamCall {
|
||||
//print("call progressMode: \(self.progressMode)")
|
||||
var canPlay = true
|
||||
if case .pause = self.progressMode.mode, (!self.progressMode.isCentral || !self.hierarchyTrackingLayer.isInHierarchy) {
|
||||
canPlay = false
|
||||
}
|
||||
if !canPlay {
|
||||
self.mediaStreamCall = nil
|
||||
shouldUpdate = true
|
||||
|
||||
let _ = mediaStreamCall.leave(terminateIfPossible: false).startStandalone()
|
||||
}
|
||||
}
|
||||
|
||||
self.initializeVideoIfReady(update: update)
|
||||
self.updateVideoPlaybackProgress()
|
||||
self.updateProgressTimer()
|
||||
|
||||
if shouldUpdate {
|
||||
self.state?.updated(transition: .immediate, isLocal: true)
|
||||
}
|
||||
}
|
||||
|
||||
private func updateProgressTimer() {
|
||||
var needsTimer = self.progressMode != .pause && self.contentLoaded && self.hierarchyTrackingLayer.isInHierarchy
|
||||
var needsTimer = self.progressMode.mode != .pause && self.contentLoaded && self.hierarchyTrackingLayer.isInHierarchy
|
||||
if let component = self.component {
|
||||
if component.item.isPending {
|
||||
if case .file = self.currentMessageMedia {
|
||||
|
|
@ -490,7 +562,7 @@ final class StoryItemContentComponent: Component {
|
|||
timeout: 1.0 / 60.0,
|
||||
repeat: true,
|
||||
completion: { [weak self] in
|
||||
guard let self, self.progressMode != .pause, self.contentLoaded, self.hierarchyTrackingLayer.isInHierarchy else {
|
||||
guard let self, self.progressMode.mode != .pause, self.contentLoaded, self.hierarchyTrackingLayer.isInHierarchy else {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -510,7 +582,7 @@ final class StoryItemContentComponent: Component {
|
|||
}
|
||||
}
|
||||
|
||||
if self.progressMode != .play {
|
||||
if self.progressMode.mode != .play {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -681,7 +753,7 @@ final class StoryItemContentComponent: Component {
|
|||
size: size,
|
||||
isCaptureProtected: component.item.isForwardingDisabled,
|
||||
attemptSynchronous: synchronousLoad,
|
||||
isActive: self.progressMode == .play,
|
||||
isActive: self.progressMode.mode == .play,
|
||||
transition: transition
|
||||
)
|
||||
}
|
||||
|
|
@ -842,7 +914,7 @@ final class StoryItemContentComponent: Component {
|
|||
}
|
||||
}
|
||||
|
||||
if case let .liveStream(liveStream) = messageMedia {
|
||||
if case let .liveStream(liveStream) = messageMedia, let mediaStreamCall = self.mediaStreamCall {
|
||||
var mediaStreamTransition = transition
|
||||
let mediaStream: ComponentView<Empty>
|
||||
if let current = self.mediaStream {
|
||||
|
|
@ -853,55 +925,6 @@ final class StoryItemContentComponent: Component {
|
|||
self.mediaStream = mediaStream
|
||||
}
|
||||
|
||||
let mediaStreamCall: PresentationGroupCallImpl
|
||||
if let current = self.mediaStreamCall {
|
||||
mediaStreamCall = current
|
||||
} else {
|
||||
let initialCall = EngineGroupCallDescription(
|
||||
id: liveStream.call.id,
|
||||
accessHash: liveStream.call.accessHash,
|
||||
title: nil,
|
||||
scheduleTimestamp: nil,
|
||||
subscribedToScheduled: false,
|
||||
isStream: true
|
||||
)
|
||||
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 })
|
||||
mediaStreamCall = PresentationGroupCallImpl(
|
||||
accountContext: component.context,
|
||||
audioSession: component.context.sharedContext.mediaManager.audioSession,
|
||||
callKitIntegration: nil,
|
||||
getDeviceAccessData: {
|
||||
(
|
||||
presentationData: presentationData,
|
||||
present: { c, a in
|
||||
|
||||
},
|
||||
openSettings: {
|
||||
|
||||
}
|
||||
)
|
||||
},
|
||||
initialCall: (initialCall, .id(id: liveStream.call.id, accessHash: liveStream.call.accessHash)),
|
||||
internalId: CallSessionInternalId(),
|
||||
peerId: nil,
|
||||
isChannel: false,
|
||||
invite: nil,
|
||||
joinAsPeerId: nil,
|
||||
isStream: true,
|
||||
keyPair: nil,
|
||||
conferenceSourceId: nil,
|
||||
isConference: false,
|
||||
beginWithVideo: false,
|
||||
sharedAudioContext: nil,
|
||||
unmuteByDefault: false
|
||||
)
|
||||
self.mediaStreamCall = mediaStreamCall
|
||||
|
||||
let _ = mediaStreamCall.accountContext.engine.calls.getGroupCallStreamCredentials(peerId: mediaStreamCall.accountContext.account.peerId, isLiveStream: true, revokePreviousCredentials: false).startStandalone(next: { params in
|
||||
print("url: \(params.url), streamKey: \(params.streamKey)")
|
||||
})
|
||||
}
|
||||
|
||||
let liveChat: ComponentView<Empty>
|
||||
if let current = self.liveChat {
|
||||
liveChat = current
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||
public let hideUI: Bool
|
||||
public let visibilityFraction: CGFloat
|
||||
public let isPanning: Bool
|
||||
public let isCentral: Bool
|
||||
public let pinchState: PinchState?
|
||||
public let presentController: (ViewController, Any?) -> Void
|
||||
public let presentInGlobalOverlay: (ViewController, Any?) -> Void
|
||||
|
|
@ -155,6 +156,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||
hideUI: Bool,
|
||||
visibilityFraction: CGFloat,
|
||||
isPanning: Bool,
|
||||
isCentral: Bool,
|
||||
pinchState: PinchState?,
|
||||
presentController: @escaping (ViewController, Any?) -> Void,
|
||||
presentInGlobalOverlay: @escaping (ViewController, Any?) -> Void,
|
||||
|
|
@ -194,6 +196,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||
self.hideUI = hideUI
|
||||
self.visibilityFraction = visibilityFraction
|
||||
self.isPanning = isPanning
|
||||
self.isCentral = isCentral
|
||||
self.pinchState = pinchState
|
||||
self.presentController = presentController
|
||||
self.presentInGlobalOverlay = presentInGlobalOverlay
|
||||
|
|
@ -269,6 +272,9 @@ public final class StoryItemSetContainerComponent: Component {
|
|||
if lhs.isPanning != rhs.isPanning {
|
||||
return false
|
||||
}
|
||||
if lhs.isCentral != rhs.isCentral {
|
||||
return false
|
||||
}
|
||||
if lhs.pinchState != rhs.pinchState {
|
||||
return false
|
||||
}
|
||||
|
|
@ -1715,7 +1721,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||
itemProgressMode = .pause
|
||||
}
|
||||
|
||||
view.setProgressMode(itemProgressMode)
|
||||
view.setProgressMode(mode: itemProgressMode, isCentral: index == centralIndex && component.isCentral)
|
||||
|
||||
var isChannel = false
|
||||
var canShare = true
|
||||
|
|
@ -1952,6 +1958,9 @@ public final class StoryItemSetContainerComponent: Component {
|
|||
}
|
||||
|
||||
func updateIsProgressPaused() {
|
||||
guard let component = self.component else {
|
||||
return
|
||||
}
|
||||
let progressMode = self.itemProgressMode()
|
||||
var centralId: StoryId?
|
||||
if let component = self.component {
|
||||
|
|
@ -1965,7 +1974,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||
if id != centralId {
|
||||
itemMode = .pause
|
||||
}
|
||||
view.setProgressMode(itemMode)
|
||||
view.setProgressMode(mode: itemMode, isCentral: id == centralId && component.isCentral)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2865,7 +2874,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||
}
|
||||
|
||||
let inputPlaceholder: MessageInputPanelComponent.Placeholder
|
||||
if let stealthModeTimeout = component.stealthModeTimeout {
|
||||
if let stealthModeTimeout = component.stealthModeTimeout, !isLiveStream {
|
||||
let minutes = Int(stealthModeTimeout / 60)
|
||||
let seconds = Int(stealthModeTimeout % 60)
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ import ChatSendAsContextMenu
|
|||
|
||||
private var ObjCKey_DeinitWatcher: Int?
|
||||
|
||||
final class StoryItemSetContainerSendMessage {
|
||||
final class StoryItemSetContainerSendMessage: @unchecked(Sendable) {
|
||||
enum InputMode {
|
||||
case text
|
||||
case media
|
||||
|
|
@ -4032,20 +4032,53 @@ final class StoryItemSetContainerSendMessage {
|
|||
}
|
||||
|
||||
func performSendStars(view: StoryItemSetContainerComponent.View, buttonView: UIView?, count: Int, isFromExpandedView: Bool) {
|
||||
guard let component = view.component else {
|
||||
return
|
||||
}
|
||||
|
||||
if isFromExpandedView {
|
||||
if let currentSendStarsUndoController = self.currentSendStarsUndoController {
|
||||
self.currentSendStarsUndoController = nil
|
||||
currentSendStarsUndoController.dismiss()
|
||||
Task { @MainActor [weak self, weak view] in
|
||||
guard let self, let view, let component = view.component else {
|
||||
return
|
||||
}
|
||||
|
||||
self.commitSendStars(view: view, count: count, delay: false)
|
||||
} else {
|
||||
Task { @MainActor [weak view] in
|
||||
guard let view, let component = view.component else {
|
||||
guard let visibleItemView = view.visibleItems[component.slice.item.id]?.view.view as? StoryItemContentComponent.View else {
|
||||
return
|
||||
}
|
||||
|
||||
if isFromExpandedView {
|
||||
if let currentSendStarsUndoController = self.currentSendStarsUndoController {
|
||||
self.currentSendStarsUndoController = nil
|
||||
currentSendStarsUndoController.dismiss()
|
||||
}
|
||||
|
||||
self.commitSendStars(view: view, count: count, delay: false)
|
||||
} else {
|
||||
let starsContextState = await component.context.starsContext?.state.get()
|
||||
guard let balance = starsContextState?.balance else {
|
||||
return
|
||||
}
|
||||
|
||||
var totalExpectedStars = count
|
||||
if let pendingMyStars = visibleItemView.liveChatState?.starStats?.pendingMyStars, pendingMyStars > 0 {
|
||||
totalExpectedStars += Int(pendingMyStars)
|
||||
}
|
||||
if Int64(totalExpectedStars) > balance.value {
|
||||
guard let starsContext = component.context.starsContext, let navigationController = component.controller()?.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
guard let targetPeerId = component.slice.item.peerId else {
|
||||
return
|
||||
}
|
||||
|
||||
let customTheme = component.theme
|
||||
let options = await component.context.engine.payments.starsTopUpOptions().get()
|
||||
let controller = component.context.sharedContext.makeStarsPurchaseScreen(
|
||||
context: component.context,
|
||||
starsContext: starsContext,
|
||||
options: options,
|
||||
purpose: .generic,
|
||||
targetPeerId: targetPeerId,
|
||||
customTheme: customTheme,
|
||||
completion: { _ in }
|
||||
)
|
||||
navigationController.pushViewController(controller)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -4126,78 +4159,74 @@ final class StoryItemSetContainerSendMessage {
|
|||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
guard let visibleItemView = view.visibleItems[component.slice.item.id]?.view.view as? StoryItemContentComponent.View else {
|
||||
return
|
||||
}
|
||||
|
||||
self.currentLiveStreamStarsIsActive = true
|
||||
self.currentLiveStreamStarsIsActiveTimer?.invalidate()
|
||||
self.currentLiveStreamStarsIsActiveTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false, block: { [weak self, weak view] _ in
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
self.currentLiveStreamStarsIsActive = false
|
||||
view.state?.updated(transition: .spring(duration: 0.4))
|
||||
})
|
||||
|
||||
var totalStars = 0
|
||||
if let pendingMyStars = visibleItemView.liveChatState?.starStats?.pendingMyStars, pendingMyStars > 0 {
|
||||
totalStars += count
|
||||
totalStars += Int(pendingMyStars)
|
||||
self.commitSendStars(view: view, count: count, delay: true)
|
||||
} else {
|
||||
let minAmount: Int64 = 1
|
||||
var count = count
|
||||
count = max(Int(minAmount), count)
|
||||
totalStars += count
|
||||
|
||||
self.commitSendStars(view: view, count: count, delay: true)
|
||||
}
|
||||
|
||||
let title: String
|
||||
/*if case .anonymous = privacy {
|
||||
title = self.presentationData.strings.Chat_ToastStarsSent_AnonymousTitle(Int32(self.currentSendStarsUndoCount))
|
||||
} else if case .peer = privacy, let privacyPeer {
|
||||
let rawTitle = self.presentationData.strings.Chat_ToastStarsSent_TitleChannel(Int32(self.currentSendStarsUndoCount))
|
||||
title = rawTitle.replacingOccurrences(of: "{name}", with: privacyPeer.compactDisplayTitle)
|
||||
} else*/ do {
|
||||
title = component.strings.Chat_ToastStarsSent_Title(Int32(totalStars))
|
||||
}
|
||||
|
||||
let textItems = AnimatedTextComponent.extractAnimatedTextString(string: component.strings.Chat_ToastStarsSent_Text("", ""), id: "text", mapping: [
|
||||
0: .number(totalStars, minDigits: 1),
|
||||
1: .text(component.strings.Chat_ToastStarsSent_TextStarAmount(Int32(totalStars)))
|
||||
])
|
||||
|
||||
if let current = self.currentSendStarsUndoController {
|
||||
current.content = .starsSent(context: component.context, title: title, text: textItems, hasUndo: true)
|
||||
} else {
|
||||
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }.withUpdated(theme: defaultDarkColorPresentationTheme)
|
||||
let controller = UndoOverlayController(presentationData: presentationData, content: .starsSent(context: component.context, title: title, text: textItems, hasUndo: true), elevatedLayout: false, position: .top, action: { [weak view] action in
|
||||
guard let view else {
|
||||
return false
|
||||
self.currentLiveStreamStarsIsActive = true
|
||||
self.currentLiveStreamStarsIsActiveTimer?.invalidate()
|
||||
self.currentLiveStreamStarsIsActiveTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false, block: { [weak self, weak view] _ in
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
if case .undo = action {
|
||||
guard let component = view.component else {
|
||||
return false
|
||||
}
|
||||
guard case .liveStream = component.slice.item.storyItem.media else {
|
||||
return false
|
||||
}
|
||||
guard let visibleItem = view.visibleItems[component.slice.item.id], let itemView = visibleItem.view.view as? StoryItemContentComponent.View else {
|
||||
return false
|
||||
}
|
||||
guard let call = itemView.mediaStreamCall else {
|
||||
return false
|
||||
}
|
||||
call.cancelSendStars()
|
||||
}
|
||||
return false
|
||||
self.currentLiveStreamStarsIsActive = false
|
||||
view.state?.updated(transition: .spring(duration: 0.4))
|
||||
})
|
||||
self.currentSendStarsUndoController = controller
|
||||
self.view?.component?.controller()?.present(controller, in: .current)
|
||||
|
||||
var totalStars = 0
|
||||
if let pendingMyStars = visibleItemView.liveChatState?.starStats?.pendingMyStars, pendingMyStars > 0 {
|
||||
totalStars += count
|
||||
totalStars += Int(pendingMyStars)
|
||||
self.commitSendStars(view: view, count: count, delay: true)
|
||||
} else {
|
||||
let minAmount: Int64 = 1
|
||||
var count = count
|
||||
count = max(Int(minAmount), count)
|
||||
totalStars += count
|
||||
|
||||
self.commitSendStars(view: view, count: count, delay: true)
|
||||
}
|
||||
|
||||
let title: String
|
||||
/*if case .anonymous = privacy {
|
||||
title = self.presentationData.strings.Chat_ToastStarsSent_AnonymousTitle(Int32(self.currentSendStarsUndoCount))
|
||||
} else if case .peer = privacy, let privacyPeer {
|
||||
let rawTitle = self.presentationData.strings.Chat_ToastStarsSent_TitleChannel(Int32(self.currentSendStarsUndoCount))
|
||||
title = rawTitle.replacingOccurrences(of: "{name}", with: privacyPeer.compactDisplayTitle)
|
||||
} else*/ do {
|
||||
title = component.strings.Chat_ToastStarsSent_Title(Int32(totalStars))
|
||||
}
|
||||
|
||||
let textItems = AnimatedTextComponent.extractAnimatedTextString(string: component.strings.Chat_ToastStarsSent_Text("", ""), id: "text", mapping: [
|
||||
0: .number(totalStars, minDigits: 1),
|
||||
1: .text(component.strings.Chat_ToastStarsSent_TextStarAmount(Int32(totalStars)))
|
||||
])
|
||||
|
||||
if let current = self.currentSendStarsUndoController {
|
||||
current.content = .starsSent(context: component.context, title: title, text: textItems, hasUndo: true)
|
||||
} else {
|
||||
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }.withUpdated(theme: defaultDarkColorPresentationTheme)
|
||||
let controller = UndoOverlayController(presentationData: presentationData, content: .starsSent(context: component.context, title: title, text: textItems, hasUndo: true), elevatedLayout: false, position: .top, action: { [weak view] action in
|
||||
guard let view else {
|
||||
return false
|
||||
}
|
||||
if case .undo = action {
|
||||
guard let component = view.component else {
|
||||
return false
|
||||
}
|
||||
guard case .liveStream = component.slice.item.storyItem.media else {
|
||||
return false
|
||||
}
|
||||
guard let visibleItem = view.visibleItems[component.slice.item.id], let itemView = visibleItem.view.view as? StoryItemContentComponent.View else {
|
||||
return false
|
||||
}
|
||||
guard let call = itemView.mediaStreamCall else {
|
||||
return false
|
||||
}
|
||||
call.cancelSendStars()
|
||||
}
|
||||
return false
|
||||
})
|
||||
self.currentSendStarsUndoController = controller
|
||||
self.view?.component?.controller()?.present(controller, in: .current)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue