mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 09:20:08 +00:00
Various improvements
This commit is contained in:
parent
400de1ef11
commit
c42b2bd9c0
@ -1031,8 +1031,9 @@ public enum StarsWithdrawalScreenSubject {
|
|||||||
case postSuggestion
|
case postSuggestion
|
||||||
}
|
}
|
||||||
|
|
||||||
case withdraw
|
case withdraw(completion: (Int64) -> Void)
|
||||||
case enterAmount(current: StarsAmount, minValue: StarsAmount, fractionAfterCommission: Int, kind: PaidMessageKind)
|
case enterAmount(current: StarsAmount, minValue: StarsAmount, fractionAfterCommission: Int, kind: PaidMessageKind, completion: (Int64) -> Void)
|
||||||
|
case postSuggestion(channel: EnginePeer, current: StarsAmount, timestamp: Int32?, completion: (Int64, Int32?) -> Void)
|
||||||
}
|
}
|
||||||
|
|
||||||
public protocol SharedAccountContext: AnyObject {
|
public protocol SharedAccountContext: AnyObject {
|
||||||
@ -1221,7 +1222,7 @@ public protocol SharedAccountContext: AnyObject {
|
|||||||
func makeStarsStatisticsScreen(context: AccountContext, peerId: EnginePeer.Id, revenueContext: StarsRevenueStatsContext) -> ViewController
|
func makeStarsStatisticsScreen(context: AccountContext, peerId: EnginePeer.Id, revenueContext: StarsRevenueStatsContext) -> ViewController
|
||||||
func makeStarsAmountScreen(context: AccountContext, initialValue: Int64?, completion: @escaping (Int64) -> Void) -> ViewController
|
func makeStarsAmountScreen(context: AccountContext, initialValue: Int64?, completion: @escaping (Int64) -> Void) -> ViewController
|
||||||
func makeStarsWithdrawalScreen(context: AccountContext, stats: StarsRevenueStats, completion: @escaping (Int64) -> Void) -> ViewController
|
func makeStarsWithdrawalScreen(context: AccountContext, stats: StarsRevenueStats, completion: @escaping (Int64) -> Void) -> ViewController
|
||||||
func makeStarsWithdrawalScreen(context: AccountContext, subject: StarsWithdrawalScreenSubject, completion: @escaping (Int64) -> Void) -> ViewController
|
func makeStarsWithdrawalScreen(context: AccountContext, subject: StarsWithdrawalScreenSubject) -> ViewController
|
||||||
func makeStarGiftResellScreen(context: AccountContext, gift: StarGift.UniqueGift, update: Bool, completion: @escaping (Int64) -> Void) -> ViewController
|
func makeStarGiftResellScreen(context: AccountContext, gift: StarGift.UniqueGift, update: Bool, completion: @escaping (Int64) -> Void) -> ViewController
|
||||||
func makeStarsGiftScreen(context: AccountContext, message: EngineMessage) -> ViewController
|
func makeStarsGiftScreen(context: AccountContext, message: EngineMessage) -> ViewController
|
||||||
func makeStarsGiveawayBoostScreen(context: AccountContext, peerId: EnginePeer.Id, boost: ChannelBoostersContext.State.Boost) -> ViewController
|
func makeStarsGiveawayBoostScreen(context: AccountContext, peerId: EnginePeer.Id, boost: ChannelBoostersContext.State.Boost) -> ViewController
|
||||||
|
|||||||
@ -961,6 +961,7 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
}, presentForwardOptions: { _ in
|
}, presentForwardOptions: { _ in
|
||||||
}, presentReplyOptions: { _ in
|
}, presentReplyOptions: { _ in
|
||||||
}, presentLinkOptions: { _ in
|
}, presentLinkOptions: { _ in
|
||||||
|
}, presentSuggestPostOptions: {
|
||||||
}, shareSelectedMessages: {
|
}, shareSelectedMessages: {
|
||||||
}, updateTextInputStateAndMode: { [weak self] f in
|
}, updateTextInputStateAndMode: { [weak self] f in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
@ -1246,7 +1247,7 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
}, joinGroupCall: { _ in
|
}, joinGroupCall: { _ in
|
||||||
}, presentInviteMembers: {
|
}, presentInviteMembers: {
|
||||||
}, presentGigagroupHelp: {
|
}, presentGigagroupHelp: {
|
||||||
}, openSuggestPost: {
|
}, openMonoforum: {
|
||||||
}, editMessageMedia: { _, _ in
|
}, editMessageMedia: { _, _ in
|
||||||
}, updateShowCommands: { _ in
|
}, updateShowCommands: { _ in
|
||||||
}, updateShowSendAsPeers: { _ in
|
}, updateShowSendAsPeers: { _ in
|
||||||
@ -1264,6 +1265,7 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
}, addDoNotTranslateLanguage: { _ in
|
}, addDoNotTranslateLanguage: { _ in
|
||||||
}, hideTranslationPanel: {
|
}, hideTranslationPanel: {
|
||||||
}, openPremiumGift: {
|
}, openPremiumGift: {
|
||||||
|
}, openSuggestPost: {
|
||||||
}, openPremiumRequiredForMessaging: {
|
}, openPremiumRequiredForMessaging: {
|
||||||
}, openStarsPurchase: { _ in
|
}, openStarsPurchase: { _ in
|
||||||
}, openMessagePayment: {
|
}, openMessagePayment: {
|
||||||
|
|||||||
@ -495,6 +495,16 @@ public final class ChatInterfaceState: Codable, Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct PostSuggestionState: Codable, Equatable {
|
||||||
|
public var price: Int64
|
||||||
|
public var timestamp: Int32?
|
||||||
|
|
||||||
|
public init(price: Int64, timestamp: Int32?) {
|
||||||
|
self.price = price
|
||||||
|
self.timestamp = timestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public let timestamp: Int32
|
public let timestamp: Int32
|
||||||
public let composeInputState: ChatTextInputState
|
public let composeInputState: ChatTextInputState
|
||||||
public let composeDisableUrlPreviews: [String]
|
public let composeDisableUrlPreviews: [String]
|
||||||
@ -510,6 +520,7 @@ public final class ChatInterfaceState: Codable, Equatable {
|
|||||||
public let silentPosting: Bool
|
public let silentPosting: Bool
|
||||||
public let inputLanguage: String?
|
public let inputLanguage: String?
|
||||||
public let sendMessageEffect: Int64?
|
public let sendMessageEffect: Int64?
|
||||||
|
public let postSuggestionState: PostSuggestionState?
|
||||||
|
|
||||||
public var synchronizeableInputState: SynchronizeableChatInputState? {
|
public var synchronizeableInputState: SynchronizeableChatInputState? {
|
||||||
if self.composeInputState.inputText.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && self.replyMessageSubject == nil {
|
if self.composeInputState.inputText.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && self.replyMessageSubject == nil {
|
||||||
@ -561,9 +572,10 @@ public final class ChatInterfaceState: Codable, Equatable {
|
|||||||
self.silentPosting = false
|
self.silentPosting = false
|
||||||
self.inputLanguage = nil
|
self.inputLanguage = nil
|
||||||
self.sendMessageEffect = nil
|
self.sendMessageEffect = nil
|
||||||
|
self.postSuggestionState = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(timestamp: Int32, composeInputState: ChatTextInputState, composeDisableUrlPreviews: [String], replyMessageSubject: ReplyMessageSubject?, forwardMessageIds: [EngineMessage.Id]?, forwardOptionsState: ChatInterfaceForwardOptionsState?, editMessage: ChatEditMessageState?, selectionState: ChatInterfaceSelectionState?, messageActionsState: ChatInterfaceMessageActionsState, historyScrollState: ChatInterfaceHistoryScrollState?, mediaRecordingMode: ChatTextInputMediaRecordingButtonMode, mediaDraftState: ChatInterfaceMediaDraftState?, silentPosting: Bool, inputLanguage: String?, sendMessageEffect: Int64?) {
|
public init(timestamp: Int32, composeInputState: ChatTextInputState, composeDisableUrlPreviews: [String], replyMessageSubject: ReplyMessageSubject?, forwardMessageIds: [EngineMessage.Id]?, forwardOptionsState: ChatInterfaceForwardOptionsState?, editMessage: ChatEditMessageState?, selectionState: ChatInterfaceSelectionState?, messageActionsState: ChatInterfaceMessageActionsState, historyScrollState: ChatInterfaceHistoryScrollState?, mediaRecordingMode: ChatTextInputMediaRecordingButtonMode, mediaDraftState: ChatInterfaceMediaDraftState?, silentPosting: Bool, inputLanguage: String?, sendMessageEffect: Int64?, postSuggestionState: PostSuggestionState?) {
|
||||||
self.timestamp = timestamp
|
self.timestamp = timestamp
|
||||||
self.composeInputState = composeInputState
|
self.composeInputState = composeInputState
|
||||||
self.composeDisableUrlPreviews = composeDisableUrlPreviews
|
self.composeDisableUrlPreviews = composeDisableUrlPreviews
|
||||||
@ -579,6 +591,7 @@ public final class ChatInterfaceState: Codable, Equatable {
|
|||||||
self.silentPosting = silentPosting
|
self.silentPosting = silentPosting
|
||||||
self.inputLanguage = inputLanguage
|
self.inputLanguage = inputLanguage
|
||||||
self.sendMessageEffect = sendMessageEffect
|
self.sendMessageEffect = sendMessageEffect
|
||||||
|
self.postSuggestionState = postSuggestionState
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(from decoder: Decoder) throws {
|
public init(from decoder: Decoder) throws {
|
||||||
@ -650,8 +663,8 @@ public final class ChatInterfaceState: Codable, Equatable {
|
|||||||
|
|
||||||
self.silentPosting = ((try? container.decode(Int32.self, forKey: "sip")) ?? 0) != 0
|
self.silentPosting = ((try? container.decode(Int32.self, forKey: "sip")) ?? 0) != 0
|
||||||
self.inputLanguage = try? container.decodeIfPresent(String.self, forKey: "inputLanguage")
|
self.inputLanguage = try? container.decodeIfPresent(String.self, forKey: "inputLanguage")
|
||||||
|
|
||||||
self.sendMessageEffect = try? container.decodeIfPresent(Int64.self, forKey: "sendMessageEffect")
|
self.sendMessageEffect = try? container.decodeIfPresent(Int64.self, forKey: "sendMessageEffect")
|
||||||
|
self.postSuggestionState = try? container.decodeIfPresent(PostSuggestionState.self, forKey: "postSuggestionState")
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(to encoder: Encoder) throws {
|
public func encode(to encoder: Encoder) throws {
|
||||||
@ -710,6 +723,7 @@ public final class ChatInterfaceState: Codable, Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try container.encodeIfPresent(self.sendMessageEffect, forKey: "sendMessageEffect")
|
try container.encodeIfPresent(self.sendMessageEffect, forKey: "sendMessageEffect")
|
||||||
|
try container.encodeIfPresent(self.postSuggestionState, forKey: "postSuggestionState")
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: ChatInterfaceState, rhs: ChatInterfaceState) -> Bool {
|
public static func ==(lhs: ChatInterfaceState, rhs: ChatInterfaceState) -> Bool {
|
||||||
@ -747,17 +761,20 @@ public final class ChatInterfaceState: Codable, Equatable {
|
|||||||
if lhs.sendMessageEffect != rhs.sendMessageEffect {
|
if lhs.sendMessageEffect != rhs.sendMessageEffect {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.postSuggestionState != rhs.postSuggestionState {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return lhs.composeInputState == rhs.composeInputState && lhs.replyMessageSubject == rhs.replyMessageSubject && lhs.selectionState == rhs.selectionState && lhs.editMessage == rhs.editMessage
|
return lhs.composeInputState == rhs.composeInputState && lhs.replyMessageSubject == rhs.replyMessageSubject && lhs.selectionState == rhs.selectionState && lhs.editMessage == rhs.editMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedComposeInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState {
|
public func withUpdatedComposeInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState {
|
||||||
let updatedComposeInputState = inputState
|
let updatedComposeInputState = inputState
|
||||||
|
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect, postSuggestionState: self.postSuggestionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedComposeDisableUrlPreviews(_ disableUrlPreviews: [String]) -> ChatInterfaceState {
|
public func withUpdatedComposeDisableUrlPreviews(_ disableUrlPreviews: [String]) -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: disableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: disableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect, postSuggestionState: self.postSuggestionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedEffectiveInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState {
|
public func withUpdatedEffectiveInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState {
|
||||||
@ -769,19 +786,19 @@ public final class ChatInterfaceState: Codable, Equatable {
|
|||||||
updatedComposeInputState = inputState
|
updatedComposeInputState = inputState
|
||||||
}
|
}
|
||||||
|
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: updatedEditMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: updatedComposeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: updatedEditMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect, postSuggestionState: self.postSuggestionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedReplyMessageSubject(_ replyMessageSubject: ReplyMessageSubject?) -> ChatInterfaceState {
|
public func withUpdatedReplyMessageSubject(_ replyMessageSubject: ReplyMessageSubject?) -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect, postSuggestionState: self.postSuggestionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedForwardMessageIds(_ forwardMessageIds: [EngineMessage.Id]?) -> ChatInterfaceState {
|
public func withUpdatedForwardMessageIds(_ forwardMessageIds: [EngineMessage.Id]?) -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect, postSuggestionState: self.postSuggestionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedForwardOptionsState(_ forwardOptionsState: ChatInterfaceForwardOptionsState?) -> ChatInterfaceState {
|
public func withUpdatedForwardOptionsState(_ forwardOptionsState: ChatInterfaceForwardOptionsState?) -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect, postSuggestionState: self.postSuggestionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedSelectedMessages(_ messageIds: [EngineMessage.Id]) -> ChatInterfaceState {
|
public func withUpdatedSelectedMessages(_ messageIds: [EngineMessage.Id]) -> ChatInterfaceState {
|
||||||
@ -792,7 +809,7 @@ public final class ChatInterfaceState: Codable, Equatable {
|
|||||||
for messageId in messageIds {
|
for messageId in messageIds {
|
||||||
selectedIds.insert(messageId)
|
selectedIds.insert(messageId)
|
||||||
}
|
}
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect, postSuggestionState: self.postSuggestionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withToggledSelectedMessages(_ messageIds: [EngineMessage.Id], value: Bool) -> ChatInterfaceState {
|
public func withToggledSelectedMessages(_ messageIds: [EngineMessage.Id], value: Bool) -> ChatInterfaceState {
|
||||||
@ -807,47 +824,51 @@ public final class ChatInterfaceState: Codable, Equatable {
|
|||||||
selectedIds.remove(messageId)
|
selectedIds.remove(messageId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds), messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect, postSuggestionState: self.postSuggestionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withoutSelectionState() -> ChatInterfaceState {
|
public func withoutSelectionState() -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: nil, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: nil, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect, postSuggestionState: self.postSuggestionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedTimestamp(_ timestamp: Int32) -> ChatInterfaceState {
|
public func withUpdatedTimestamp(_ timestamp: Int32) -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect)
|
return ChatInterfaceState(timestamp: timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect, postSuggestionState: self.postSuggestionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedEditMessage(_ editMessage: ChatEditMessageState?) -> ChatInterfaceState {
|
public func withUpdatedEditMessage(_ editMessage: ChatEditMessageState?) -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect, postSuggestionState: self.postSuggestionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedMessageActionsState(_ f: (ChatInterfaceMessageActionsState) -> ChatInterfaceMessageActionsState) -> ChatInterfaceState {
|
public func withUpdatedMessageActionsState(_ f: (ChatInterfaceMessageActionsState) -> ChatInterfaceMessageActionsState) -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: f(self.messageActionsState), historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: f(self.messageActionsState), historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect, postSuggestionState: self.postSuggestionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedHistoryScrollState(_ historyScrollState: ChatInterfaceHistoryScrollState?) -> ChatInterfaceState {
|
public func withUpdatedHistoryScrollState(_ historyScrollState: ChatInterfaceHistoryScrollState?) -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect, postSuggestionState: self.postSuggestionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedMediaRecordingMode(_ mediaRecordingMode: ChatTextInputMediaRecordingButtonMode) -> ChatInterfaceState {
|
public func withUpdatedMediaRecordingMode(_ mediaRecordingMode: ChatTextInputMediaRecordingButtonMode) -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect, postSuggestionState: self.postSuggestionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedMediaDraftState(_ mediaDraftState: ChatInterfaceMediaDraftState?) -> ChatInterfaceState {
|
public func withUpdatedMediaDraftState(_ mediaDraftState: ChatInterfaceMediaDraftState?) -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect, postSuggestionState: self.postSuggestionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedSilentPosting(_ silentPosting: Bool) -> ChatInterfaceState {
|
public func withUpdatedSilentPosting(_ silentPosting: Bool) -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect, postSuggestionState: self.postSuggestionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedInputLanguage(_ inputLanguage: String?) -> ChatInterfaceState {
|
public func withUpdatedInputLanguage(_ inputLanguage: String?) -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: inputLanguage, sendMessageEffect: self.sendMessageEffect)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: inputLanguage, sendMessageEffect: self.sendMessageEffect, postSuggestionState: self.postSuggestionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func withUpdatedSendMessageEffect(_ sendMessageEffect: Int64?) -> ChatInterfaceState {
|
public func withUpdatedSendMessageEffect(_ sendMessageEffect: Int64?) -> ChatInterfaceState {
|
||||||
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: sendMessageEffect)
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: sendMessageEffect, postSuggestionState: self.postSuggestionState)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func withUpdatedPostSuggestionState(_ postSuggestionState: PostSuggestionState?) -> ChatInterfaceState {
|
||||||
|
return ChatInterfaceState(timestamp: self.timestamp, composeInputState: self.composeInputState, composeDisableUrlPreviews: self.composeDisableUrlPreviews, replyMessageSubject: self.replyMessageSubject, forwardMessageIds: self.forwardMessageIds, forwardOptionsState: self.forwardOptionsState, editMessage: self.editMessage, selectionState: self.selectionState, messageActionsState: self.messageActionsState, historyScrollState: self.historyScrollState, mediaRecordingMode: self.mediaRecordingMode, mediaDraftState: self.mediaDraftState, silentPosting: self.silentPosting, inputLanguage: self.inputLanguage, sendMessageEffect: self.sendMessageEffect, postSuggestionState: postSuggestionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func parse(_ state: OpaqueChatInterfaceState) -> ChatInterfaceState {
|
public static func parse(_ state: OpaqueChatInterfaceState) -> ChatInterfaceState {
|
||||||
|
|||||||
@ -78,6 +78,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||||||
public let presentForwardOptions: (ASDisplayNode) -> Void
|
public let presentForwardOptions: (ASDisplayNode) -> Void
|
||||||
public let presentReplyOptions: (ASDisplayNode) -> Void
|
public let presentReplyOptions: (ASDisplayNode) -> Void
|
||||||
public let presentLinkOptions: (ASDisplayNode) -> Void
|
public let presentLinkOptions: (ASDisplayNode) -> Void
|
||||||
|
public let presentSuggestPostOptions: () -> Void
|
||||||
public let shareSelectedMessages: () -> Void
|
public let shareSelectedMessages: () -> Void
|
||||||
public let updateTextInputStateAndMode: (@escaping (ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void
|
public let updateTextInputStateAndMode: (@escaping (ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void
|
||||||
public let updateInputModeAndDismissedButtonKeyboardMessageId: ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void
|
public let updateInputModeAndDismissedButtonKeyboardMessageId: ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void
|
||||||
@ -150,7 +151,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||||||
public let joinGroupCall: (CachedChannelData.ActiveCall) -> Void
|
public let joinGroupCall: (CachedChannelData.ActiveCall) -> Void
|
||||||
public let presentInviteMembers: () -> Void
|
public let presentInviteMembers: () -> Void
|
||||||
public let presentGigagroupHelp: () -> Void
|
public let presentGigagroupHelp: () -> Void
|
||||||
public let openSuggestPost: () -> Void
|
public let openMonoforum: () -> Void
|
||||||
public let updateShowCommands: ((Bool) -> Bool) -> Void
|
public let updateShowCommands: ((Bool) -> Bool) -> Void
|
||||||
public let updateShowSendAsPeers: ((Bool) -> Bool) -> Void
|
public let updateShowSendAsPeers: ((Bool) -> Bool) -> Void
|
||||||
public let openInviteRequests: () -> Void
|
public let openInviteRequests: () -> Void
|
||||||
@ -167,6 +168,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||||||
public let addDoNotTranslateLanguage: (String) -> Void
|
public let addDoNotTranslateLanguage: (String) -> Void
|
||||||
public let hideTranslationPanel: () -> Void
|
public let hideTranslationPanel: () -> Void
|
||||||
public let openPremiumGift: () -> Void
|
public let openPremiumGift: () -> Void
|
||||||
|
public let openSuggestPost: () -> Void
|
||||||
public let openPremiumRequiredForMessaging: () -> Void
|
public let openPremiumRequiredForMessaging: () -> Void
|
||||||
public let openStarsPurchase: (Int64?) -> Void
|
public let openStarsPurchase: (Int64?) -> Void
|
||||||
public let openMessagePayment: () -> Void
|
public let openMessagePayment: () -> Void
|
||||||
@ -199,6 +201,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||||||
presentForwardOptions: @escaping (ASDisplayNode) -> Void,
|
presentForwardOptions: @escaping (ASDisplayNode) -> Void,
|
||||||
presentReplyOptions: @escaping (ASDisplayNode) -> Void,
|
presentReplyOptions: @escaping (ASDisplayNode) -> Void,
|
||||||
presentLinkOptions: @escaping (ASDisplayNode) -> Void,
|
presentLinkOptions: @escaping (ASDisplayNode) -> Void,
|
||||||
|
presentSuggestPostOptions: @escaping () -> Void,
|
||||||
shareSelectedMessages: @escaping () -> Void,
|
shareSelectedMessages: @escaping () -> Void,
|
||||||
updateTextInputStateAndMode: @escaping ((ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void,
|
updateTextInputStateAndMode: @escaping ((ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void,
|
||||||
updateInputModeAndDismissedButtonKeyboardMessageId: @escaping ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void,
|
updateInputModeAndDismissedButtonKeyboardMessageId: @escaping ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void,
|
||||||
@ -270,7 +273,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||||||
joinGroupCall: @escaping (CachedChannelData.ActiveCall) -> Void,
|
joinGroupCall: @escaping (CachedChannelData.ActiveCall) -> Void,
|
||||||
presentInviteMembers: @escaping () -> Void,
|
presentInviteMembers: @escaping () -> Void,
|
||||||
presentGigagroupHelp: @escaping () -> Void,
|
presentGigagroupHelp: @escaping () -> Void,
|
||||||
openSuggestPost: @escaping () -> Void,
|
openMonoforum: @escaping () -> Void,
|
||||||
editMessageMedia: @escaping (MessageId, Bool) -> Void,
|
editMessageMedia: @escaping (MessageId, Bool) -> Void,
|
||||||
updateShowCommands: @escaping ((Bool) -> Bool) -> Void,
|
updateShowCommands: @escaping ((Bool) -> Bool) -> Void,
|
||||||
updateShowSendAsPeers: @escaping ((Bool) -> Bool) -> Void,
|
updateShowSendAsPeers: @escaping ((Bool) -> Bool) -> Void,
|
||||||
@ -288,6 +291,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||||||
addDoNotTranslateLanguage: @escaping (String) -> Void,
|
addDoNotTranslateLanguage: @escaping (String) -> Void,
|
||||||
hideTranslationPanel: @escaping () -> Void,
|
hideTranslationPanel: @escaping () -> Void,
|
||||||
openPremiumGift: @escaping () -> Void,
|
openPremiumGift: @escaping () -> Void,
|
||||||
|
openSuggestPost: @escaping () -> Void,
|
||||||
openPremiumRequiredForMessaging: @escaping () -> Void,
|
openPremiumRequiredForMessaging: @escaping () -> Void,
|
||||||
openStarsPurchase: @escaping (Int64?) -> Void,
|
openStarsPurchase: @escaping (Int64?) -> Void,
|
||||||
openMessagePayment: @escaping () -> Void,
|
openMessagePayment: @escaping () -> Void,
|
||||||
@ -319,6 +323,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||||||
self.presentForwardOptions = presentForwardOptions
|
self.presentForwardOptions = presentForwardOptions
|
||||||
self.presentReplyOptions = presentReplyOptions
|
self.presentReplyOptions = presentReplyOptions
|
||||||
self.presentLinkOptions = presentLinkOptions
|
self.presentLinkOptions = presentLinkOptions
|
||||||
|
self.presentSuggestPostOptions = presentSuggestPostOptions
|
||||||
self.shareSelectedMessages = shareSelectedMessages
|
self.shareSelectedMessages = shareSelectedMessages
|
||||||
self.updateTextInputStateAndMode = updateTextInputStateAndMode
|
self.updateTextInputStateAndMode = updateTextInputStateAndMode
|
||||||
self.updateInputModeAndDismissedButtonKeyboardMessageId = updateInputModeAndDismissedButtonKeyboardMessageId
|
self.updateInputModeAndDismissedButtonKeyboardMessageId = updateInputModeAndDismissedButtonKeyboardMessageId
|
||||||
@ -391,7 +396,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||||||
self.joinGroupCall = joinGroupCall
|
self.joinGroupCall = joinGroupCall
|
||||||
self.presentInviteMembers = presentInviteMembers
|
self.presentInviteMembers = presentInviteMembers
|
||||||
self.presentGigagroupHelp = presentGigagroupHelp
|
self.presentGigagroupHelp = presentGigagroupHelp
|
||||||
self.openSuggestPost = openSuggestPost
|
self.openMonoforum = openMonoforum
|
||||||
self.updateShowCommands = updateShowCommands
|
self.updateShowCommands = updateShowCommands
|
||||||
self.updateShowSendAsPeers = updateShowSendAsPeers
|
self.updateShowSendAsPeers = updateShowSendAsPeers
|
||||||
self.openInviteRequests = openInviteRequests
|
self.openInviteRequests = openInviteRequests
|
||||||
@ -408,6 +413,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||||||
self.addDoNotTranslateLanguage = addDoNotTranslateLanguage
|
self.addDoNotTranslateLanguage = addDoNotTranslateLanguage
|
||||||
self.hideTranslationPanel = hideTranslationPanel
|
self.hideTranslationPanel = hideTranslationPanel
|
||||||
self.openPremiumGift = openPremiumGift
|
self.openPremiumGift = openPremiumGift
|
||||||
|
self.openSuggestPost = openSuggestPost
|
||||||
self.openPremiumRequiredForMessaging = openPremiumRequiredForMessaging
|
self.openPremiumRequiredForMessaging = openPremiumRequiredForMessaging
|
||||||
self.openStarsPurchase = openStarsPurchase
|
self.openStarsPurchase = openStarsPurchase
|
||||||
self.openMessagePayment = openMessagePayment
|
self.openMessagePayment = openMessagePayment
|
||||||
@ -447,6 +453,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||||||
}, presentForwardOptions: { _ in
|
}, presentForwardOptions: { _ in
|
||||||
}, presentReplyOptions: { _ in
|
}, presentReplyOptions: { _ in
|
||||||
}, presentLinkOptions: { _ in
|
}, presentLinkOptions: { _ in
|
||||||
|
}, presentSuggestPostOptions: {
|
||||||
}, shareSelectedMessages: {
|
}, shareSelectedMessages: {
|
||||||
}, updateTextInputStateAndMode: updateTextInputStateAndMode, updateInputModeAndDismissedButtonKeyboardMessageId: updateInputModeAndDismissedButtonKeyboardMessageId, openStickers: {
|
}, updateTextInputStateAndMode: updateTextInputStateAndMode, updateInputModeAndDismissedButtonKeyboardMessageId: updateInputModeAndDismissedButtonKeyboardMessageId, openStickers: {
|
||||||
}, editMessage: {
|
}, editMessage: {
|
||||||
@ -519,7 +526,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||||||
}, joinGroupCall: { _ in
|
}, joinGroupCall: { _ in
|
||||||
}, presentInviteMembers: {
|
}, presentInviteMembers: {
|
||||||
}, presentGigagroupHelp: {
|
}, presentGigagroupHelp: {
|
||||||
}, openSuggestPost: {
|
}, openMonoforum: {
|
||||||
}, editMessageMedia: { _, _ in
|
}, editMessageMedia: { _, _ in
|
||||||
}, updateShowCommands: { _ in
|
}, updateShowCommands: { _ in
|
||||||
}, updateShowSendAsPeers: { _ in
|
}, updateShowSendAsPeers: { _ in
|
||||||
@ -537,6 +544,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||||||
}, addDoNotTranslateLanguage: { _ in
|
}, addDoNotTranslateLanguage: { _ in
|
||||||
}, hideTranslationPanel: {
|
}, hideTranslationPanel: {
|
||||||
}, openPremiumGift: {
|
}, openPremiumGift: {
|
||||||
|
}, openSuggestPost: {
|
||||||
}, openPremiumRequiredForMessaging: {
|
}, openPremiumRequiredForMessaging: {
|
||||||
}, openStarsPurchase: { _ in
|
}, openStarsPurchase: { _ in
|
||||||
}, openMessagePayment: {
|
}, openMessagePayment: {
|
||||||
|
|||||||
@ -11,6 +11,7 @@ public enum ChatTextInputAccessoryItem: Equatable {
|
|||||||
case messageAutoremoveTimeout
|
case messageAutoremoveTimeout
|
||||||
case scheduledMessages
|
case scheduledMessages
|
||||||
case gift
|
case gift
|
||||||
|
case suggestPost
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum InputMode: Hashable {
|
public enum InputMode: Hashable {
|
||||||
@ -27,6 +28,7 @@ public enum ChatTextInputAccessoryItem: Equatable {
|
|||||||
case messageAutoremoveTimeout(Int32?)
|
case messageAutoremoveTimeout(Int32?)
|
||||||
case scheduledMessages
|
case scheduledMessages
|
||||||
case gift
|
case gift
|
||||||
|
case suggestPost
|
||||||
|
|
||||||
public var key: Key {
|
public var key: Key {
|
||||||
switch self {
|
switch self {
|
||||||
@ -44,6 +46,8 @@ public enum ChatTextInputAccessoryItem: Equatable {
|
|||||||
return .scheduledMessages
|
return .scheduledMessages
|
||||||
case .gift:
|
case .gift:
|
||||||
return .gift
|
return .gift
|
||||||
|
case .suggestPost:
|
||||||
|
return .suggestPost
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -376,13 +376,18 @@ public func incomingMessagePrivacyScreen(context: AccountContext, value: GlobalP
|
|||||||
if case let .paidMessages(value) = stateValue.with({ $0 }).updatedValue {
|
if case let .paidMessages(value) = stateValue.with({ $0 }).updatedValue {
|
||||||
currentAmount = value
|
currentAmount = value
|
||||||
}
|
}
|
||||||
let starsScreen = context.sharedContext.makeStarsWithdrawalScreen(context: context, subject: .enterAmount(current: currentAmount, minValue: StarsAmount(value: 1, nanos: 0), fractionAfterCommission: 80, kind: .privacy), completion: { amount in
|
let starsScreen = context.sharedContext.makeStarsWithdrawalScreen(context: context, subject: .enterAmount(
|
||||||
|
current: currentAmount,
|
||||||
|
minValue: StarsAmount(value: 1, nanos: 0),
|
||||||
|
fractionAfterCommission: 80, kind: .privacy,
|
||||||
|
completion: { amount in
|
||||||
updateState { state in
|
updateState { state in
|
||||||
var state = state
|
var state = state
|
||||||
state.updatedValue = .paidMessages(StarsAmount(value: amount, nanos: 0))
|
state.updatedValue = .paidMessages(StarsAmount(value: amount, nanos: 0))
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
))
|
||||||
pushControllerImpl?(starsScreen)
|
pushControllerImpl?(starsScreen)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@ -68,6 +68,7 @@ public struct MessageHistoryThreadData: Codable, Equatable {
|
|||||||
case isHidden
|
case isHidden
|
||||||
case notificationSettings
|
case notificationSettings
|
||||||
case isMarkedUnread
|
case isMarkedUnread
|
||||||
|
case isMessageFeeRemoved
|
||||||
}
|
}
|
||||||
|
|
||||||
public var creationDate: Int32
|
public var creationDate: Int32
|
||||||
@ -82,6 +83,7 @@ public struct MessageHistoryThreadData: Codable, Equatable {
|
|||||||
public var isClosed: Bool
|
public var isClosed: Bool
|
||||||
public var isHidden: Bool
|
public var isHidden: Bool
|
||||||
public var notificationSettings: TelegramPeerNotificationSettings
|
public var notificationSettings: TelegramPeerNotificationSettings
|
||||||
|
public var isMessageFeeRemoved: Bool
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
creationDate: Int32,
|
creationDate: Int32,
|
||||||
@ -95,7 +97,8 @@ public struct MessageHistoryThreadData: Codable, Equatable {
|
|||||||
maxOutgoingReadId: Int32,
|
maxOutgoingReadId: Int32,
|
||||||
isClosed: Bool,
|
isClosed: Bool,
|
||||||
isHidden: Bool,
|
isHidden: Bool,
|
||||||
notificationSettings: TelegramPeerNotificationSettings
|
notificationSettings: TelegramPeerNotificationSettings,
|
||||||
|
isMessageFeeRemoved: Bool
|
||||||
) {
|
) {
|
||||||
self.creationDate = creationDate
|
self.creationDate = creationDate
|
||||||
self.isOwnedByMe = isOwnedByMe
|
self.isOwnedByMe = isOwnedByMe
|
||||||
@ -109,6 +112,7 @@ public struct MessageHistoryThreadData: Codable, Equatable {
|
|||||||
self.isClosed = isClosed
|
self.isClosed = isClosed
|
||||||
self.isHidden = isHidden
|
self.isHidden = isHidden
|
||||||
self.notificationSettings = notificationSettings
|
self.notificationSettings = notificationSettings
|
||||||
|
self.isMessageFeeRemoved = isMessageFeeRemoved
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(from decoder: Decoder) throws {
|
public init(from decoder: Decoder) throws {
|
||||||
@ -126,6 +130,7 @@ public struct MessageHistoryThreadData: Codable, Equatable {
|
|||||||
self.isClosed = try container.decodeIfPresent(Bool.self, forKey: .isClosed) ?? false
|
self.isClosed = try container.decodeIfPresent(Bool.self, forKey: .isClosed) ?? false
|
||||||
self.isHidden = try container.decodeIfPresent(Bool.self, forKey: .isHidden) ?? false
|
self.isHidden = try container.decodeIfPresent(Bool.self, forKey: .isHidden) ?? false
|
||||||
self.notificationSettings = try container.decode(TelegramPeerNotificationSettings.self, forKey: .notificationSettings)
|
self.notificationSettings = try container.decode(TelegramPeerNotificationSettings.self, forKey: .notificationSettings)
|
||||||
|
self.isMessageFeeRemoved = try container.decodeIfPresent(Bool.self, forKey: .isMessageFeeRemoved) ?? false
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(to encoder: Encoder) throws {
|
public func encode(to encoder: Encoder) throws {
|
||||||
@ -143,6 +148,7 @@ public struct MessageHistoryThreadData: Codable, Equatable {
|
|||||||
try container.encode(self.isClosed, forKey: .isClosed)
|
try container.encode(self.isClosed, forKey: .isClosed)
|
||||||
try container.encode(self.isHidden, forKey: .isHidden)
|
try container.encode(self.isHidden, forKey: .isHidden)
|
||||||
try container.encode(self.notificationSettings, forKey: .notificationSettings)
|
try container.encode(self.notificationSettings, forKey: .notificationSettings)
|
||||||
|
try container.encode(self.isMessageFeeRemoved, forKey: .isMessageFeeRemoved)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -668,7 +674,8 @@ public func _internal_fillSavedMessageHistory(accountPeerId: PeerId, postbox: Po
|
|||||||
maxOutgoingReadId: 0,
|
maxOutgoingReadId: 0,
|
||||||
isClosed: false,
|
isClosed: false,
|
||||||
isHidden: false,
|
isHidden: false,
|
||||||
notificationSettings: TelegramPeerNotificationSettings.defaultSettings
|
notificationSettings: TelegramPeerNotificationSettings.defaultSettings,
|
||||||
|
isMessageFeeRemoved: false
|
||||||
),
|
),
|
||||||
topMessage: message.id.id,
|
topMessage: message.id.id,
|
||||||
unreadMentionsCount: 0,
|
unreadMentionsCount: 0,
|
||||||
@ -786,7 +793,8 @@ func _internal_requestMessageHistoryThreads(accountPeerId: PeerId, postbox: Post
|
|||||||
maxOutgoingReadId: 0,
|
maxOutgoingReadId: 0,
|
||||||
isClosed: false,
|
isClosed: false,
|
||||||
isHidden: false,
|
isHidden: false,
|
||||||
notificationSettings: TelegramPeerNotificationSettings.defaultSettings
|
notificationSettings: TelegramPeerNotificationSettings.defaultSettings,
|
||||||
|
isMessageFeeRemoved: false
|
||||||
)
|
)
|
||||||
|
|
||||||
var topTimestamp: Int32 = 1
|
var topTimestamp: Int32 = 1
|
||||||
@ -840,7 +848,8 @@ func _internal_requestMessageHistoryThreads(accountPeerId: PeerId, postbox: Post
|
|||||||
maxOutgoingReadId: readOutboxMaxId,
|
maxOutgoingReadId: readOutboxMaxId,
|
||||||
isClosed: false,
|
isClosed: false,
|
||||||
isHidden: false,
|
isHidden: false,
|
||||||
notificationSettings: TelegramPeerNotificationSettings.defaultSettings
|
notificationSettings: TelegramPeerNotificationSettings.defaultSettings,
|
||||||
|
isMessageFeeRemoved: (flags & (1 << 4)) != 0
|
||||||
)
|
)
|
||||||
|
|
||||||
var topTimestamp: Int32 = 1
|
var topTimestamp: Int32 = 1
|
||||||
@ -989,7 +998,8 @@ func _internal_requestMessageHistoryThreads(accountPeerId: PeerId, postbox: Post
|
|||||||
maxOutgoingReadId: readOutboxMaxId,
|
maxOutgoingReadId: readOutboxMaxId,
|
||||||
isClosed: (flags & (1 << 2)) != 0,
|
isClosed: (flags & (1 << 2)) != 0,
|
||||||
isHidden: (flags & (1 << 6)) != 0,
|
isHidden: (flags & (1 << 6)) != 0,
|
||||||
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings)
|
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings),
|
||||||
|
isMessageFeeRemoved: false
|
||||||
)
|
)
|
||||||
|
|
||||||
var topTimestamp = date
|
var topTimestamp = date
|
||||||
|
|||||||
@ -2107,7 +2107,8 @@ func resolveForumThreads(accountPeerId: PeerId, postbox: Postbox, source: FetchM
|
|||||||
maxOutgoingReadId: readOutboxMaxId,
|
maxOutgoingReadId: readOutboxMaxId,
|
||||||
isClosed: (flags & (1 << 2)) != 0,
|
isClosed: (flags & (1 << 2)) != 0,
|
||||||
isHidden: (flags & (1 << 6)) != 0,
|
isHidden: (flags & (1 << 6)) != 0,
|
||||||
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings)
|
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings),
|
||||||
|
isMessageFeeRemoved: false
|
||||||
),
|
),
|
||||||
topMessageId: topMessage,
|
topMessageId: topMessage,
|
||||||
unreadMentionCount: unreadMentionsCount,
|
unreadMentionCount: unreadMentionsCount,
|
||||||
@ -2140,7 +2141,8 @@ func resolveForumThreads(accountPeerId: PeerId, postbox: Postbox, source: FetchM
|
|||||||
maxOutgoingReadId: readOutboxMaxId,
|
maxOutgoingReadId: readOutboxMaxId,
|
||||||
isClosed: false,
|
isClosed: false,
|
||||||
isHidden: false,
|
isHidden: false,
|
||||||
notificationSettings: TelegramPeerNotificationSettings.defaultSettings
|
notificationSettings: TelegramPeerNotificationSettings.defaultSettings,
|
||||||
|
isMessageFeeRemoved: (flags & (1 << 4)) != 0
|
||||||
),
|
),
|
||||||
topMessageId: topMessage,
|
topMessageId: topMessage,
|
||||||
unreadMentionCount: 0,
|
unreadMentionCount: 0,
|
||||||
@ -2266,7 +2268,8 @@ func resolveForumThreads(accountPeerId: PeerId, postbox: Postbox, source: FetchM
|
|||||||
maxOutgoingReadId: readOutboxMaxId,
|
maxOutgoingReadId: readOutboxMaxId,
|
||||||
isClosed: (flags & (1 << 2)) != 0,
|
isClosed: (flags & (1 << 2)) != 0,
|
||||||
isHidden: (flags & (1 << 6)) != 0,
|
isHidden: (flags & (1 << 6)) != 0,
|
||||||
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings)
|
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings),
|
||||||
|
isMessageFeeRemoved: false
|
||||||
)
|
)
|
||||||
if let entry = StoredMessageHistoryThreadInfo(data) {
|
if let entry = StoredMessageHistoryThreadInfo(data) {
|
||||||
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: Int64(id), info: entry)
|
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: Int64(id), info: entry)
|
||||||
@ -2296,7 +2299,8 @@ func resolveForumThreads(accountPeerId: PeerId, postbox: Postbox, source: FetchM
|
|||||||
maxOutgoingReadId: readOutboxMaxId,
|
maxOutgoingReadId: readOutboxMaxId,
|
||||||
isClosed: false,
|
isClosed: false,
|
||||||
isHidden: false,
|
isHidden: false,
|
||||||
notificationSettings: TelegramPeerNotificationSettings.defaultSettings
|
notificationSettings: TelegramPeerNotificationSettings.defaultSettings,
|
||||||
|
isMessageFeeRemoved: (flags & (1 << 4)) != 0
|
||||||
)
|
)
|
||||||
if let entry = StoredMessageHistoryThreadInfo(data) {
|
if let entry = StoredMessageHistoryThreadInfo(data) {
|
||||||
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: peer.peerId.toInt64(), info: entry)
|
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: peer.peerId.toInt64(), info: entry)
|
||||||
@ -2429,7 +2433,8 @@ func resolveForumThreads(accountPeerId: PeerId, postbox: Postbox, source: FetchM
|
|||||||
maxOutgoingReadId: readOutboxMaxId,
|
maxOutgoingReadId: readOutboxMaxId,
|
||||||
isClosed: (flags & (1 << 2)) != 0,
|
isClosed: (flags & (1 << 2)) != 0,
|
||||||
isHidden: (flags & (1 << 6)) != 0,
|
isHidden: (flags & (1 << 6)) != 0,
|
||||||
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings)
|
notificationSettings: TelegramPeerNotificationSettings(apiSettings: notifySettings),
|
||||||
|
isMessageFeeRemoved: false
|
||||||
),
|
),
|
||||||
topMessageId: topMessage,
|
topMessageId: topMessage,
|
||||||
unreadMentionCount: unreadMentionsCount,
|
unreadMentionCount: unreadMentionsCount,
|
||||||
@ -2459,7 +2464,8 @@ func resolveForumThreads(accountPeerId: PeerId, postbox: Postbox, source: FetchM
|
|||||||
maxOutgoingReadId: readOutboxMaxId,
|
maxOutgoingReadId: readOutboxMaxId,
|
||||||
isClosed: false,
|
isClosed: false,
|
||||||
isHidden: false,
|
isHidden: false,
|
||||||
notificationSettings: TelegramPeerNotificationSettings.defaultSettings
|
notificationSettings: TelegramPeerNotificationSettings.defaultSettings,
|
||||||
|
isMessageFeeRemoved: (flags & (1 << 4)) != 0
|
||||||
),
|
),
|
||||||
topMessageId: topMessage,
|
topMessageId: topMessage,
|
||||||
unreadMentionCount: 0,
|
unreadMentionCount: 0,
|
||||||
|
|||||||
@ -3,15 +3,26 @@ import TelegramApi
|
|||||||
import Postbox
|
import Postbox
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
|
|
||||||
func _internal_getPaidMessagesRevenue(account: Account, peerId: PeerId) -> Signal<StarsAmount?, NoError> {
|
func _internal_getPaidMessagesRevenue(account: Account, scopePeerId: PeerId, peerId: PeerId) -> Signal<StarsAmount?, NoError> {
|
||||||
return account.postbox.transaction { transaction -> Api.InputUser? in
|
return account.postbox.transaction { transaction -> (Api.InputPeer?, Api.InputUser?) in
|
||||||
return transaction.getPeer(peerId).flatMap(apiInputUser)
|
return (transaction.getPeer(scopePeerId).flatMap(apiInputPeer), transaction.getPeer(peerId).flatMap(apiInputUser))
|
||||||
|
}
|
||||||
|
|> mapToSignal { scopeInputPeer, inputUser -> Signal<StarsAmount?, NoError> in
|
||||||
|
if scopePeerId != account.peerId {
|
||||||
|
if scopeInputPeer == nil {
|
||||||
|
return .never()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|> mapToSignal { inputUser -> Signal<StarsAmount?, NoError> in
|
|
||||||
guard let inputUser else {
|
guard let inputUser else {
|
||||||
return .single(nil)
|
return .single(nil)
|
||||||
}
|
}
|
||||||
return account.network.request(Api.functions.account.getPaidMessagesRevenue(flags: 0, parentPeer: nil, userId: inputUser))
|
|
||||||
|
var flags: Int32 = 0
|
||||||
|
if scopePeerId != account.peerId, scopeInputPeer != nil {
|
||||||
|
flags |= 1 << 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return account.network.request(Api.functions.account.getPaidMessagesRevenue(flags: 0, parentPeer: scopeInputPeer, userId: inputUser))
|
||||||
|> map(Optional.init)
|
|> map(Optional.init)
|
||||||
|> `catch` { _ -> Signal<Api.account.PaidMessagesRevenue?, NoError> in
|
|> `catch` { _ -> Signal<Api.account.PaidMessagesRevenue?, NoError> in
|
||||||
return .single(nil)
|
return .single(nil)
|
||||||
@ -28,11 +39,16 @@ func _internal_getPaidMessagesRevenue(account: Account, peerId: PeerId) -> Signa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func _internal_addNoPaidMessagesException(account: Account, peerId: PeerId, refundCharged: Bool) -> Signal<Never, NoError> {
|
func _internal_addNoPaidMessagesException(account: Account, scopePeerId: PeerId, peerId: PeerId, refundCharged: Bool) -> Signal<Never, NoError> {
|
||||||
return account.postbox.transaction { transaction -> Api.InputUser? in
|
return account.postbox.transaction { transaction -> (Api.InputPeer?, Api.InputUser?) in
|
||||||
return transaction.getPeer(peerId).flatMap(apiInputUser)
|
return (transaction.getPeer(scopePeerId).flatMap(apiInputPeer), transaction.getPeer(peerId).flatMap(apiInputUser))
|
||||||
|
}
|
||||||
|
|> mapToSignal { scopeInputPeer, inputUser -> Signal<Never, NoError> in
|
||||||
|
if scopePeerId != account.peerId {
|
||||||
|
if scopeInputPeer == nil {
|
||||||
|
return .never()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|> mapToSignal { inputUser -> Signal<Never, NoError> in
|
|
||||||
guard let inputUser else {
|
guard let inputUser else {
|
||||||
return .never()
|
return .never()
|
||||||
}
|
}
|
||||||
@ -40,11 +56,24 @@ func _internal_addNoPaidMessagesException(account: Account, peerId: PeerId, refu
|
|||||||
if refundCharged {
|
if refundCharged {
|
||||||
flags |= (1 << 0)
|
flags |= (1 << 0)
|
||||||
}
|
}
|
||||||
return account.network.request(Api.functions.account.toggleNoPaidMessagesException(flags: flags, parentPeer: nil, userId: inputUser))
|
if scopePeerId != account.peerId, scopeInputPeer != nil {
|
||||||
|
flags |= (1 << 1)
|
||||||
|
}
|
||||||
|
return account.network.request(Api.functions.account.toggleNoPaidMessagesException(flags: flags, parentPeer: scopeInputPeer, userId: inputUser))
|
||||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||||
return .single(.boolFalse)
|
return .single(.boolFalse)
|
||||||
} |> mapToSignal { _ in
|
} |> mapToSignal { _ in
|
||||||
return account.postbox.transaction { transaction -> Void in
|
return account.postbox.transaction { transaction -> Void in
|
||||||
|
if scopePeerId != account.peerId, scopeInputPeer != nil {
|
||||||
|
guard var data = transaction.getMessageHistoryThreadInfo(peerId: scopePeerId, threadId: peerId.toInt64())?.data.get(MessageHistoryThreadData.self) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data.isMessageFeeRemoved = true
|
||||||
|
|
||||||
|
if let entry = StoredMessageHistoryThreadInfo(data) {
|
||||||
|
transaction.setMessageHistoryThreadInfo(peerId: scopePeerId, threadId: peerId.toInt64(), info: entry)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData in
|
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData in
|
||||||
if let cachedData = cachedData as? CachedUserData {
|
if let cachedData = cachedData as? CachedUserData {
|
||||||
var settings = cachedData.peerStatusSettings ?? .init()
|
var settings = cachedData.peerStatusSettings ?? .init()
|
||||||
@ -54,6 +83,7 @@ func _internal_addNoPaidMessagesException(account: Account, peerId: PeerId, refu
|
|||||||
return cachedData
|
return cachedData
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|> ignoreValues
|
|> ignoreValues
|
||||||
}
|
}
|
||||||
|> ignoreValues
|
|> ignoreValues
|
||||||
|
|||||||
@ -1494,12 +1494,12 @@ public extension TelegramEngine {
|
|||||||
return _internal_applyChannelBoost(account: self.account, peerId: peerId, slots: slots)
|
return _internal_applyChannelBoost(account: self.account, peerId: peerId, slots: slots)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getPaidMessagesRevenue(peerId: EnginePeer.Id) -> Signal<StarsAmount?, NoError> {
|
public func getPaidMessagesRevenue(scopePeerId: EnginePeer.Id, peerId: EnginePeer.Id) -> Signal<StarsAmount?, NoError> {
|
||||||
return _internal_getPaidMessagesRevenue(account: self.account, peerId: peerId)
|
return _internal_getPaidMessagesRevenue(account: self.account, scopePeerId: scopePeerId, peerId: peerId)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func addNoPaidMessagesException(peerId: EnginePeer.Id, refundCharged: Bool) -> Signal<Never, NoError> {
|
public func addNoPaidMessagesException(scopePeerId: EnginePeer.Id, peerId: EnginePeer.Id, refundCharged: Bool) -> Signal<Never, NoError> {
|
||||||
return _internal_addNoPaidMessagesException(account: self.account, peerId: peerId, refundCharged: refundCharged)
|
return _internal_addNoPaidMessagesException(account: self.account, scopePeerId: scopePeerId, peerId: peerId, refundCharged: refundCharged)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func updateChannelPaidMessagesStars(peerId: EnginePeer.Id, stars: StarsAmount?, broadcastMessagesAllowed: Bool) -> Signal<Never, NoError> {
|
public func updateChannelPaidMessagesStars(peerId: EnginePeer.Id, stars: StarsAmount?, broadcastMessagesAllowed: Bool) -> Signal<Never, NoError> {
|
||||||
|
|||||||
@ -224,6 +224,7 @@ public enum PresentationResourceKey: Int32 {
|
|||||||
case chatInputTextFieldTimerImage
|
case chatInputTextFieldTimerImage
|
||||||
case chatInputTextFieldScheduleImage
|
case chatInputTextFieldScheduleImage
|
||||||
case chatInputTextFieldGiftImage
|
case chatInputTextFieldGiftImage
|
||||||
|
case chatInputTextFieldSuggestPostImage
|
||||||
|
|
||||||
case chatInputSearchPanelUpImage
|
case chatInputSearchPanelUpImage
|
||||||
case chatInputSearchPanelUpDisabledImage
|
case chatInputSearchPanelUpDisabledImage
|
||||||
|
|||||||
@ -562,6 +562,12 @@ public struct PresentationResourcesChat {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func chatInputTextFieldSuggestPostImage(_ theme: PresentationTheme) -> UIImage? {
|
||||||
|
return theme.image(PresentationResourceKey.chatInputTextFieldSuggestPostImage.rawValue, { theme in
|
||||||
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Text/AccessoryIconSuggestPost"), color: theme.chat.inputPanel.inputControlColor)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
public static func chatInputTextFieldKeyboardImage(_ theme: PresentationTheme) -> UIImage? {
|
public static func chatInputTextFieldKeyboardImage(_ theme: PresentationTheme) -> UIImage? {
|
||||||
return theme.image(PresentationResourceKey.chatInputTextFieldKeyboardImage.rawValue, { theme in
|
return theme.image(PresentationResourceKey.chatInputTextFieldKeyboardImage.rawValue, { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Text/AccessoryIconKeyboard"), color: theme.chat.inputPanel.inputControlColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Text/AccessoryIconKeyboard"), color: theme.chat.inputPanel.inputControlColor)
|
||||||
|
|||||||
@ -228,7 +228,7 @@ public final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc private func suggestedPostPressed() {
|
@objc private func suggestedPostPressed() {
|
||||||
self.interfaceInteraction?.openSuggestPost()
|
self.interfaceInteraction?.openMonoforum()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func buttonPressed() {
|
@objc private func buttonPressed() {
|
||||||
|
|||||||
@ -109,7 +109,7 @@ public final class ChatLoadingPlaceholderMessageContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func update(size: CGSize, hasAvatar: Bool, rect: CGRect, transition: ContainedViewLayoutTransition) {
|
public func update(size: CGSize, isSidebarOpen: Bool, hasAvatar: Bool, rect: CGRect, transition: ContainedViewLayoutTransition) {
|
||||||
var avatarOffset: CGFloat = 0.0
|
var avatarOffset: CGFloat = 0.0
|
||||||
|
|
||||||
if hasAvatar && self.avatarNode == nil {
|
if hasAvatar && self.avatarNode == nil {
|
||||||
@ -127,13 +127,25 @@ public final class ChatLoadingPlaceholderMessageContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let avatarNode = self.avatarNode, let avatarBorderNode = self.avatarBorderNode {
|
if let avatarNode = self.avatarNode, let avatarBorderNode = self.avatarBorderNode {
|
||||||
let avatarFrame = CGRect(origin: CGPoint(x: rect.minX + 3.0, y: rect.maxY + 1.0 - avatarSize.height), size: avatarSize)
|
var avatarFrame = CGRect(origin: CGPoint(x: rect.minX + 3.0, y: rect.maxY + 1.0 - avatarSize.height), size: avatarSize)
|
||||||
|
if isSidebarOpen {
|
||||||
|
avatarFrame.origin.x -= avatarFrame.width * 0.5
|
||||||
|
avatarFrame.origin.y += avatarFrame.height * 0.5
|
||||||
|
}
|
||||||
|
|
||||||
transition.updateFrame(node: avatarNode, frame: avatarFrame)
|
transition.updatePosition(node: avatarNode, position: avatarFrame.center)
|
||||||
transition.updateFrame(node: avatarBorderNode, frame: avatarFrame)
|
transition.updateBounds(node: avatarNode, bounds: CGRect(origin: CGPoint(), size: avatarFrame.size))
|
||||||
|
transition.updateTransformScale(node: avatarNode, scale: isSidebarOpen ? 0.001 : 1.0)
|
||||||
|
transition.updateAlpha(node: avatarNode, alpha: isSidebarOpen ? 0.0 : 1.0)
|
||||||
|
transition.updatePosition(node: avatarBorderNode, position: avatarFrame.center)
|
||||||
|
transition.updateBounds(node: avatarBorderNode, bounds: CGRect(origin: CGPoint(), size: avatarFrame.size))
|
||||||
|
transition.updateTransformScale(node: avatarBorderNode, scale: isSidebarOpen ? 0.001 : 1.0)
|
||||||
|
transition.updateAlpha(node: avatarBorderNode, alpha: isSidebarOpen ? 0.0 : 1.0)
|
||||||
|
|
||||||
|
if !isSidebarOpen {
|
||||||
avatarOffset += avatarSize.width - 1.0
|
avatarOffset += avatarSize.width - 1.0
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let bubbleFrame = CGRect(origin: CGPoint(x: rect.minX + 3.0 + avatarOffset, y: rect.origin.y), size: CGSize(width: rect.width, height: rect.height))
|
let bubbleFrame = CGRect(origin: CGPoint(x: rect.minX + 3.0 + avatarOffset, y: rect.origin.y), size: CGSize(width: rect.width, height: rect.height))
|
||||||
transition.updateFrame(node: self.bubbleNode, frame: bubbleFrame)
|
transition.updateFrame(node: self.bubbleNode, frame: bubbleFrame)
|
||||||
@ -161,7 +173,7 @@ public final class ChatLoadingPlaceholderNode: ASDisplayNode {
|
|||||||
|
|
||||||
private var absolutePosition: (CGRect, CGSize)?
|
private var absolutePosition: (CGRect, CGSize)?
|
||||||
|
|
||||||
private var validLayout: (CGSize, UIEdgeInsets, LayoutMetrics)?
|
private var validLayout: (CGSize, Bool, UIEdgeInsets, LayoutMetrics)?
|
||||||
|
|
||||||
public init(context: AccountContext, theme: PresentationTheme, chatWallpaper: TelegramWallpaper, bubbleCorners: PresentationChatBubbleCorners, backgroundNode: WallpaperBackgroundNode) {
|
public init(context: AccountContext, theme: PresentationTheme, chatWallpaper: TelegramWallpaper, bubbleCorners: PresentationChatBubbleCorners, backgroundNode: WallpaperBackgroundNode) {
|
||||||
self.context = context
|
self.context = context
|
||||||
@ -295,7 +307,7 @@ public final class ChatLoadingPlaceholderNode: ASDisplayNode {
|
|||||||
|
|
||||||
private var didAnimateOut = false
|
private var didAnimateOut = false
|
||||||
public func animateOut(_ historyNode: ListView, completion: @escaping () -> Void = {}) {
|
public func animateOut(_ historyNode: ListView, completion: @escaping () -> Void = {}) {
|
||||||
guard let (size, _, _) = self.validLayout else {
|
guard let (size, isSidebarOpen, _, _) = self.validLayout else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let listNode = historyNode
|
let listNode = historyNode
|
||||||
@ -376,7 +388,7 @@ public final class ChatLoadingPlaceholderNode: ASDisplayNode {
|
|||||||
let messageContainer = self.messageContainers[k]
|
let messageContainer = self.messageContainers[k]
|
||||||
let messageSize = messageContainer.frame.size
|
let messageSize = messageContainer.frame.size
|
||||||
|
|
||||||
messageContainer.update(size: size, hasAvatar: self.chatType != .channel && self.chatType != .user, rect: CGRect(origin: CGPoint(x: 0.0, y: offset - messageSize.height), size: messageSize), transition: transition)
|
messageContainer.update(size: size, isSidebarOpen: isSidebarOpen, hasAvatar: self.chatType != .channel && self.chatType != .user, rect: CGRect(origin: CGPoint(x: 0.0, y: offset - messageSize.height), size: messageSize), transition: transition)
|
||||||
offset -= messageSize.height
|
offset -= messageSize.height
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -439,14 +451,14 @@ public final class ChatLoadingPlaceholderNode: ASDisplayNode {
|
|||||||
|
|
||||||
if self.chatType != chatType {
|
if self.chatType != chatType {
|
||||||
self.chatType = chatType
|
self.chatType = chatType
|
||||||
if let (size, insets, metrics) = self.validLayout {
|
if let (size, isSidebarOpen, insets, metrics) = self.validLayout {
|
||||||
self.updateLayout(size: size, insets: insets, metrics: metrics, transition: .immediate)
|
self.updateLayout(size: size, isSidebarOpen: isSidebarOpen, insets: insets, metrics: metrics, transition: .immediate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func updateLayout(size: CGSize, insets: UIEdgeInsets, metrics: LayoutMetrics, transition: ContainedViewLayoutTransition) {
|
public func updateLayout(size: CGSize, isSidebarOpen: Bool, insets: UIEdgeInsets, metrics: LayoutMetrics, transition: ContainedViewLayoutTransition) {
|
||||||
self.validLayout = (size, insets, metrics)
|
self.validLayout = (size, isSidebarOpen, insets, metrics)
|
||||||
|
|
||||||
let bounds = CGRect(origin: .zero, size: size)
|
let bounds = CGRect(origin: .zero, size: size)
|
||||||
|
|
||||||
@ -500,7 +512,7 @@ public final class ChatLoadingPlaceholderNode: ASDisplayNode {
|
|||||||
|
|
||||||
for messageContainer in self.messageContainers {
|
for messageContainer in self.messageContainers {
|
||||||
let messageSize = dimensions[index % 14]
|
let messageSize = dimensions[index % 14]
|
||||||
messageContainer.update(size: bounds.size, hasAvatar: self.chatType != .channel && self.chatType != .user, rect: CGRect(origin: CGPoint(x: insets.left, y: bounds.size.height - insets.bottom - offset - messageSize.height), size: messageSize), transition: transition)
|
messageContainer.update(size: bounds.size, isSidebarOpen: isSidebarOpen, hasAvatar: self.chatType != .channel && self.chatType != .user, rect: CGRect(origin: CGPoint(x: insets.left, y: bounds.size.height - insets.bottom - offset - messageSize.height), size: messageSize), transition: transition)
|
||||||
offset += messageSize.height
|
offset += messageSize.height
|
||||||
index += 1
|
index += 1
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2436,8 +2436,12 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||||||
|
|
||||||
if isSidePanelOpen && incoming {
|
if isSidePanelOpen && incoming {
|
||||||
hasTitleAvatar = true
|
hasTitleAvatar = true
|
||||||
|
|
||||||
|
if let channel = item.message.peers[item.message.id.peerId], channel.isMonoForum {
|
||||||
|
} else {
|
||||||
hasTitleTopicNavigation = item.chatLocation.threadId == nil
|
hasTitleTopicNavigation = item.chatLocation.threadId == nil
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let inlineBotNameColor = messageTheme.accentTextColor
|
let inlineBotNameColor = messageTheme.accentTextColor
|
||||||
|
|
||||||
|
|||||||
@ -72,6 +72,7 @@ public final class ChatRecentActionsController: TelegramBaseController {
|
|||||||
}, presentForwardOptions: { _ in
|
}, presentForwardOptions: { _ in
|
||||||
}, presentReplyOptions: { _ in
|
}, presentReplyOptions: { _ in
|
||||||
}, presentLinkOptions: { _ in
|
}, presentLinkOptions: { _ in
|
||||||
|
}, presentSuggestPostOptions: {
|
||||||
}, shareSelectedMessages: {
|
}, shareSelectedMessages: {
|
||||||
}, updateTextInputStateAndMode: { _ in
|
}, updateTextInputStateAndMode: { _ in
|
||||||
}, updateInputModeAndDismissedButtonKeyboardMessageId: { _ in
|
}, updateInputModeAndDismissedButtonKeyboardMessageId: { _ in
|
||||||
@ -146,7 +147,7 @@ public final class ChatRecentActionsController: TelegramBaseController {
|
|||||||
}, joinGroupCall: { _ in
|
}, joinGroupCall: { _ in
|
||||||
}, presentInviteMembers: {
|
}, presentInviteMembers: {
|
||||||
}, presentGigagroupHelp: {
|
}, presentGigagroupHelp: {
|
||||||
}, openSuggestPost: {
|
}, openMonoforum: {
|
||||||
}, editMessageMedia: { _, _ in
|
}, editMessageMedia: { _, _ in
|
||||||
}, updateShowCommands: { _ in
|
}, updateShowCommands: { _ in
|
||||||
}, updateShowSendAsPeers: { _ in
|
}, updateShowSendAsPeers: { _ in
|
||||||
@ -164,6 +165,7 @@ public final class ChatRecentActionsController: TelegramBaseController {
|
|||||||
}, addDoNotTranslateLanguage: { _ in
|
}, addDoNotTranslateLanguage: { _ in
|
||||||
}, hideTranslationPanel: {
|
}, hideTranslationPanel: {
|
||||||
}, openPremiumGift: {
|
}, openPremiumGift: {
|
||||||
|
}, openSuggestPost: {
|
||||||
}, openPremiumRequiredForMessaging: {
|
}, openPremiumRequiredForMessaging: {
|
||||||
}, openStarsPurchase: { _ in
|
}, openStarsPurchase: { _ in
|
||||||
}, openMessagePayment: {
|
}, openMessagePayment: {
|
||||||
|
|||||||
@ -0,0 +1,37 @@
|
|||||||
|
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||||
|
|
||||||
|
swift_library(
|
||||||
|
name = "SuggestPostAccessoryPanelNode",
|
||||||
|
module_name = "SuggestPostAccessoryPanelNode",
|
||||||
|
srcs = glob([
|
||||||
|
"Sources/**/*.swift",
|
||||||
|
]),
|
||||||
|
copts = [
|
||||||
|
"-warnings-as-errors",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
"//submodules/AsyncDisplayKit",
|
||||||
|
"//submodules/TelegramCore",
|
||||||
|
"//submodules/Postbox",
|
||||||
|
"//submodules/SSignalKit/SwiftSignalKit",
|
||||||
|
"//submodules/Display",
|
||||||
|
"//submodules/TelegramPresentationData",
|
||||||
|
"//submodules/TelegramUIPreferences",
|
||||||
|
"//submodules/AccountContext",
|
||||||
|
"//submodules/LocalizedPeerData",
|
||||||
|
"//submodules/PhotoResources",
|
||||||
|
"//submodules/TelegramStringFormatting",
|
||||||
|
"//submodules/TextFormat",
|
||||||
|
"//submodules/ChatPresentationInterfaceState",
|
||||||
|
"//submodules/TelegramUI/Components/TextNodeWithEntities",
|
||||||
|
"//submodules/TelegramUI/Components/AnimationCache",
|
||||||
|
"//submodules/TelegramUI/Components/MultiAnimationRenderer",
|
||||||
|
"//submodules/TelegramUI/Components/Chat/AccessoryPanelNode",
|
||||||
|
"//submodules/TelegramUI/Components/CompositeTextNode",
|
||||||
|
"//submodules/TelegramNotices",
|
||||||
|
],
|
||||||
|
visibility = [
|
||||||
|
"//visibility:public",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
@ -0,0 +1,315 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import TelegramCore
|
||||||
|
import Postbox
|
||||||
|
import SwiftSignalKit
|
||||||
|
import Display
|
||||||
|
import TelegramPresentationData
|
||||||
|
import TelegramUIPreferences
|
||||||
|
import AccountContext
|
||||||
|
import LocalizedPeerData
|
||||||
|
import PhotoResources
|
||||||
|
import TelegramStringFormatting
|
||||||
|
import TextFormat
|
||||||
|
import ChatPresentationInterfaceState
|
||||||
|
import TextNodeWithEntities
|
||||||
|
import AnimationCache
|
||||||
|
import MultiAnimationRenderer
|
||||||
|
import AccessoryPanelNode
|
||||||
|
import TelegramNotices
|
||||||
|
import AppBundle
|
||||||
|
import CompositeTextNode
|
||||||
|
|
||||||
|
public final class SuggestPostAccessoryPanelNode: AccessoryPanelNode {
|
||||||
|
private var previousMediaReference: AnyMediaReference?
|
||||||
|
|
||||||
|
public let closeButton: HighlightableButtonNode
|
||||||
|
public let lineNode: ASImageNode
|
||||||
|
public let iconView: UIImageView
|
||||||
|
public let titleNode: CompositeTextNode
|
||||||
|
public let textNode: ImmediateTextNodeWithEntities
|
||||||
|
|
||||||
|
private let actionArea: AccessibilityAreaNode
|
||||||
|
|
||||||
|
private let context: AccountContext
|
||||||
|
public var theme: PresentationTheme
|
||||||
|
public var strings: PresentationStrings
|
||||||
|
|
||||||
|
private var textIsOptions: Bool = false
|
||||||
|
|
||||||
|
private var validLayout: (size: CGSize, inset: CGFloat, interfaceState: ChatPresentationInterfaceState)?
|
||||||
|
|
||||||
|
private var inlineTextStarImage: UIImage?
|
||||||
|
|
||||||
|
public init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, animationCache: AnimationCache?, animationRenderer: MultiAnimationRenderer?) {
|
||||||
|
self.context = context
|
||||||
|
self.theme = theme
|
||||||
|
self.strings = strings
|
||||||
|
|
||||||
|
self.closeButton = HighlightableButtonNode()
|
||||||
|
self.closeButton.accessibilityLabel = strings.VoiceOver_DiscardPreparedContent
|
||||||
|
self.closeButton.hitTestSlop = UIEdgeInsets(top: -8.0, left: -8.0, bottom: -8.0, right: -8.0)
|
||||||
|
self.closeButton.setImage(PresentationResourcesChat.chatInputPanelCloseIconImage(theme), for: [])
|
||||||
|
self.closeButton.displaysAsynchronously = false
|
||||||
|
|
||||||
|
self.lineNode = ASImageNode()
|
||||||
|
self.lineNode.displayWithoutProcessing = true
|
||||||
|
self.lineNode.displaysAsynchronously = false
|
||||||
|
self.lineNode.image = PresentationResourcesChat.chatInputPanelVerticalSeparatorLineImage(theme)
|
||||||
|
|
||||||
|
self.iconView = UIImageView()
|
||||||
|
self.iconView.image = UIImage(bundleImageName: "Chat/Input/Accessory Panels/SuggestPostIcon")?.withRenderingMode(.alwaysTemplate)
|
||||||
|
self.iconView.tintColor = theme.chat.inputPanel.panelControlAccentColor
|
||||||
|
|
||||||
|
self.titleNode = CompositeTextNode()
|
||||||
|
|
||||||
|
self.textNode = ImmediateTextNodeWithEntities()
|
||||||
|
self.textNode.maximumNumberOfLines = 1
|
||||||
|
self.textNode.displaysAsynchronously = false
|
||||||
|
self.textNode.insets = UIEdgeInsets(top: 3.0, left: 0.0, bottom: 3.0, right: 0.0)
|
||||||
|
self.textNode.visibility = true
|
||||||
|
self.textNode.spoilerColor = self.theme.chat.inputPanel.secondaryTextColor
|
||||||
|
|
||||||
|
if let animationCache = animationCache, let animationRenderer = animationRenderer {
|
||||||
|
self.textNode.arguments = TextNodeWithEntities.Arguments(
|
||||||
|
context: context,
|
||||||
|
cache: animationCache,
|
||||||
|
renderer: animationRenderer,
|
||||||
|
placeholderColor: theme.list.mediaPlaceholderColor,
|
||||||
|
attemptSynchronous: false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.actionArea = AccessibilityAreaNode()
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.closeButton.addTarget(self, action: #selector(self.closePressed), forControlEvents: [.touchUpInside])
|
||||||
|
self.addSubnode(self.closeButton)
|
||||||
|
|
||||||
|
self.addSubnode(self.lineNode)
|
||||||
|
self.view.addSubview(self.iconView)
|
||||||
|
self.addSubnode(self.titleNode)
|
||||||
|
self.addSubnode(self.textNode)
|
||||||
|
self.addSubnode(self.actionArea)
|
||||||
|
|
||||||
|
//TODO:localize
|
||||||
|
var titleText: [CompositeTextNode.Component] = []
|
||||||
|
titleText.append(.text(NSAttributedString(string: "Suggest a post below", font: Font.medium(15.0), textColor: self.theme.chat.inputPanel.panelControlAccentColor)))
|
||||||
|
self.titleNode.components = titleText
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func didLoad() {
|
||||||
|
super.didLoad()
|
||||||
|
|
||||||
|
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func animateIn() {
|
||||||
|
self.iconView.layer.animateScale(from: 0.001, to: 1.0, duration: 0.2)
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func animateOut() {
|
||||||
|
self.iconView.layer.animateScale(from: 1.0, to: 0.001, duration: 0.2, removeOnCompletion: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
|
||||||
|
self.updateThemeAndStrings(theme: theme, strings: strings, force: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, force: Bool) {
|
||||||
|
if self.theme !== theme || force {
|
||||||
|
self.theme = theme
|
||||||
|
|
||||||
|
self.closeButton.setImage(PresentationResourcesChat.chatInputPanelCloseIconImage(theme), for: [])
|
||||||
|
|
||||||
|
self.lineNode.image = PresentationResourcesChat.chatInputPanelVerticalSeparatorLineImage(theme)
|
||||||
|
self.iconView.tintColor = theme.chat.inputPanel.panelControlAccentColor
|
||||||
|
|
||||||
|
self.titleNode.components = self.titleNode.components.map { item in
|
||||||
|
switch item {
|
||||||
|
case let .text(text):
|
||||||
|
let updatedText = NSMutableAttributedString(attributedString: text)
|
||||||
|
updatedText.addAttribute(.foregroundColor, value: theme.chat.inputPanel.panelControlAccentColor, range: NSRange(location: 0, length: updatedText.length))
|
||||||
|
return .text(updatedText)
|
||||||
|
case let .icon(icon):
|
||||||
|
if let iconImage = generateTintedImage(image: icon, color: theme.chat.inputPanel.panelControlAccentColor) {
|
||||||
|
return .icon(iconImage)
|
||||||
|
} else {
|
||||||
|
return .icon(icon)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let text = self.textNode.attributedText {
|
||||||
|
let updatedText = NSMutableAttributedString(attributedString: text)
|
||||||
|
updatedText.addAttribute(.foregroundColor, value: self.textIsOptions ? self.theme.chat.inputPanel.secondaryTextColor : self.theme.chat.inputPanel.primaryTextColor, range: NSRange(location: 0, length: updatedText.length))
|
||||||
|
self.textNode.attributedText = updatedText
|
||||||
|
}
|
||||||
|
self.textNode.spoilerColor = self.theme.chat.inputPanel.secondaryTextColor
|
||||||
|
|
||||||
|
if let (size, inset, interfaceState) = self.validLayout {
|
||||||
|
self.updateState(size: size, inset: inset, interfaceState: interfaceState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
|
||||||
|
return CGSize(width: constrainedSize.width, height: 45.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func updateState(size: CGSize, inset: CGFloat, interfaceState: ChatPresentationInterfaceState) {
|
||||||
|
self.validLayout = (size, inset, interfaceState)
|
||||||
|
|
||||||
|
let bounds = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: 45.0))
|
||||||
|
let leftInset: CGFloat = 55.0 + inset
|
||||||
|
let textLineInset: CGFloat = 10.0
|
||||||
|
let rightInset: CGFloat = 55.0
|
||||||
|
let textRightInset: CGFloat = 20.0
|
||||||
|
|
||||||
|
let closeButtonSize = CGSize(width: 44.0, height: bounds.height)
|
||||||
|
let closeButtonFrame = CGRect(origin: CGPoint(x: bounds.width - closeButtonSize.width - inset, y: 2.0), size: closeButtonSize)
|
||||||
|
self.closeButton.frame = closeButtonFrame
|
||||||
|
|
||||||
|
self.actionArea.frame = CGRect(origin: CGPoint(x: leftInset, y: 2.0), size: CGSize(width: closeButtonFrame.minX - leftInset, height: bounds.height))
|
||||||
|
|
||||||
|
if self.lineNode.supernode == self {
|
||||||
|
self.lineNode.frame = CGRect(origin: CGPoint(x: leftInset, y: 8.0), size: CGSize(width: 2.0, height: bounds.size.height - 10.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
if let icon = self.iconView.image {
|
||||||
|
self.iconView.frame = CGRect(origin: CGPoint(x: 7.0 + inset, y: 10.0), size: icon.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
let imageTextInset: CGFloat = 0.0
|
||||||
|
|
||||||
|
let titleSize = self.titleNode.update(constrainedSize: CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset - imageTextInset, height: bounds.size.height))
|
||||||
|
if self.titleNode.supernode == self {
|
||||||
|
self.titleNode.frame = CGRect(origin: CGPoint(x: leftInset + textLineInset + imageTextInset, y: 7.0), size: titleSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
let textFont = Font.regular(15.0)
|
||||||
|
|
||||||
|
var inlineTextStarImage: UIImage?
|
||||||
|
if let current = self.inlineTextStarImage {
|
||||||
|
inlineTextStarImage = current
|
||||||
|
} else {
|
||||||
|
if let image = UIImage(bundleImageName: "Premium/Stars/StarSmall") {
|
||||||
|
let starInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
|
||||||
|
inlineTextStarImage = generateImage(CGSize(width: starInsets.left + image.size.width + starInsets.right, height: image.size.height), rotatedContext: { size, context in
|
||||||
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
|
UIGraphicsPushContext(context)
|
||||||
|
defer {
|
||||||
|
UIGraphicsPopContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
image.draw(at: CGPoint(x: starInsets.left, y: starInsets.top))
|
||||||
|
})?.withRenderingMode(.alwaysOriginal)
|
||||||
|
self.inlineTextStarImage = inlineTextStarImage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let textString: NSAttributedString
|
||||||
|
if let postSuggestionState = interfaceState.interfaceState.postSuggestionState, postSuggestionState.price != 0 {
|
||||||
|
if let timestamp = postSuggestionState.timestamp {
|
||||||
|
let timeString = humanReadableStringForTimestamp(strings: interfaceState.strings, dateTimeFormat: interfaceState.dateTimeFormat, timestamp: timestamp, alwaysShowTime: true, allowYesterday: false, format: HumanReadableStringFormat(
|
||||||
|
dateFormatString: { value in
|
||||||
|
return PresentationStrings.FormattedString(string: interfaceState.strings.SuggestPost_SetTimeFormat_Date(value).string, ranges: [])
|
||||||
|
},
|
||||||
|
tomorrowFormatString: { value in
|
||||||
|
return PresentationStrings.FormattedString(string: interfaceState.strings.SuggestPost_SetTimeFormat_TomorrowAt(value).string, ranges: [])
|
||||||
|
},
|
||||||
|
todayFormatString: { value in
|
||||||
|
return PresentationStrings.FormattedString(string: interfaceState.strings.SuggestPost_SetTimeFormat_TodayAt(value).string, ranges: [])
|
||||||
|
},
|
||||||
|
yesterdayFormatString: { value in
|
||||||
|
return PresentationStrings.FormattedString(string: interfaceState.strings.SuggestPost_SetTimeFormat_TodayAt(value).string, ranges: [])
|
||||||
|
}
|
||||||
|
)).string
|
||||||
|
textString = NSAttributedString(string: "#\(postSuggestionState.price) 📅 \(timeString)", font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor)
|
||||||
|
} else {
|
||||||
|
textString = NSAttributedString(string: "#\(postSuggestionState.price) for publishing anytime", font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
textString = NSAttributedString(string: "Tap to offer a price for publishing", font: textFont, textColor: self.theme.chat.inputPanel.primaryTextColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
let mutableTextString = NSMutableAttributedString(attributedString: textString)
|
||||||
|
if let range = mutableTextString.string.range(of: "#"), let starImage = inlineTextStarImage {
|
||||||
|
final class RunDelegateData {
|
||||||
|
let ascent: CGFloat
|
||||||
|
let descent: CGFloat
|
||||||
|
let width: CGFloat
|
||||||
|
|
||||||
|
init(ascent: CGFloat, descent: CGFloat, width: CGFloat) {
|
||||||
|
self.ascent = ascent
|
||||||
|
self.descent = descent
|
||||||
|
self.width = width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let runDelegateData = RunDelegateData(
|
||||||
|
ascent: Font.regular(15.0).ascender,
|
||||||
|
descent: Font.regular(15.0).descender,
|
||||||
|
width: starImage.size.width + 2.0
|
||||||
|
)
|
||||||
|
var callbacks = CTRunDelegateCallbacks(
|
||||||
|
version: kCTRunDelegateCurrentVersion,
|
||||||
|
dealloc: { dataRef in
|
||||||
|
Unmanaged<RunDelegateData>.fromOpaque(dataRef).release()
|
||||||
|
},
|
||||||
|
getAscent: { dataRef in
|
||||||
|
let data = Unmanaged<RunDelegateData>.fromOpaque(dataRef)
|
||||||
|
return data.takeUnretainedValue().ascent
|
||||||
|
},
|
||||||
|
getDescent: { dataRef in
|
||||||
|
let data = Unmanaged<RunDelegateData>.fromOpaque(dataRef)
|
||||||
|
return data.takeUnretainedValue().descent
|
||||||
|
},
|
||||||
|
getWidth: { dataRef in
|
||||||
|
let data = Unmanaged<RunDelegateData>.fromOpaque(dataRef)
|
||||||
|
return data.takeUnretainedValue().width
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if let runDelegate = CTRunDelegateCreate(&callbacks, Unmanaged.passRetained(runDelegateData).toOpaque()) {
|
||||||
|
mutableTextString.addAttribute(NSAttributedString.Key(kCTRunDelegateAttributeName as String), value: runDelegate, range: NSRange(range, in: mutableTextString.string))
|
||||||
|
}
|
||||||
|
mutableTextString.addAttribute(.attachment, value: starImage, range: NSRange(range, in: mutableTextString.string))
|
||||||
|
mutableTextString.addAttribute(.foregroundColor, value: UIColor(rgb: 0xffffff), range: NSRange(range, in: mutableTextString.string))
|
||||||
|
mutableTextString.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: mutableTextString.string))
|
||||||
|
}
|
||||||
|
|
||||||
|
self.textNode.attributedText = mutableTextString
|
||||||
|
|
||||||
|
let textSize = self.textNode.updateLayout(CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset - imageTextInset, height: bounds.size.height))
|
||||||
|
let textFrame = CGRect(origin: CGPoint(x: leftInset + textLineInset + imageTextInset - self.textNode.insets.left, y: 25.0 - self.textNode.insets.top), size: textSize)
|
||||||
|
if self.textNode.supernode == self {
|
||||||
|
self.textNode.frame = textFrame
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func closePressed() {
|
||||||
|
if let dismiss = self.dismiss {
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var previousTapTimestamp: Double?
|
||||||
|
@objc private func tapGesture(_ recognizer: UITapGestureRecognizer) {
|
||||||
|
if case .ended = recognizer.state {
|
||||||
|
let timestamp = CFAbsoluteTimeGetCurrent()
|
||||||
|
if let previousTapTimestamp = self.previousTapTimestamp, previousTapTimestamp + 1.0 > timestamp {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.previousTapTimestamp = CFAbsoluteTimeGetCurrent()
|
||||||
|
self.interfaceInteraction?.presentSuggestPostOptions()
|
||||||
|
Queue.mainQueue().after(1.5) {
|
||||||
|
self.updateThemeAndStrings(theme: self.theme, strings: self.strings, force: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -335,6 +335,7 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode {
|
|||||||
}, presentForwardOptions: { _ in
|
}, presentForwardOptions: { _ in
|
||||||
}, presentReplyOptions: { _ in
|
}, presentReplyOptions: { _ in
|
||||||
}, presentLinkOptions: { _ in
|
}, presentLinkOptions: { _ in
|
||||||
|
}, presentSuggestPostOptions: {
|
||||||
}, shareSelectedMessages: {
|
}, shareSelectedMessages: {
|
||||||
shareMessages()
|
shareMessages()
|
||||||
}, updateTextInputStateAndMode: { _ in
|
}, updateTextInputStateAndMode: { _ in
|
||||||
@ -410,7 +411,7 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode {
|
|||||||
}, joinGroupCall: { _ in
|
}, joinGroupCall: { _ in
|
||||||
}, presentInviteMembers: {
|
}, presentInviteMembers: {
|
||||||
}, presentGigagroupHelp: {
|
}, presentGigagroupHelp: {
|
||||||
}, openSuggestPost: {
|
}, openMonoforum: {
|
||||||
}, editMessageMedia: { _, _ in
|
}, editMessageMedia: { _, _ in
|
||||||
}, updateShowCommands: { _ in
|
}, updateShowCommands: { _ in
|
||||||
}, updateShowSendAsPeers: { _ in
|
}, updateShowSendAsPeers: { _ in
|
||||||
@ -429,6 +430,7 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode {
|
|||||||
}, addDoNotTranslateLanguage: { _ in
|
}, addDoNotTranslateLanguage: { _ in
|
||||||
}, hideTranslationPanel: {
|
}, hideTranslationPanel: {
|
||||||
}, openPremiumGift: {
|
}, openPremiumGift: {
|
||||||
|
}, openSuggestPost: {
|
||||||
}, openPremiumRequiredForMessaging: {
|
}, openPremiumRequiredForMessaging: {
|
||||||
}, openStarsPurchase: { _ in
|
}, openStarsPurchase: { _ in
|
||||||
}, openMessagePayment: {
|
}, openMessagePayment: {
|
||||||
@ -1252,6 +1254,7 @@ private enum InfoSection: Int, CaseIterable {
|
|||||||
case peerInfoTrailing
|
case peerInfoTrailing
|
||||||
case peerSettings
|
case peerSettings
|
||||||
case peerMembers
|
case peerMembers
|
||||||
|
case channelMonoforum
|
||||||
case botAffiliateProgram
|
case botAffiliateProgram
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1698,6 +1701,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
let ItemMemberRequests = 8
|
let ItemMemberRequests = 8
|
||||||
let ItemBalance = 9
|
let ItemBalance = 9
|
||||||
let ItemEdit = 10
|
let ItemEdit = 10
|
||||||
|
let ItemPeerPersonalChannel = 11
|
||||||
|
|
||||||
if let _ = data.threadData {
|
if let _ = data.threadData {
|
||||||
let mainUsername: String
|
let mainUsername: String
|
||||||
@ -1935,6 +1939,21 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
interaction.openEditing()
|
interaction.openEditing()
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let personalChannel = data.personalChannel {
|
||||||
|
let peerId = personalChannel.peer.peerId
|
||||||
|
items[.channelMonoforum]?.append(PeerInfoScreenPersonalChannelItem(id: ItemPeerPersonalChannel, context: context, data: personalChannel, controller: { [weak interaction] in
|
||||||
|
guard let interaction else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return interaction.getController()
|
||||||
|
}, action: { [weak interaction] in
|
||||||
|
guard let interaction else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
interaction.openChat(peerId)
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let group = data.peer as? TelegramGroup {
|
} else if let group = data.peer as? TelegramGroup {
|
||||||
|
|||||||
@ -373,7 +373,7 @@ final class PostSuggestionsSettingsScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let currentAmount: StarsAmount = StarsAmount(value: Int64(self.starCount), nanos: 0)
|
let currentAmount: StarsAmount = StarsAmount(value: Int64(self.starCount), nanos: 0)
|
||||||
let starsScreen = component.context.sharedContext.makeStarsWithdrawalScreen(context: component.context, subject: .enterAmount(current: currentAmount, minValue: StarsAmount(value: 0, nanos: 0), fractionAfterCommission: component.paidMessageCommissionPermille / 10, kind: .postSuggestion), completion: { [weak self] amount in
|
let starsScreen = component.context.sharedContext.makeStarsWithdrawalScreen(context: component.context, subject: .enterAmount(current: currentAmount, minValue: StarsAmount(value: 0, nanos: 0), fractionAfterCommission: component.paidMessageCommissionPermille / 10, kind: .postSuggestion, completion: { [weak self] amount in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -382,7 +382,7 @@ final class PostSuggestionsSettingsScreenComponent: Component {
|
|||||||
if !self.isUpdating {
|
if !self.isUpdating {
|
||||||
self.state?.updated(transition: .immediate)
|
self.state?.updated(transition: .immediate)
|
||||||
}
|
}
|
||||||
})
|
}))
|
||||||
environment.controller()?.push(starsScreen)
|
environment.controller()?.push(starsScreen)
|
||||||
},
|
},
|
||||||
openPremiumInfo: nil
|
openPremiumInfo: nil
|
||||||
|
|||||||
@ -594,6 +594,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
strongSelf.controller?.presentInGlobalOverlay(contextController)
|
strongSelf.controller?.presentInGlobalOverlay(contextController)
|
||||||
}, presentReplyOptions: { _ in
|
}, presentReplyOptions: { _ in
|
||||||
}, presentLinkOptions: { _ in
|
}, presentLinkOptions: { _ in
|
||||||
|
}, presentSuggestPostOptions: {
|
||||||
}, shareSelectedMessages: {
|
}, shareSelectedMessages: {
|
||||||
}, updateTextInputStateAndMode: { [weak self] f in
|
}, updateTextInputStateAndMode: { [weak self] f in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
@ -799,7 +800,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
}, joinGroupCall: { _ in
|
}, joinGroupCall: { _ in
|
||||||
}, presentInviteMembers: {
|
}, presentInviteMembers: {
|
||||||
}, presentGigagroupHelp: {
|
}, presentGigagroupHelp: {
|
||||||
}, openSuggestPost: {
|
}, openMonoforum: {
|
||||||
}, editMessageMedia: { _, _ in
|
}, editMessageMedia: { _, _ in
|
||||||
}, updateShowCommands: { _ in
|
}, updateShowCommands: { _ in
|
||||||
}, updateShowSendAsPeers: { _ in
|
}, updateShowSendAsPeers: { _ in
|
||||||
@ -817,6 +818,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
}, addDoNotTranslateLanguage: { _ in
|
}, addDoNotTranslateLanguage: { _ in
|
||||||
}, hideTranslationPanel: {
|
}, hideTranslationPanel: {
|
||||||
}, openPremiumGift: {
|
}, openPremiumGift: {
|
||||||
|
}, openSuggestPost: {
|
||||||
}, openPremiumRequiredForMessaging: {
|
}, openPremiumRequiredForMessaging: {
|
||||||
}, openStarsPurchase: { _ in
|
}, openStarsPurchase: { _ in
|
||||||
}, openMessagePayment: {
|
}, openMessagePayment: {
|
||||||
|
|||||||
@ -37,6 +37,7 @@ swift_library(
|
|||||||
"//submodules/Components/BundleIconComponent",
|
"//submodules/Components/BundleIconComponent",
|
||||||
"//submodules/PasswordSetupUI",
|
"//submodules/PasswordSetupUI",
|
||||||
"//submodules/TelegramUI/Components/PeerManagement/OwnershipTransferController",
|
"//submodules/TelegramUI/Components/PeerManagement/OwnershipTransferController",
|
||||||
|
"//submodules/TelegramUI/Components/ChatScheduleTimeController",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
|||||||
@ -21,6 +21,8 @@ import PresentationDataUtils
|
|||||||
import ListSectionComponent
|
import ListSectionComponent
|
||||||
import TelegramStringFormatting
|
import TelegramStringFormatting
|
||||||
import UndoUI
|
import UndoUI
|
||||||
|
import ListActionItemComponent
|
||||||
|
import ChatScheduleTimeController
|
||||||
|
|
||||||
private let amountTag = GenericComponentViewTag()
|
private let amountTag = GenericComponentViewTag()
|
||||||
|
|
||||||
@ -29,25 +31,22 @@ private final class SheetContent: CombinedComponent {
|
|||||||
|
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let mode: StarsWithdrawScreen.Mode
|
let mode: StarsWithdrawScreen.Mode
|
||||||
|
let controller: () -> ViewController?
|
||||||
let dismiss: () -> Void
|
let dismiss: () -> Void
|
||||||
|
|
||||||
init(
|
init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
mode: StarsWithdrawScreen.Mode,
|
mode: StarsWithdrawScreen.Mode,
|
||||||
|
controller: @escaping () -> ViewController?,
|
||||||
dismiss: @escaping () -> Void
|
dismiss: @escaping () -> Void
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
|
self.controller = controller
|
||||||
self.dismiss = dismiss
|
self.dismiss = dismiss
|
||||||
}
|
}
|
||||||
|
|
||||||
static func ==(lhs: SheetContent, rhs: SheetContent) -> Bool {
|
static func ==(lhs: SheetContent, rhs: SheetContent) -> Bool {
|
||||||
if lhs.context !== rhs.context {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if lhs.mode != rhs.mode {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,6 +55,7 @@ private final class SheetContent: CombinedComponent {
|
|||||||
let title = Child(Text.self)
|
let title = Child(Text.self)
|
||||||
let amountSection = Child(ListSectionComponent.self)
|
let amountSection = Child(ListSectionComponent.self)
|
||||||
let amountAdditionalLabel = Child(MultilineTextComponent.self)
|
let amountAdditionalLabel = Child(MultilineTextComponent.self)
|
||||||
|
let timestampSection = Child(ListSectionComponent.self)
|
||||||
let button = Child(ButtonComponent.self)
|
let button = Child(ButtonComponent.self)
|
||||||
let balanceTitle = Child(MultilineTextComponent.self)
|
let balanceTitle = Child(MultilineTextComponent.self)
|
||||||
let balanceValue = Child(MultilineTextComponent.self)
|
let balanceValue = Child(MultilineTextComponent.self)
|
||||||
@ -66,6 +66,8 @@ private final class SheetContent: CombinedComponent {
|
|||||||
let component = context.component
|
let component = context.component
|
||||||
let state = context.state
|
let state = context.state
|
||||||
|
|
||||||
|
state.component = component
|
||||||
|
|
||||||
let controller = environment.controller
|
let controller = environment.controller
|
||||||
|
|
||||||
let theme = environment.theme.withModalBlocksBackground()
|
let theme = environment.theme.withModalBlocksBackground()
|
||||||
@ -111,7 +113,7 @@ private final class SheetContent: CombinedComponent {
|
|||||||
let resaleConfiguration = StarsSubscriptionConfiguration.with(appConfiguration: component.context.currentAppConfiguration.with { $0 })
|
let resaleConfiguration = StarsSubscriptionConfiguration.with(appConfiguration: component.context.currentAppConfiguration.with { $0 })
|
||||||
|
|
||||||
switch component.mode {
|
switch component.mode {
|
||||||
case let .withdraw(status):
|
case let .withdraw(status, _):
|
||||||
titleString = environment.strings.Stars_Withdraw_Title
|
titleString = environment.strings.Stars_Withdraw_Title
|
||||||
amountTitle = environment.strings.Stars_Withdraw_AmountTitle
|
amountTitle = environment.strings.Stars_Withdraw_AmountTitle
|
||||||
amountPlaceholder = environment.strings.Stars_Withdraw_AmountPlaceholder
|
amountPlaceholder = environment.strings.Stars_Withdraw_AmountPlaceholder
|
||||||
@ -144,20 +146,28 @@ private final class SheetContent: CombinedComponent {
|
|||||||
|
|
||||||
minAmount = StarsAmount(value: 1, nanos: 0)
|
minAmount = StarsAmount(value: 1, nanos: 0)
|
||||||
maxAmount = withdrawConfiguration.maxPaidMediaAmount.flatMap { StarsAmount(value: $0, nanos: 0) }
|
maxAmount = withdrawConfiguration.maxPaidMediaAmount.flatMap { StarsAmount(value: $0, nanos: 0) }
|
||||||
case let .starGiftResell(_, update):
|
case let .starGiftResell(_, update, _):
|
||||||
titleString = update ? environment.strings.Stars_SellGift_EditTitle : environment.strings.Stars_SellGift_Title
|
titleString = update ? environment.strings.Stars_SellGift_EditTitle : environment.strings.Stars_SellGift_Title
|
||||||
amountTitle = environment.strings.Stars_SellGift_AmountTitle
|
amountTitle = environment.strings.Stars_SellGift_AmountTitle
|
||||||
amountPlaceholder = environment.strings.Stars_SellGift_AmountPlaceholder
|
amountPlaceholder = environment.strings.Stars_SellGift_AmountPlaceholder
|
||||||
|
|
||||||
minAmount = StarsAmount(value: resaleConfiguration.starGiftResaleMinAmount, nanos: 0)
|
minAmount = StarsAmount(value: resaleConfiguration.starGiftResaleMinAmount, nanos: 0)
|
||||||
maxAmount = StarsAmount(value: resaleConfiguration.starGiftResaleMaxAmount, nanos: 0)
|
maxAmount = StarsAmount(value: resaleConfiguration.starGiftResaleMaxAmount, nanos: 0)
|
||||||
case let .paidMessages(_, minAmountValue, _, _):
|
case let .paidMessages(_, minAmountValue, _, _, _):
|
||||||
titleString = environment.strings.Stars_SendMessage_AdjustmentTitle
|
titleString = environment.strings.Stars_SendMessage_AdjustmentTitle
|
||||||
amountTitle = environment.strings.Stars_SendMessage_AdjustmentSectionHeader
|
amountTitle = environment.strings.Stars_SendMessage_AdjustmentSectionHeader
|
||||||
amountPlaceholder = environment.strings.Stars_SendMessage_AdjustmentPlaceholder
|
amountPlaceholder = environment.strings.Stars_SendMessage_AdjustmentPlaceholder
|
||||||
|
|
||||||
minAmount = StarsAmount(value: minAmountValue, nanos: 0)
|
minAmount = StarsAmount(value: minAmountValue, nanos: 0)
|
||||||
maxAmount = StarsAmount(value: resaleConfiguration.paidMessageMaxAmount, nanos: 0)
|
maxAmount = StarsAmount(value: resaleConfiguration.paidMessageMaxAmount, nanos: 0)
|
||||||
|
case .suggestedPost:
|
||||||
|
//TODO:localize
|
||||||
|
titleString = "Suggest Terms"
|
||||||
|
amountTitle = "ENTER A PRICE IN STARS"
|
||||||
|
amountPlaceholder = environment.strings.Stars_SendMessage_AdjustmentPlaceholder
|
||||||
|
|
||||||
|
minAmount = StarsAmount(value: 1, nanos: 0)
|
||||||
|
maxAmount = StarsAmount(value: resaleConfiguration.paidMessageMaxAmount, nanos: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
let title = title.update(
|
let title = title.update(
|
||||||
@ -176,7 +186,7 @@ private final class SheetContent: CombinedComponent {
|
|||||||
balance = state.balance
|
balance = state.balance
|
||||||
} else if case .reaction = component.mode {
|
} else if case .reaction = component.mode {
|
||||||
balance = state.balance
|
balance = state.balance
|
||||||
} else if case let .withdraw(starsState) = component.mode {
|
} else if case let .withdraw(starsState, _) = component.mode {
|
||||||
balance = starsState.balances.availableBalance
|
balance = starsState.balances.availableBalance
|
||||||
} else {
|
} else {
|
||||||
balance = nil
|
balance = nil
|
||||||
@ -264,7 +274,7 @@ private final class SheetContent: CombinedComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
case let .reaction(starsToTop):
|
case let .reaction(starsToTop, _):
|
||||||
let amountInfoString = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString(environment.strings.Stars_SendStars_AmountInfo("\(starsToTop ?? 0)").string, attributes: amountMarkdownAttributes, textAlignment: .natural))
|
let amountInfoString = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString(environment.strings.Stars_SendStars_AmountInfo("\(starsToTop ?? 0)").string, attributes: amountMarkdownAttributes, textAlignment: .natural))
|
||||||
amountFooter = AnyComponent(MultilineTextComponent(
|
amountFooter = AnyComponent(MultilineTextComponent(
|
||||||
text: .plain(amountInfoString),
|
text: .plain(amountInfoString),
|
||||||
@ -288,7 +298,7 @@ private final class SheetContent: CombinedComponent {
|
|||||||
text: .plain(amountInfoString),
|
text: .plain(amountInfoString),
|
||||||
maximumNumberOfLines: 0
|
maximumNumberOfLines: 0
|
||||||
))
|
))
|
||||||
case let .paidMessages(_, _, fractionAfterCommission, _):
|
case let .paidMessages(_, _, fractionAfterCommission, _, _):
|
||||||
let amountInfoString: NSAttributedString
|
let amountInfoString: NSAttributedString
|
||||||
if let value = state.amount?.value, value > 0 {
|
if let value = state.amount?.value, value > 0 {
|
||||||
let fullValue: Int64 = Int64(value) * 1_000_000_000 * Int64(fractionAfterCommission) / 100
|
let fullValue: Int64 = Int64(value) * 1_000_000_000 * Int64(fractionAfterCommission) / 100
|
||||||
@ -301,6 +311,16 @@ private final class SheetContent: CombinedComponent {
|
|||||||
text: .plain(amountInfoString),
|
text: .plain(amountInfoString),
|
||||||
maximumNumberOfLines: 0
|
maximumNumberOfLines: 0
|
||||||
))
|
))
|
||||||
|
case let .suggestedPost(mode, _, _, _):
|
||||||
|
switch mode {
|
||||||
|
case let .sender(channel):
|
||||||
|
//TODO:localize
|
||||||
|
let amountInfoString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString("Choose how many Stars you want to offer \(channel.compactDisplayTitle) to publish this message.", attributes: amountMarkdownAttributes, textAlignment: .natural))
|
||||||
|
amountFooter = AnyComponent(MultilineTextComponent(
|
||||||
|
text: .plain(amountInfoString),
|
||||||
|
maximumNumberOfLines: 0
|
||||||
|
))
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
amountFooter = nil
|
amountFooter = nil
|
||||||
}
|
}
|
||||||
@ -358,6 +378,103 @@ private final class SheetContent: CombinedComponent {
|
|||||||
context.add(amountAdditionalLabel
|
context.add(amountAdditionalLabel
|
||||||
.position(CGPoint(x: context.availableSize.width - amountAdditionalLabel.size.width / 2.0 - sideInset - 16.0, y: contentSize.height - amountAdditionalLabel.size.height / 2.0)))
|
.position(CGPoint(x: context.availableSize.width - amountAdditionalLabel.size.width / 2.0 - sideInset - 16.0, y: contentSize.height - amountAdditionalLabel.size.height / 2.0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if case .suggestedPost = component.mode {
|
||||||
|
contentSize.height += 24.0
|
||||||
|
|
||||||
|
//TODO:localize
|
||||||
|
let timestampFooterString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString("Select the date and time you want your message to be published.", attributes: amountMarkdownAttributes, textAlignment: .natural))
|
||||||
|
let timestampFooter = AnyComponent(MultilineTextComponent(
|
||||||
|
text: .plain(timestampFooterString),
|
||||||
|
maximumNumberOfLines: 0
|
||||||
|
))
|
||||||
|
|
||||||
|
let timeString: String
|
||||||
|
if let timestamp = state.timestamp {
|
||||||
|
timeString = humanReadableStringForTimestamp(strings: strings, dateTimeFormat: presentationData.dateTimeFormat, timestamp: timestamp, alwaysShowTime: true, allowYesterday: true, format: HumanReadableStringFormat(
|
||||||
|
dateFormatString: { value in
|
||||||
|
return PresentationStrings.FormattedString(string: strings.SuggestPost_SetTimeFormat_Date(value).string, ranges: [])
|
||||||
|
},
|
||||||
|
tomorrowFormatString: { value in
|
||||||
|
return PresentationStrings.FormattedString(string: strings.SuggestPost_SetTimeFormat_TomorrowAt(value).string, ranges: [])
|
||||||
|
},
|
||||||
|
todayFormatString: { value in
|
||||||
|
return PresentationStrings.FormattedString(string: strings.SuggestPost_SetTimeFormat_TodayAt(value).string, ranges: [])
|
||||||
|
},
|
||||||
|
yesterdayFormatString: { value in
|
||||||
|
return PresentationStrings.FormattedString(string: strings.SuggestPost_SetTimeFormat_TodayAt(value).string, ranges: [])
|
||||||
|
}
|
||||||
|
)).string
|
||||||
|
} else {
|
||||||
|
timeString = "Anytime"
|
||||||
|
}
|
||||||
|
|
||||||
|
let timestampSection = timestampSection.update(
|
||||||
|
component: ListSectionComponent(
|
||||||
|
theme: theme,
|
||||||
|
header: nil,
|
||||||
|
footer: timestampFooter,
|
||||||
|
items: [AnyComponentWithIdentity(
|
||||||
|
id: "timestamp",
|
||||||
|
component: AnyComponent(ListActionItemComponent(
|
||||||
|
theme: theme,
|
||||||
|
title: AnyComponent(VStack([
|
||||||
|
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
|
||||||
|
text: .plain(NSAttributedString(
|
||||||
|
string: "Time",
|
||||||
|
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||||
|
textColor: environment.theme.list.itemPrimaryTextColor
|
||||||
|
)),
|
||||||
|
maximumNumberOfLines: 1
|
||||||
|
))),
|
||||||
|
], alignment: .left, spacing: 2.0)),
|
||||||
|
icon: ListActionItemComponent.Icon(component: AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent(
|
||||||
|
text: .plain(NSAttributedString(
|
||||||
|
string: timeString,
|
||||||
|
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||||
|
textColor: environment.theme.list.itemSecondaryTextColor
|
||||||
|
)),
|
||||||
|
maximumNumberOfLines: 1
|
||||||
|
)))),
|
||||||
|
accessory: .arrow,
|
||||||
|
action: { [weak state] _ in
|
||||||
|
guard let state else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let component = state.component
|
||||||
|
guard case let .suggestedPost(mode, _, _, _) = component.mode else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard case let .sender(channel) = mode else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let theme = environment.theme
|
||||||
|
let controller = ChatScheduleTimeController(context: state.context, updatedPresentationData: (state.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), state.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) }), peerId: channel.id, mode: .suggestPost, style: .default, currentTime: state.timestamp, minimalTime: nil, dismissByTapOutside: true, completion: { [weak state] time in
|
||||||
|
guard let state else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
state.timestamp = time == 0 ? nil : time
|
||||||
|
state.updated(transition: .immediate)
|
||||||
|
})
|
||||||
|
component.controller()?.view.endEditing(true)
|
||||||
|
component.controller()?.present(controller, in: .window(.root))
|
||||||
|
}
|
||||||
|
))
|
||||||
|
)]
|
||||||
|
),
|
||||||
|
environment: {},
|
||||||
|
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: .greatestFiniteMagnitude),
|
||||||
|
transition: context.transition
|
||||||
|
)
|
||||||
|
context.add(timestampSection
|
||||||
|
.position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height + timestampSection.size.height / 2.0))
|
||||||
|
.clipsToBounds(true)
|
||||||
|
.cornerRadius(10.0)
|
||||||
|
)
|
||||||
|
contentSize.height += timestampSection.size.height
|
||||||
|
}
|
||||||
|
|
||||||
contentSize.height += 32.0
|
contentSize.height += 32.0
|
||||||
|
|
||||||
let buttonString: String
|
let buttonString: String
|
||||||
@ -371,6 +488,16 @@ private final class SheetContent: CombinedComponent {
|
|||||||
}
|
}
|
||||||
} else if case .paidMessages = component.mode {
|
} else if case .paidMessages = component.mode {
|
||||||
buttonString = environment.strings.Stars_SendMessage_AdjustmentAction
|
buttonString = environment.strings.Stars_SendMessage_AdjustmentAction
|
||||||
|
} else if case let .suggestedPost(mode, _, _, _) = component.mode {
|
||||||
|
//TODO:localize
|
||||||
|
switch mode {
|
||||||
|
case .sender:
|
||||||
|
if let amount = state.amount {
|
||||||
|
buttonString = "Offer # \(presentationStringsFormattedNumber(amount, environment.dateTimeFormat.groupingSeparator))"
|
||||||
|
} else {
|
||||||
|
buttonString = "Offer"
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if let amount = state.amount {
|
} else if let amount = state.amount {
|
||||||
buttonString = "\(environment.strings.Stars_Withdraw_Withdraw) # \(presentationStringsFormattedNumber(amount, environment.dateTimeFormat.groupingSeparator))"
|
buttonString = "\(environment.strings.Stars_Withdraw_Withdraw) # \(presentationStringsFormattedNumber(amount, environment.dateTimeFormat.groupingSeparator))"
|
||||||
} else {
|
} else {
|
||||||
@ -393,7 +520,7 @@ private final class SheetContent: CombinedComponent {
|
|||||||
let amount = state.amount ?? StarsAmount.zero
|
let amount = state.amount ?? StarsAmount.zero
|
||||||
if amount > StarsAmount.zero {
|
if amount > StarsAmount.zero {
|
||||||
isButtonEnabled = true
|
isButtonEnabled = true
|
||||||
} else if case let .paidMessages(_, minValue, _, _) = context.component.mode {
|
} else if case let .paidMessages(_, minValue, _, _, _) = context.component.mode {
|
||||||
if minValue <= 0 {
|
if minValue <= 0 {
|
||||||
isButtonEnabled = true
|
isButtonEnabled = true
|
||||||
}
|
}
|
||||||
@ -414,11 +541,27 @@ private final class SheetContent: CombinedComponent {
|
|||||||
isEnabled: isButtonEnabled,
|
isEnabled: isButtonEnabled,
|
||||||
displaysProgress: false,
|
displaysProgress: false,
|
||||||
action: { [weak state] in
|
action: { [weak state] in
|
||||||
if let controller = controller() as? StarsWithdrawScreen, let amount = state?.amount {
|
if let controller = controller() as? StarsWithdrawScreen, let state, let amount = state.amount {
|
||||||
if let minAmount, amount < minAmount {
|
if let minAmount, amount < minAmount {
|
||||||
controller.presentMinAmountTooltip(minAmount.value)
|
controller.presentMinAmountTooltip(minAmount.value)
|
||||||
} else {
|
} else {
|
||||||
controller.completion(amount.value)
|
switch state.mode {
|
||||||
|
case let .withdraw(_, completion):
|
||||||
|
completion(amount.value)
|
||||||
|
case let .accountWithdraw(completion):
|
||||||
|
completion(amount.value)
|
||||||
|
case let .paidMedia(_, completion):
|
||||||
|
completion(amount.value)
|
||||||
|
case let .reaction(_, completion):
|
||||||
|
completion(amount.value)
|
||||||
|
case let .starGiftResell(_, _, completion):
|
||||||
|
completion(amount.value)
|
||||||
|
case let .paidMessages(_, _, _, _, completion):
|
||||||
|
completion(amount.value)
|
||||||
|
case let .suggestedPost(_, _, _, completion):
|
||||||
|
completion(amount.value, state.timestamp)
|
||||||
|
}
|
||||||
|
|
||||||
controller.dismissAnimated()
|
controller.dismissAnimated()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -442,10 +585,13 @@ private final class SheetContent: CombinedComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class State: ComponentState {
|
final class State: ComponentState {
|
||||||
private let context: AccountContext
|
fileprivate let context: AccountContext
|
||||||
private let mode: StarsWithdrawScreen.Mode
|
fileprivate let mode: StarsWithdrawScreen.Mode
|
||||||
|
|
||||||
|
fileprivate var component: SheetContent
|
||||||
|
|
||||||
fileprivate var amount: StarsAmount?
|
fileprivate var amount: StarsAmount?
|
||||||
|
fileprivate var timestamp: Int32?
|
||||||
|
|
||||||
fileprivate var balance: StarsAmount?
|
fileprivate var balance: StarsAmount?
|
||||||
private var stateDisposable: Disposable?
|
private var stateDisposable: Disposable?
|
||||||
@ -454,27 +600,30 @@ private final class SheetContent: CombinedComponent {
|
|||||||
var cachedStarImage: (UIImage, PresentationTheme)?
|
var cachedStarImage: (UIImage, PresentationTheme)?
|
||||||
var cachedChevronImage: (UIImage, PresentationTheme)?
|
var cachedChevronImage: (UIImage, PresentationTheme)?
|
||||||
|
|
||||||
init(
|
init(component: SheetContent) {
|
||||||
context: AccountContext,
|
self.context = component.context
|
||||||
mode: StarsWithdrawScreen.Mode
|
self.mode = component.mode
|
||||||
) {
|
self.component = component
|
||||||
self.context = context
|
|
||||||
self.mode = mode
|
|
||||||
|
|
||||||
var amount: StarsAmount?
|
var amount: StarsAmount?
|
||||||
switch mode {
|
switch mode {
|
||||||
case let .withdraw(stats):
|
case let .withdraw(stats, _):
|
||||||
amount = StarsAmount(value: stats.balances.availableBalance.value, nanos: 0)
|
amount = StarsAmount(value: stats.balances.availableBalance.value, nanos: 0)
|
||||||
case .accountWithdraw:
|
case .accountWithdraw:
|
||||||
amount = context.starsContext?.currentState.flatMap { StarsAmount(value: $0.balance.value, nanos: 0) }
|
amount = context.starsContext?.currentState.flatMap { StarsAmount(value: $0.balance.value, nanos: 0) }
|
||||||
case let .paidMedia(initialValue):
|
case let .paidMedia(initialValue, _):
|
||||||
amount = initialValue.flatMap { StarsAmount(value: $0, nanos: 0) }
|
amount = initialValue.flatMap { StarsAmount(value: $0, nanos: 0) }
|
||||||
case .reaction:
|
case .reaction:
|
||||||
amount = nil
|
amount = nil
|
||||||
case .starGiftResell:
|
case .starGiftResell:
|
||||||
amount = nil
|
amount = nil
|
||||||
case let .paidMessages(initialValue, _, _, _):
|
case let .paidMessages(initialValue, _, _, _, _):
|
||||||
amount = StarsAmount(value: initialValue, nanos: 0)
|
amount = StarsAmount(value: initialValue, nanos: 0)
|
||||||
|
case let .suggestedPost(_, initialValue, initialTimestamp, _):
|
||||||
|
if initialValue != 0 {
|
||||||
|
amount = StarsAmount(value: initialValue, nanos: 0)
|
||||||
|
}
|
||||||
|
self.timestamp = initialTimestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
self.amount = amount
|
self.amount = amount
|
||||||
@ -491,7 +640,7 @@ private final class SheetContent: CombinedComponent {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if case let .starGiftResell(giftToMatch, update) = self.mode {
|
if case let .starGiftResell(giftToMatch, update, _) = self.mode {
|
||||||
if update {
|
if update {
|
||||||
if let resellStars = giftToMatch.resellStars {
|
if let resellStars = giftToMatch.resellStars {
|
||||||
self.amount = StarsAmount(value: resellStars, nanos: 0)
|
self.amount = StarsAmount(value: resellStars, nanos: 0)
|
||||||
@ -528,7 +677,7 @@ private final class SheetContent: CombinedComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func makeState() -> State {
|
func makeState() -> State {
|
||||||
return State(context: self.context, mode: self.mode)
|
return State(component: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -547,12 +696,6 @@ private final class StarsWithdrawSheetComponent: CombinedComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static func ==(lhs: StarsWithdrawSheetComponent, rhs: StarsWithdrawSheetComponent) -> Bool {
|
static func ==(lhs: StarsWithdrawSheetComponent, rhs: StarsWithdrawSheetComponent) -> Bool {
|
||||||
if lhs.context !== rhs.context {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if lhs.mode != rhs.mode {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -570,6 +713,9 @@ private final class StarsWithdrawSheetComponent: CombinedComponent {
|
|||||||
content: AnyComponent<EnvironmentType>(SheetContent(
|
content: AnyComponent<EnvironmentType>(SheetContent(
|
||||||
context: context.component.context,
|
context: context.component.context,
|
||||||
mode: context.component.mode,
|
mode: context.component.mode,
|
||||||
|
controller: {
|
||||||
|
return controller()
|
||||||
|
},
|
||||||
dismiss: {
|
dismiss: {
|
||||||
animateOut.invoke(Action { _ in
|
animateOut.invoke(Action { _ in
|
||||||
if let controller = controller() {
|
if let controller = controller() {
|
||||||
@ -620,27 +766,29 @@ private final class StarsWithdrawSheetComponent: CombinedComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class StarsWithdrawScreen: ViewControllerComponentContainer {
|
public final class StarsWithdrawScreen: ViewControllerComponentContainer {
|
||||||
public enum Mode: Equatable {
|
public enum Mode {
|
||||||
case withdraw(StarsRevenueStats)
|
public enum SuggestedPostMode {
|
||||||
case accountWithdraw
|
case sender(channel: EnginePeer)
|
||||||
case paidMedia(Int64?)
|
}
|
||||||
case reaction(Int64?)
|
|
||||||
case starGiftResell(StarGift.UniqueGift, Bool)
|
case withdraw(StarsRevenueStats, completion: (Int64) -> Void)
|
||||||
case paidMessages(current: Int64, minValue: Int64, fractionAfterCommission: Int, kind: StarsWithdrawalScreenSubject.PaidMessageKind)
|
case accountWithdraw(completion: (Int64) -> Void)
|
||||||
|
case paidMedia(Int64?, completion: (Int64) -> Void)
|
||||||
|
case reaction(Int64?, completion: (Int64) -> Void)
|
||||||
|
case starGiftResell(StarGift.UniqueGift, Bool, completion: (Int64) -> Void)
|
||||||
|
case paidMessages(current: Int64, minValue: Int64, fractionAfterCommission: Int, kind: StarsWithdrawalScreenSubject.PaidMessageKind, completion: (Int64) -> Void)
|
||||||
|
case suggestedPost(mode: SuggestedPostMode, price: Int64, timestamp: Int32?, completion: (Int64, Int32?) -> Void)
|
||||||
}
|
}
|
||||||
|
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
private let mode: StarsWithdrawScreen.Mode
|
private let mode: StarsWithdrawScreen.Mode
|
||||||
fileprivate let completion: (Int64) -> Void
|
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
mode: StarsWithdrawScreen.Mode,
|
mode: StarsWithdrawScreen.Mode
|
||||||
completion: @escaping (Int64) -> Void
|
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
self.completion = completion
|
|
||||||
|
|
||||||
super.init(
|
super.init(
|
||||||
context: context,
|
context: context,
|
||||||
|
|||||||
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "suggest_30.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "suggest_24.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
@ -306,6 +306,9 @@ extension ChatControllerImpl {
|
|||||||
if let requestsState = previousState.requestsState, requestsState.count > 0 && !previousInvitationRequestsPeersDismissed {
|
if let requestsState = previousState.requestsState, requestsState.count > 0 && !previousInvitationRequestsPeersDismissed {
|
||||||
didDisplayActionsPanel = true
|
didDisplayActionsPanel = true
|
||||||
}
|
}
|
||||||
|
if previousState.removePaidMessageFeeData != nil {
|
||||||
|
didDisplayActionsPanel = true
|
||||||
|
}
|
||||||
|
|
||||||
var displayActionsPanel = false
|
var displayActionsPanel = false
|
||||||
if let contactStatus = contentData.state.contactStatus, !contactStatus.isEmpty, let peerStatusSettings = contactStatus.peerStatusSettings {
|
if let contactStatus = contentData.state.contactStatus, !contactStatus.isEmpty, let peerStatusSettings = contactStatus.peerStatusSettings {
|
||||||
@ -339,6 +342,9 @@ extension ChatControllerImpl {
|
|||||||
if let requestsState = contentData.state.requestsState, requestsState.count > 0 && !invitationRequestsPeersDismissed {
|
if let requestsState = contentData.state.requestsState, requestsState.count > 0 && !invitationRequestsPeersDismissed {
|
||||||
displayActionsPanel = true
|
displayActionsPanel = true
|
||||||
}
|
}
|
||||||
|
if contentData.state.removePaidMessageFeeData != nil {
|
||||||
|
displayActionsPanel = true
|
||||||
|
}
|
||||||
|
|
||||||
if displayActionsPanel != didDisplayActionsPanel {
|
if displayActionsPanel != didDisplayActionsPanel {
|
||||||
animated = true
|
animated = true
|
||||||
@ -1894,6 +1900,11 @@ extension ChatControllerImpl {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
presentChatLinkOptions(selfController: self, sourceNode: sourceNode)
|
presentChatLinkOptions(selfController: self, sourceNode: sourceNode)
|
||||||
|
}, presentSuggestPostOptions: { [weak self] in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.presentSuggestPostOptions()
|
||||||
}, shareSelectedMessages: { [weak self] in
|
}, shareSelectedMessages: { [weak self] in
|
||||||
if let strongSelf = self, let selectedIds = strongSelf.presentationInterfaceState.interfaceState.selectionState?.selectedIds, !selectedIds.isEmpty {
|
if let strongSelf = self, let selectedIds = strongSelf.presentationInterfaceState.interfaceState.selectionState?.selectedIds, !selectedIds.isEmpty {
|
||||||
strongSelf.commitPurposefulAction()
|
strongSelf.commitPurposefulAction()
|
||||||
@ -3734,7 +3745,7 @@ extension ChatControllerImpl {
|
|||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .info(title: nil, text: strongSelf.presentationData.strings.Conversation_GigagroupDescription, timeout: nil, customUndoText: nil), elevatedLayout: false, action: { _ in return true }), in: .current)
|
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .info(title: nil, text: strongSelf.presentationData.strings.Conversation_GigagroupDescription, timeout: nil, customUndoText: nil), elevatedLayout: false, action: { _ in return true }), in: .current)
|
||||||
}
|
}
|
||||||
}, openSuggestPost: { [weak self] in
|
}, openMonoforum: { [weak self] in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -4084,6 +4095,22 @@ extension ChatControllerImpl {
|
|||||||
})
|
})
|
||||||
self.push(controller)
|
self.push(controller)
|
||||||
}
|
}
|
||||||
|
}, openSuggestPost: { [weak self] in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.updateChatPresentationInterfaceState(interactive: true, { state in
|
||||||
|
var state = state
|
||||||
|
state = state.updatedInterfaceState { interfaceState in
|
||||||
|
var interfaceState = interfaceState
|
||||||
|
interfaceState = interfaceState.withUpdatedPostSuggestionState(ChatInterfaceState.PostSuggestionState(
|
||||||
|
price: 0,
|
||||||
|
timestamp: nil
|
||||||
|
))
|
||||||
|
return interfaceState
|
||||||
|
}
|
||||||
|
return state
|
||||||
|
})
|
||||||
}, openPremiumRequiredForMessaging: { [weak self] in
|
}, openPremiumRequiredForMessaging: { [weak self] in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
|
|||||||
@ -977,3 +977,39 @@ private func chatLinkOptions(selfController: ChatControllerImpl, sourceNode: ASD
|
|||||||
func presentChatLinkOptions(selfController: ChatControllerImpl, sourceNode: ASDisplayNode) {
|
func presentChatLinkOptions(selfController: ChatControllerImpl, sourceNode: ASDisplayNode) {
|
||||||
presentChatInputOptions(selfController: selfController, sourceNode: sourceNode, initialId: .link)
|
presentChatInputOptions(selfController: selfController, sourceNode: sourceNode, initialId: .link)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension ChatControllerImpl {
|
||||||
|
func presentSuggestPostOptions() {
|
||||||
|
guard let channel = self.presentationInterfaceState.renderedPeer?.chatOrMonoforumMainPeer as? TelegramChannel else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard let postSuggestionState = self.presentationInterfaceState.interfaceState.postSuggestionState else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.push(self.context.sharedContext.makeStarsWithdrawalScreen(
|
||||||
|
context: self.context,
|
||||||
|
subject: .postSuggestion(
|
||||||
|
channel: .channel(channel),
|
||||||
|
current: StarsAmount(value: postSuggestionState.price, nanos: 0),
|
||||||
|
timestamp: postSuggestionState.timestamp,
|
||||||
|
completion: { [weak self] price, timestamp in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.updateChatPresentationInterfaceState(interactive: true, { state in
|
||||||
|
var state = state
|
||||||
|
state = state.updatedInterfaceState { interfaceState in
|
||||||
|
var interfaceState = interfaceState
|
||||||
|
interfaceState = interfaceState.withUpdatedPostSuggestionState(ChatInterfaceState.PostSuggestionState(
|
||||||
|
price: price,
|
||||||
|
timestamp: timestamp
|
||||||
|
))
|
||||||
|
return interfaceState
|
||||||
|
}
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -4595,24 +4595,32 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
guard let chatPeer = self.presentationInterfaceState.renderedPeer?.chatOrMonoforumMainPeer else {
|
guard let chatPeer = self.presentationInterfaceState.renderedPeer?.chatOrMonoforumMainPeer else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _ = (self.context.engine.peers.getPaidMessagesRevenue(scopePeerId: peer.id, peerId: removePaidMessageFeeData.peer.id)
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] revenue in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let controller = chatMessageRemovePaymentAlertController(
|
let controller = chatMessageRemovePaymentAlertController(
|
||||||
context: self.context,
|
context: self.context,
|
||||||
presentationData: self.presentationData,
|
presentationData: self.presentationData,
|
||||||
updatedPresentationData: self.updatedPresentationData,
|
updatedPresentationData: self.updatedPresentationData,
|
||||||
peer: removePaidMessageFeeData.peer,
|
peer: removePaidMessageFeeData.peer,
|
||||||
chatPeer: EnginePeer(chatPeer),
|
chatPeer: EnginePeer(chatPeer),
|
||||||
amount: StarsAmount(value: 123, nanos: 0), //TODO:release
|
amount: revenue == StarsAmount(value: 0, nanos: 0) ? nil : revenue,
|
||||||
navigationController: self.navigationController as? NavigationController,
|
navigationController: self.navigationController as? NavigationController,
|
||||||
completion: { [weak self] refund in
|
completion: { [weak self] refund in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let _ = self
|
let _ = self.context.engine.peers.addNoPaidMessagesException(scopePeerId: peer.id, peerId: removePaidMessageFeeData.peer.id, refundCharged: refund).start()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
self.present(controller, in: .window(.root))
|
self.present(controller, in: .window(.root))
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
let _ = (self.context.engine.peers.getPaidMessagesRevenue(peerId: peer.id)
|
let _ = (self.context.engine.peers.getPaidMessagesRevenue(scopePeerId: self.context.account.peerId, peerId: peer.id)
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] revenue in
|
|> deliverOnMainQueue).start(next: { [weak self] revenue in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
@ -4629,7 +4637,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let _ = self.context.engine.peers.addNoPaidMessagesException(peerId: peer.id, refundCharged: refund).start()
|
let _ = self.context.engine.peers.addNoPaidMessagesException(scopePeerId: self.context.account.peerId, peerId: peer.id, refundCharged: refund).start()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
self.present(controller, in: .window(.root))
|
self.present(controller, in: .window(.root))
|
||||||
|
|||||||
@ -1189,13 +1189,15 @@ extension ChatControllerImpl {
|
|||||||
savedMessagesPeerId = nil
|
savedMessagesPeerId = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
let savedMessagesPeer: Signal<(peer: EnginePeer?, messageCount: Int, presence: EnginePeer.Presence?)?, NoError>
|
let savedMessagesPeer: Signal<(peer: EnginePeer?, messageCount: Int, presence: EnginePeer.Presence?, isMonoforumFeeRemoved: Bool)?, NoError>
|
||||||
if let savedMessagesPeerId {
|
if let savedMessagesPeerId {
|
||||||
let threadPeerId = savedMessagesPeerId
|
let threadPeerId = savedMessagesPeerId
|
||||||
let basicPeerKey: PostboxViewKey = .peer(peerId: threadPeerId, components: [])
|
let basicPeerKey: PostboxViewKey = .peer(peerId: threadPeerId, components: [])
|
||||||
let countViewKey: PostboxViewKey = .historyTagSummaryView(tag: MessageTags(), peerId: peerId, threadId: savedMessagesPeerId.toInt64(), namespace: Namespaces.Message.Cloud, customTag: nil)
|
let countViewKey: PostboxViewKey = .historyTagSummaryView(tag: MessageTags(), peerId: peerId, threadId: savedMessagesPeerId.toInt64(), namespace: Namespaces.Message.Cloud, customTag: nil)
|
||||||
savedMessagesPeer = context.account.postbox.combinedView(keys: [basicPeerKey, countViewKey])
|
let threadInfoKey: PostboxViewKey = .messageHistoryThreadInfo(peerId: peerId, threadId: savedMessagesPeerId.toInt64())
|
||||||
|> map { views -> (peer: EnginePeer?, messageCount: Int, presence: EnginePeer.Presence?)? in
|
|
||||||
|
savedMessagesPeer = context.account.postbox.combinedView(keys: [basicPeerKey, countViewKey, threadInfoKey])
|
||||||
|
|> map { views -> (peer: EnginePeer?, messageCount: Int, presence: EnginePeer.Presence?, isMonoforumFeeRemoved: Bool)? in
|
||||||
var peer: EnginePeer?
|
var peer: EnginePeer?
|
||||||
var presence: EnginePeer.Presence?
|
var presence: EnginePeer.Presence?
|
||||||
if let peerView = views.views[basicPeerKey] as? PeerView {
|
if let peerView = views.views[basicPeerKey] as? PeerView {
|
||||||
@ -1208,7 +1210,12 @@ extension ChatControllerImpl {
|
|||||||
messageCount += Int(count)
|
messageCount += Int(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (peer, messageCount, presence)
|
var isMonoforumFeeRemoved = false
|
||||||
|
if let threadInfoView = views.views[threadInfoKey] as? MessageHistoryThreadInfoView, let threadInfo = threadInfoView.info?.data.get(MessageHistoryThreadData.self) {
|
||||||
|
isMonoforumFeeRemoved = threadInfo.isMessageFeeRemoved
|
||||||
|
}
|
||||||
|
|
||||||
|
return (peer, messageCount, presence, isMonoforumFeeRemoved)
|
||||||
}
|
}
|
||||||
|> distinctUntilChanged(isEqual: { lhs, rhs in
|
|> distinctUntilChanged(isEqual: { lhs, rhs in
|
||||||
if lhs?.peer != rhs?.peer {
|
if lhs?.peer != rhs?.peer {
|
||||||
@ -1220,6 +1227,9 @@ extension ChatControllerImpl {
|
|||||||
if lhs?.presence != rhs?.presence {
|
if lhs?.presence != rhs?.presence {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs?.isMonoforumFeeRemoved != rhs?.isMonoforumFeeRemoved {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@ -1473,7 +1483,7 @@ extension ChatControllerImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var removePaidMessageFeeData: ChatPresentationInterfaceState.RemovePaidMessageFeeData?
|
var removePaidMessageFeeData: ChatPresentationInterfaceState.RemovePaidMessageFeeData?
|
||||||
if !"".isEmpty, let peer = savedMessagesPeer?.peer, let channel = peerView.peers[peerView.peerId] as? TelegramChannel, let sendPaidMessageStars = channel.sendPaidMessageStars, channel.isMonoForum {
|
if let savedMessagesPeer, !savedMessagesPeer.isMonoforumFeeRemoved, let peer = savedMessagesPeer.peer, let channel = peerView.peers[peerView.peerId] as? TelegramChannel, let sendPaidMessageStars = channel.sendPaidMessageStars, channel.isMonoForum {
|
||||||
if let linkedMonoforumId = channel.linkedMonoforumId, let mainChannel = peerView.peers[linkedMonoforumId] as? TelegramChannel, mainChannel.hasPermission(.sendSomething) {
|
if let linkedMonoforumId = channel.linkedMonoforumId, let mainChannel = peerView.peers[linkedMonoforumId] as? TelegramChannel, mainChannel.hasPermission(.sendSomething) {
|
||||||
removePaidMessageFeeData = ChatPresentationInterfaceState.RemovePaidMessageFeeData(
|
removePaidMessageFeeData = ChatPresentationInterfaceState.RemovePaidMessageFeeData(
|
||||||
peer: peer,
|
peer: peer,
|
||||||
|
|||||||
@ -32,6 +32,7 @@ import ChatInputPanelNode
|
|||||||
import ChatInputContextPanelNode
|
import ChatInputContextPanelNode
|
||||||
import TextSelectionNode
|
import TextSelectionNode
|
||||||
import ReplyAccessoryPanelNode
|
import ReplyAccessoryPanelNode
|
||||||
|
import SuggestPostAccessoryPanelNode
|
||||||
import ChatMessageItemView
|
import ChatMessageItemView
|
||||||
import ChatMessageSelectionNode
|
import ChatMessageSelectionNode
|
||||||
import ManagedDiceAnimationNode
|
import ManagedDiceAnimationNode
|
||||||
@ -371,7 +372,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
let contentBounds = self.loadingNode.frame
|
let contentBounds = self.loadingNode.frame
|
||||||
loadingPlaceholderNode.frame = contentBounds
|
loadingPlaceholderNode.frame = contentBounds
|
||||||
if let loadingPlaceholderNode = self.loadingPlaceholderNode, let validLayout = self.validLayout {
|
if let loadingPlaceholderNode = self.loadingPlaceholderNode, let validLayout = self.validLayout {
|
||||||
loadingPlaceholderNode.updateLayout(size: contentBounds.size, insets: self.loadingNodeInsets, metrics: validLayout.0.metrics, transition: .immediate)
|
loadingPlaceholderNode.updateLayout(size: contentBounds.size, isSidebarOpen: self.leftPanel != nil, insets: self.loadingNodeInsets, metrics: validLayout.0.metrics, transition: .immediate)
|
||||||
loadingPlaceholderNode.update(rect: contentBounds, within: contentBounds.size, transition: .immediate)
|
loadingPlaceholderNode.update(rect: contentBounds, within: contentBounds.size, transition: .immediate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1712,6 +1713,12 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
strongSelf.interfaceInteraction?.setupEditMessage(nil, { _ in })
|
strongSelf.interfaceInteraction?.setupEditMessage(nil, { _ in })
|
||||||
} else if let _ = accessoryPanelNode as? WebpagePreviewAccessoryPanelNode {
|
} else if let _ = accessoryPanelNode as? WebpagePreviewAccessoryPanelNode {
|
||||||
strongSelf.dismissUrlPreview()
|
strongSelf.dismissUrlPreview()
|
||||||
|
} else if let _ = accessoryPanelNode as? SuggestPostAccessoryPanelNode {
|
||||||
|
strongSelf.requestUpdateChatInterfaceState(.animated(duration: 0.4, curve: .spring), false, { state in
|
||||||
|
var state = state
|
||||||
|
state = state.withUpdatedPostSuggestionState(nil)
|
||||||
|
return state
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2250,7 +2257,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
self.loadingNode.updateLayout(size: contentBounds.size, insets: loadingNodeInsets, transition: transition)
|
self.loadingNode.updateLayout(size: contentBounds.size, insets: loadingNodeInsets, transition: transition)
|
||||||
|
|
||||||
if let loadingPlaceholderNode = self.loadingPlaceholderNode {
|
if let loadingPlaceholderNode = self.loadingPlaceholderNode {
|
||||||
loadingPlaceholderNode.updateLayout(size: contentBounds.size, insets: loadingNodeInsets, metrics: layout.metrics, transition: transition)
|
loadingPlaceholderNode.updateLayout(size: contentBounds.size, isSidebarOpen: leftPanelSize != nil, insets: loadingNodeInsets, metrics: layout.metrics, transition: transition)
|
||||||
loadingPlaceholderNode.update(rect: contentBounds, within: contentBounds.size, transition: transition)
|
loadingPlaceholderNode.update(rect: contentBounds, within: contentBounds.size, transition: transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -233,6 +233,12 @@ func inputTextPanelStateForChatPresentationInterfaceState(_ chatPresentationInte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isTextEmpty, let channel = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel, channel.isMonoForum, let mainChannel = chatPresentationInterfaceState.renderedPeer?.chatOrMonoforumMainPeer as? TelegramChannel, !mainChannel.hasPermission(.sendSomething) {
|
||||||
|
if chatPresentationInterfaceState.interfaceState.postSuggestionState == nil {
|
||||||
|
accessoryItems.append(.suggestPost)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if case let .customChatContents(customChatContents) = chatPresentationInterfaceState.subject {
|
if case let .customChatContents(customChatContents) = chatPresentationInterfaceState.subject {
|
||||||
switch customChatContents.kind {
|
switch customChatContents.kind {
|
||||||
case .hashTagSearch:
|
case .hashTagSearch:
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import ChatControllerInteraction
|
|||||||
import AccessoryPanelNode
|
import AccessoryPanelNode
|
||||||
import ForwardAccessoryPanelNode
|
import ForwardAccessoryPanelNode
|
||||||
import ReplyAccessoryPanelNode
|
import ReplyAccessoryPanelNode
|
||||||
|
import SuggestPostAccessoryPanelNode
|
||||||
|
|
||||||
func accessoryPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState, context: AccountContext, currentPanel: AccessoryPanelNode?, chatControllerInteraction: ChatControllerInteraction?, interfaceInteraction: ChatPanelInterfaceInteraction?) -> AccessoryPanelNode? {
|
func accessoryPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState, context: AccountContext, currentPanel: AccessoryPanelNode?, chatControllerInteraction: ChatControllerInteraction?, interfaceInteraction: ChatPanelInterfaceInteraction?) -> AccessoryPanelNode? {
|
||||||
if case .standard(.previewing) = chatPresentationInterfaceState.mode {
|
if case .standard(.previewing) = chatPresentationInterfaceState.mode {
|
||||||
@ -92,6 +93,16 @@ func accessoryPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceS
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if chatPresentationInterfaceState.interfaceState.postSuggestionState != nil {
|
||||||
|
if let replyPanelNode = currentPanel as? SuggestPostAccessoryPanelNode {
|
||||||
|
replyPanelNode.interfaceInteraction = interfaceInteraction
|
||||||
|
replyPanelNode.updateThemeAndStrings(theme: chatPresentationInterfaceState.theme, strings: chatPresentationInterfaceState.strings)
|
||||||
|
return replyPanelNode
|
||||||
|
} else {
|
||||||
|
let panelNode = SuggestPostAccessoryPanelNode(context: context, theme: chatPresentationInterfaceState.theme, strings: chatPresentationInterfaceState.strings, nameDisplayOrder: chatPresentationInterfaceState.nameDisplayOrder, dateTimeFormat: chatPresentationInterfaceState.dateTimeFormat, animationCache: chatControllerInteraction?.presentationContext.animationCache, animationRenderer: chatControllerInteraction?.presentationContext.animationRenderer)
|
||||||
|
panelNode.interfaceInteraction = interfaceInteraction
|
||||||
|
return panelNode
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -157,6 +157,9 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
|
|||||||
} else {
|
} else {
|
||||||
return (PresentationResourcesChat.chatInputTextFieldSilentPostOffImage(theme), nil, strings.VoiceOver_SilentPostOff, 1.0, UIEdgeInsets())
|
return (PresentationResourcesChat.chatInputTextFieldSilentPostOffImage(theme), nil, strings.VoiceOver_SilentPostOff, 1.0, UIEdgeInsets())
|
||||||
}
|
}
|
||||||
|
case .suggestPost:
|
||||||
|
//TODO:localize
|
||||||
|
return (PresentationResourcesChat.chatInputTextFieldSuggestPostImage(theme), nil, "Suggest post", 1.0, UIEdgeInsets())
|
||||||
case let .messageAutoremoveTimeout(timeout):
|
case let .messageAutoremoveTimeout(timeout):
|
||||||
if let timeout = timeout {
|
if let timeout = timeout {
|
||||||
return (nil, shortTimeIntervalString(strings: strings, value: timeout), strings.VoiceOver_SelfDestructTimerOn(timeIntervalString(strings: strings, value: timeout)).string, 1.0, UIEdgeInsets())
|
return (nil, shortTimeIntervalString(strings: strings, value: timeout), strings.VoiceOver_SelfDestructTimerOn(timeIntervalString(strings: strings, value: timeout)).string, 1.0, UIEdgeInsets())
|
||||||
@ -172,7 +175,7 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode {
|
|||||||
|
|
||||||
private static func calculateWidth(item: ChatTextInputAccessoryItem, image: UIImage?, text: String?, strings: PresentationStrings) -> CGFloat {
|
private static func calculateWidth(item: ChatTextInputAccessoryItem, image: UIImage?, text: String?, strings: PresentationStrings) -> CGFloat {
|
||||||
switch item {
|
switch item {
|
||||||
case .input, .botInput, .silentPost, .commands, .scheduledMessages, .gift:
|
case .input, .botInput, .silentPost, .commands, .scheduledMessages, .gift, .suggestPost:
|
||||||
return 32.0
|
return 32.0
|
||||||
case let .messageAutoremoveTimeout(timeout):
|
case let .messageAutoremoveTimeout(timeout):
|
||||||
var imageWidth = (image?.size.width ?? 0.0) + CGFloat(8.0)
|
var imageWidth = (image?.size.width ?? 0.0) + CGFloat(8.0)
|
||||||
@ -4707,6 +4710,8 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
|||||||
self.interfaceInteraction?.openScheduledMessages()
|
self.interfaceInteraction?.openScheduledMessages()
|
||||||
case .gift:
|
case .gift:
|
||||||
self.interfaceInteraction?.openPremiumGift()
|
self.interfaceInteraction?.openPremiumGift()
|
||||||
|
case .suggestPost:
|
||||||
|
self.interfaceInteraction?.openSuggestPost()
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3715,26 +3715,28 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func makeStarsAmountScreen(context: AccountContext, initialValue: Int64?, completion: @escaping (Int64) -> Void) -> ViewController {
|
public func makeStarsAmountScreen(context: AccountContext, initialValue: Int64?, completion: @escaping (Int64) -> Void) -> ViewController {
|
||||||
return StarsWithdrawScreen(context: context, mode: .paidMedia(initialValue), completion: completion)
|
return StarsWithdrawScreen(context: context, mode: .paidMedia(initialValue, completion: completion))
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makeStarsWithdrawalScreen(context: AccountContext, stats: StarsRevenueStats, completion: @escaping (Int64) -> Void) -> ViewController {
|
public func makeStarsWithdrawalScreen(context: AccountContext, stats: StarsRevenueStats, completion: @escaping (Int64) -> Void) -> ViewController {
|
||||||
return StarsWithdrawScreen(context: context, mode: .withdraw(stats), completion: completion)
|
return StarsWithdrawScreen(context: context, mode: .withdraw(stats, completion: completion))
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makeStarsWithdrawalScreen(context: AccountContext, subject: StarsWithdrawalScreenSubject, completion: @escaping (Int64) -> Void) -> ViewController {
|
public func makeStarsWithdrawalScreen(context: AccountContext, subject: StarsWithdrawalScreenSubject) -> ViewController {
|
||||||
let mode: StarsWithdrawScreen.Mode
|
let mode: StarsWithdrawScreen.Mode
|
||||||
switch subject {
|
switch subject {
|
||||||
case .withdraw:
|
case let .withdraw(completion):
|
||||||
mode = .accountWithdraw
|
mode = .accountWithdraw(completion: completion)
|
||||||
case let .enterAmount(current, minValue, fractionAfterCommission, kind):
|
case let .enterAmount(current, minValue, fractionAfterCommission, kind, completion):
|
||||||
mode = .paidMessages(current: current.value, minValue: minValue.value, fractionAfterCommission: fractionAfterCommission, kind: kind)
|
mode = .paidMessages(current: current.value, minValue: minValue.value, fractionAfterCommission: fractionAfterCommission, kind: kind, completion: completion)
|
||||||
|
case let .postSuggestion(channel, current, timestamp, completion):
|
||||||
|
mode = .suggestedPost(mode: .sender(channel: channel), price: current.value, timestamp: timestamp, completion: completion)
|
||||||
}
|
}
|
||||||
return StarsWithdrawScreen(context: context, mode: mode, completion: completion)
|
return StarsWithdrawScreen(context: context, mode: mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makeStarGiftResellScreen(context: AccountContext, gift: StarGift.UniqueGift, update: Bool, completion: @escaping (Int64) -> Void) -> ViewController {
|
public func makeStarGiftResellScreen(context: AccountContext, gift: StarGift.UniqueGift, update: Bool, completion: @escaping (Int64) -> Void) -> ViewController {
|
||||||
return StarsWithdrawScreen(context: context, mode: .starGiftResell(gift, update), completion: completion)
|
return StarsWithdrawScreen(context: context, mode: .starGiftResell(gift, update, completion: completion))
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makeStarsGiftScreen(context: AccountContext, message: EngineMessage) -> ViewController {
|
public func makeStarsGiftScreen(context: AccountContext, message: EngineMessage) -> ViewController {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user