mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-24 07:05:35 +00:00
Various improvements
This commit is contained in:
@@ -502,5 +502,26 @@ public extension TelegramEngine.EngineData.Item {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
public struct AudioTranscriptionTrial: TelegramEngineDataItem, PostboxViewDataItem {
|
||||
public typealias Result = AudioTranscription.TrialState
|
||||
|
||||
public init() {
|
||||
}
|
||||
|
||||
var key: PostboxViewKey {
|
||||
return .preferences(keys: Set([PreferencesKeys.audioTranscriptionTrialState]))
|
||||
}
|
||||
|
||||
func extract(view: PostboxView) -> Result {
|
||||
guard let view = view as? PreferencesView else {
|
||||
preconditionFailure()
|
||||
}
|
||||
guard let value = view.values[PreferencesKeys.audioTranscriptionTrialState]?.get(AudioTranscription.TrialState.self) else {
|
||||
return AudioTranscription.TrialState.defaultValue
|
||||
}
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ public final class EngineStoryViewListContext {
|
||||
}
|
||||
|
||||
public enum SortMode {
|
||||
case repostsFirst
|
||||
case reactionsFirst
|
||||
case recentFirst
|
||||
}
|
||||
@@ -176,6 +177,16 @@ public final class EngineStoryViewListContext {
|
||||
}
|
||||
}
|
||||
switch sortMode {
|
||||
case .repostsFirst:
|
||||
items.sort(by: { lhs, rhs in
|
||||
if (lhs.reaction == nil) != (rhs.reaction == nil) {
|
||||
return lhs.reaction != nil
|
||||
}
|
||||
if lhs.timestamp != rhs.timestamp {
|
||||
return lhs.timestamp > rhs.timestamp
|
||||
}
|
||||
return lhs.peer.id < rhs.peer.id
|
||||
})
|
||||
case .reactionsFirst:
|
||||
items.sort(by: { lhs, rhs in
|
||||
if (lhs.reaction == nil) != (rhs.reaction == nil) {
|
||||
@@ -287,7 +298,7 @@ public final class EngineStoryViewListContext {
|
||||
switch sortMode {
|
||||
case .reactionsFirst:
|
||||
flags |= (1 << 2)
|
||||
case .recentFirst:
|
||||
case .recentFirst, .repostsFirst:
|
||||
break
|
||||
}
|
||||
if searchQuery != nil {
|
||||
@@ -376,7 +387,8 @@ public final class EngineStoryViewListContext {
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
isMy: item.isMy,
|
||||
myReaction: item.myReaction
|
||||
myReaction: item.myReaction,
|
||||
forwardInfo: item.forwardInfo
|
||||
))
|
||||
if let entry = CodableEntry(updatedItem) {
|
||||
transaction.setStory(id: StoryId(peerId: account.peerId, id: storyId), value: entry)
|
||||
@@ -413,7 +425,8 @@ public final class EngineStoryViewListContext {
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
isMy: item.isMy,
|
||||
myReaction: item.myReaction
|
||||
myReaction: item.myReaction,
|
||||
forwardInfo: item.forwardInfo
|
||||
))
|
||||
if let entry = CodableEntry(updatedItem) {
|
||||
currentItems[i] = StoryItemsTableEntry(value: entry, id: updatedItem.id, expirationTimestamp: updatedItem.expirationTimestamp, isCloseFriends: updatedItem.isCloseFriends)
|
||||
|
||||
@@ -39,6 +39,40 @@ public extension Stories {
|
||||
}
|
||||
}
|
||||
|
||||
struct PendingForwardInfo: Codable, Equatable {
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case peerId = "peerId"
|
||||
case storyId = "storyId"
|
||||
case isForwardingDisabled = "isForwardingDisabled"
|
||||
}
|
||||
|
||||
public let peerId: EnginePeer.Id
|
||||
public let storyId: Int32
|
||||
public let isForwardingDisabled: Bool
|
||||
|
||||
public init(peerId: EnginePeer.Id, storyId: Int32, isForwardingDisabled: Bool) {
|
||||
self.peerId = peerId
|
||||
self.storyId = storyId
|
||||
self.isForwardingDisabled = isForwardingDisabled
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
self.peerId = EnginePeer.Id(try container.decode(Int64.self, forKey: .peerId))
|
||||
self.storyId = try container.decode(Int32.self, forKey: .storyId)
|
||||
self.isForwardingDisabled = try container.decode(Bool.self, forKey: .isForwardingDisabled)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try container.encode(self.peerId.toInt64(), forKey: .peerId)
|
||||
try container.encode(self.storyId, forKey: .storyId)
|
||||
try container.encode(self.isForwardingDisabled, forKey: .isForwardingDisabled)
|
||||
}
|
||||
}
|
||||
|
||||
final class PendingItem: Equatable, Codable {
|
||||
private enum CodingKeys: CodingKey {
|
||||
case target
|
||||
@@ -54,6 +88,7 @@ public extension Stories {
|
||||
case isForwardingDisabled
|
||||
case period
|
||||
case randomId
|
||||
case forwardInfo
|
||||
}
|
||||
|
||||
public let target: PendingTarget
|
||||
@@ -69,6 +104,7 @@ public extension Stories {
|
||||
public let isForwardingDisabled: Bool
|
||||
public let period: Int32
|
||||
public let randomId: Int64
|
||||
public let forwardInfo: PendingForwardInfo?
|
||||
|
||||
public init(
|
||||
target: PendingTarget,
|
||||
@@ -83,7 +119,8 @@ public extension Stories {
|
||||
privacy: EngineStoryPrivacy,
|
||||
isForwardingDisabled: Bool,
|
||||
period: Int32,
|
||||
randomId: Int64
|
||||
randomId: Int64,
|
||||
forwardInfo: PendingForwardInfo?
|
||||
) {
|
||||
self.target = target
|
||||
self.stableId = stableId
|
||||
@@ -98,6 +135,7 @@ public extension Stories {
|
||||
self.isForwardingDisabled = isForwardingDisabled
|
||||
self.period = period
|
||||
self.randomId = randomId
|
||||
self.forwardInfo = forwardInfo
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
@@ -123,6 +161,8 @@ public extension Stories {
|
||||
self.isForwardingDisabled = try container.decodeIfPresent(Bool.self, forKey: .isForwardingDisabled) ?? false
|
||||
self.period = try container.decode(Int32.self, forKey: .period)
|
||||
self.randomId = try container.decode(Int64.self, forKey: .randomId)
|
||||
|
||||
self.forwardInfo = try container.decodeIfPresent(PendingForwardInfo.self, forKey: .forwardInfo)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@@ -150,6 +190,7 @@ public extension Stories {
|
||||
try container.encode(self.isForwardingDisabled, forKey: .isForwardingDisabled)
|
||||
try container.encode(self.period, forKey: .period)
|
||||
try container.encode(self.randomId, forKey: .randomId)
|
||||
try container.encodeIfPresent(self.forwardInfo, forKey: .forwardInfo)
|
||||
}
|
||||
|
||||
public static func ==(lhs: PendingItem, rhs: PendingItem) -> Bool {
|
||||
@@ -186,6 +227,9 @@ public extension Stories {
|
||||
if lhs.randomId != rhs.randomId {
|
||||
return false
|
||||
}
|
||||
if lhs.forwardInfo != rhs.forwardInfo {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -359,8 +403,9 @@ final class PendingStoryManager {
|
||||
case let .peer(peerId):
|
||||
toPeerId = peerId
|
||||
}
|
||||
|
||||
let stableId = firstItem.stableId
|
||||
pendingItemContext.disposable = (_internal_uploadStoryImpl(postbox: self.postbox, network: self.network, accountPeerId: self.accountPeerId, stateManager: self.stateManager, messageMediaPreuploadManager: self.messageMediaPreuploadManager, revalidationContext: self.revalidationContext, auxiliaryMethods: self.auxiliaryMethods, toPeerId: toPeerId, stableId: stableId, media: firstItem.media, mediaAreas: firstItem.mediaAreas, text: firstItem.text, entities: firstItem.entities, embeddedStickers: firstItem.embeddedStickers, pin: firstItem.pin, privacy: firstItem.privacy, isForwardingDisabled: firstItem.isForwardingDisabled, period: Int(firstItem.period), randomId: firstItem.randomId)
|
||||
pendingItemContext.disposable = (_internal_uploadStoryImpl(postbox: self.postbox, network: self.network, accountPeerId: self.accountPeerId, stateManager: self.stateManager, messageMediaPreuploadManager: self.messageMediaPreuploadManager, revalidationContext: self.revalidationContext, auxiliaryMethods: self.auxiliaryMethods, toPeerId: toPeerId, stableId: stableId, media: firstItem.media, mediaAreas: firstItem.mediaAreas, text: firstItem.text, entities: firstItem.entities, embeddedStickers: firstItem.embeddedStickers, pin: firstItem.pin, privacy: firstItem.privacy, isForwardingDisabled: firstItem.isForwardingDisabled, period: Int(firstItem.period), randomId: firstItem.randomId, forwardInfo: firstItem.forwardInfo)
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] event in
|
||||
guard let `self` = self else {
|
||||
return
|
||||
|
||||
@@ -6,11 +6,14 @@ import TelegramApi
|
||||
public enum EngineStoryInputMedia {
|
||||
case image(dimensions: PixelDimensions, data: Data, stickers: [TelegramMediaFile])
|
||||
case video(dimensions: PixelDimensions, duration: Double, resource: TelegramMediaResource, firstFrameFile: TempBoxFile?, stickers: [TelegramMediaFile])
|
||||
case existing(media: Media)
|
||||
|
||||
var embeddedStickers: [TelegramMediaFile] {
|
||||
switch self {
|
||||
case let .image(_, _, stickers), let .video(_, _, _, _, stickers):
|
||||
return stickers
|
||||
case .existing:
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,6 +39,34 @@ public extension EngineStoryPrivacy {
|
||||
}
|
||||
}
|
||||
|
||||
public extension EngineStoryItem.ForwardInfo {
|
||||
init?(_ forwardInfo: Stories.Item.ForwardInfo, transaction: Transaction) {
|
||||
switch forwardInfo {
|
||||
case let .known(peerId, storyId):
|
||||
if let peer = transaction.getPeer(peerId) {
|
||||
self = .known(peer: EnginePeer(peer), storyId: storyId)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
case let .unknown(name):
|
||||
self = .unknown(name: name)
|
||||
}
|
||||
}
|
||||
|
||||
init?(_ forwardInfo: Stories.Item.ForwardInfo, peers: [PeerId: Peer]) {
|
||||
switch forwardInfo {
|
||||
case let .known(peerId, storyId):
|
||||
if let peer = peers[peerId] {
|
||||
self = .known(peer: EnginePeer(peer), storyId: storyId)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
case let .unknown(name):
|
||||
self = .unknown(name: name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum Stories {
|
||||
public final class Item: Codable, Equatable {
|
||||
public struct Views: Codable, Equatable {
|
||||
@@ -162,6 +193,49 @@ public enum Stories {
|
||||
}
|
||||
}
|
||||
|
||||
public enum ForwardInfo: Codable, Equatable {
|
||||
public enum DecodingError: Error {
|
||||
case generic
|
||||
}
|
||||
|
||||
private enum CodingKeys: CodingKey {
|
||||
case discriminator
|
||||
case authorPeerId
|
||||
case storyId
|
||||
case authorName
|
||||
}
|
||||
|
||||
case known(peerId: EnginePeer.Id, storyId: Int32)
|
||||
case unknown(name: String)
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
switch try container.decode(Int32.self, forKey: .discriminator) {
|
||||
case 0:
|
||||
self = .known(peerId: EnginePeer.Id(try container.decode(Int64.self, forKey: .authorPeerId)), storyId: try container.decode(Int32.self, forKey: .storyId))
|
||||
case 1:
|
||||
self = .unknown(name: try container.decode(String.self, forKey: .authorName))
|
||||
default:
|
||||
throw DecodingError.generic
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
switch self {
|
||||
case let .known(peerId, storyId):
|
||||
try container.encode(0 as Int32, forKey: .discriminator)
|
||||
try container.encode(peerId.toInt64(), forKey: .authorPeerId)
|
||||
try container.encode(storyId, forKey: .storyId)
|
||||
case let .unknown(name):
|
||||
try container.encode(1 as Int32, forKey: .discriminator)
|
||||
try container.encode(name, forKey: .authorName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case timestamp
|
||||
@@ -182,6 +256,7 @@ public enum Stories {
|
||||
case isEdited
|
||||
case isMy
|
||||
case myReaction
|
||||
case forwardInfo
|
||||
}
|
||||
|
||||
public let id: Int32
|
||||
@@ -203,6 +278,7 @@ public enum Stories {
|
||||
public let isEdited: Bool
|
||||
public let isMy: Bool
|
||||
public let myReaction: MessageReaction.Reaction?
|
||||
public let forwardInfo: ForwardInfo?
|
||||
|
||||
public init(
|
||||
id: Int32,
|
||||
@@ -223,7 +299,8 @@ public enum Stories {
|
||||
isForwardingDisabled: Bool,
|
||||
isEdited: Bool,
|
||||
isMy: Bool,
|
||||
myReaction: MessageReaction.Reaction?
|
||||
myReaction: MessageReaction.Reaction?,
|
||||
forwardInfo: ForwardInfo?
|
||||
) {
|
||||
self.id = id
|
||||
self.timestamp = timestamp
|
||||
@@ -244,6 +321,7 @@ public enum Stories {
|
||||
self.isEdited = isEdited
|
||||
self.isMy = isMy
|
||||
self.myReaction = myReaction
|
||||
self.forwardInfo = forwardInfo
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
@@ -274,6 +352,7 @@ public enum Stories {
|
||||
self.isEdited = try container.decodeIfPresent(Bool.self, forKey: .isEdited) ?? false
|
||||
self.isMy = try container.decodeIfPresent(Bool.self, forKey: .isMy) ?? false
|
||||
self.myReaction = try container.decodeIfPresent(MessageReaction.Reaction.self, forKey: .myReaction)
|
||||
self.forwardInfo = try container.decodeIfPresent(ForwardInfo.self, forKey: .forwardInfo)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@@ -305,6 +384,7 @@ public enum Stories {
|
||||
try container.encode(self.isEdited, forKey: .isEdited)
|
||||
try container.encode(self.isMy, forKey: .isMy)
|
||||
try container.encodeIfPresent(self.myReaction, forKey: .myReaction)
|
||||
try container.encodeIfPresent(self.forwardInfo, forKey: .forwardInfo)
|
||||
}
|
||||
|
||||
public static func ==(lhs: Item, rhs: Item) -> Bool {
|
||||
@@ -369,7 +449,9 @@ public enum Stories {
|
||||
if lhs.myReaction != rhs.myReaction {
|
||||
return false
|
||||
}
|
||||
|
||||
if lhs.forwardInfo != rhs.forwardInfo {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -752,6 +834,8 @@ private func prepareUploadStoryContent(account: Account, media: EngineStoryInput
|
||||
)
|
||||
|
||||
return fileMedia
|
||||
case let .existing(media):
|
||||
return media
|
||||
}
|
||||
}
|
||||
|
||||
@@ -845,7 +929,7 @@ private func apiInputPrivacyRules(privacy: EngineStoryPrivacy, transaction: Tran
|
||||
return privacyRules
|
||||
}
|
||||
|
||||
func _internal_uploadStory(account: Account, target: Stories.PendingTarget, media: EngineStoryInputMedia, mediaAreas: [MediaArea], text: String, entities: [MessageTextEntity], pin: Bool, privacy: EngineStoryPrivacy, isForwardingDisabled: Bool, period: Int, randomId: Int64) -> Signal<Int32, NoError> {
|
||||
func _internal_uploadStory(account: Account, target: Stories.PendingTarget, media: EngineStoryInputMedia, mediaAreas: [MediaArea], text: String, entities: [MessageTextEntity], pin: Bool, privacy: EngineStoryPrivacy, isForwardingDisabled: Bool, period: Int, randomId: Int64, forwardInfo: Stories.PendingForwardInfo?) -> Signal<Int32, NoError> {
|
||||
let inputMedia = prepareUploadStoryContent(account: account, media: media)
|
||||
|
||||
return (account.postbox.transaction { transaction in
|
||||
@@ -872,7 +956,8 @@ func _internal_uploadStory(account: Account, target: Stories.PendingTarget, medi
|
||||
privacy: privacy,
|
||||
isForwardingDisabled: isForwardingDisabled,
|
||||
period: Int32(period),
|
||||
randomId: randomId
|
||||
randomId: randomId,
|
||||
forwardInfo: forwardInfo
|
||||
))
|
||||
transaction.setLocalStoryState(state: CodableEntry(currentState))
|
||||
return stableId
|
||||
@@ -917,7 +1002,28 @@ private func _internal_putPendingStoryIdMapping(peerId: PeerId, stableId: Int32,
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_uploadStoryImpl(postbox: Postbox, network: Network, accountPeerId: PeerId, stateManager: AccountStateManager, messageMediaPreuploadManager: MessageMediaPreuploadManager, revalidationContext: MediaReferenceRevalidationContext, auxiliaryMethods: AccountAuxiliaryMethods, toPeerId: PeerId, stableId: Int32, media: Media, mediaAreas: [MediaArea], text: String, entities: [MessageTextEntity], embeddedStickers: [TelegramMediaFile], pin: Bool, privacy: EngineStoryPrivacy, isForwardingDisabled: Bool, period: Int, randomId: Int64) -> Signal<StoryUploadResult, NoError> {
|
||||
func _internal_uploadStoryImpl(
|
||||
postbox: Postbox,
|
||||
network: Network,
|
||||
accountPeerId: PeerId,
|
||||
stateManager: AccountStateManager,
|
||||
messageMediaPreuploadManager: MessageMediaPreuploadManager,
|
||||
revalidationContext: MediaReferenceRevalidationContext,
|
||||
auxiliaryMethods: AccountAuxiliaryMethods,
|
||||
toPeerId: PeerId,
|
||||
stableId: Int32,
|
||||
media: Media,
|
||||
mediaAreas: [MediaArea],
|
||||
text: String,
|
||||
entities: [MessageTextEntity],
|
||||
embeddedStickers: [TelegramMediaFile],
|
||||
pin: Bool,
|
||||
privacy: EngineStoryPrivacy,
|
||||
isForwardingDisabled: Bool,
|
||||
period: Int,
|
||||
randomId: Int64,
|
||||
forwardInfo: Stories.PendingForwardInfo?
|
||||
) -> Signal<StoryUploadResult, NoError> {
|
||||
return postbox.transaction { transaction -> Api.InputPeer? in
|
||||
return transaction.getPeer(toPeerId).flatMap(apiInputPeer)
|
||||
}
|
||||
@@ -975,6 +1081,14 @@ func _internal_uploadStoryImpl(postbox: Postbox, network: Network, accountPeerId
|
||||
flags |= 1 << 5
|
||||
}
|
||||
|
||||
var fwdFromId: Api.InputPeer?
|
||||
var fwdFromStory: Int32?
|
||||
if let forwardInfo = forwardInfo, let inputPeer = transaction.getPeer(forwardInfo.peerId).flatMap({ apiInputPeer($0) }) {
|
||||
flags |= 1 << 6
|
||||
fwdFromId = inputPeer
|
||||
fwdFromStory = forwardInfo.storyId
|
||||
}
|
||||
|
||||
return network.request(Api.functions.stories.sendStory(
|
||||
flags: flags,
|
||||
peer: inputPeer,
|
||||
@@ -985,8 +1099,8 @@ func _internal_uploadStoryImpl(postbox: Postbox, network: Network, accountPeerId
|
||||
privacyRules: privacyRules,
|
||||
randomId: randomId,
|
||||
period: Int32(period),
|
||||
fwdFromId: nil,
|
||||
fwdFromStory: nil
|
||||
fwdFromId: fwdFromId,
|
||||
fwdFromStory: fwdFromStory
|
||||
))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
|
||||
@@ -1034,7 +1148,8 @@ func _internal_uploadStoryImpl(postbox: Postbox, network: Network, accountPeerId
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
isMy: item.isMy,
|
||||
myReaction: item.myReaction
|
||||
myReaction: item.myReaction,
|
||||
forwardInfo: item.forwardInfo
|
||||
)
|
||||
if let entry = CodableEntry(Stories.StoredItem.item(updatedItem)) {
|
||||
items.append(StoryItemsTableEntry(value: entry, id: item.id, expirationTimestamp: updatedItem.expirationTimestamp, isCloseFriends: updatedItem.isCloseFriends))
|
||||
@@ -1214,7 +1329,8 @@ func _internal_editStoryPrivacy(account: Account, id: Int32, privacy: EngineStor
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
isMy: item.isMy,
|
||||
myReaction: item.myReaction
|
||||
myReaction: item.myReaction,
|
||||
forwardInfo: item.forwardInfo
|
||||
)
|
||||
if let entry = CodableEntry(Stories.StoredItem.item(updatedItem)) {
|
||||
transaction.setStory(id: storyId, value: entry)
|
||||
@@ -1243,7 +1359,8 @@ func _internal_editStoryPrivacy(account: Account, id: Int32, privacy: EngineStor
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
isMy: item.isMy,
|
||||
myReaction: item.myReaction
|
||||
myReaction: item.myReaction,
|
||||
forwardInfo: item.forwardInfo
|
||||
)
|
||||
if let entry = CodableEntry(Stories.StoredItem.item(updatedItem)) {
|
||||
items[index] = StoryItemsTableEntry(value: entry, id: item.id, expirationTimestamp: updatedItem.expirationTimestamp, isCloseFriends: updatedItem.isCloseFriends)
|
||||
@@ -1435,7 +1552,8 @@ func _internal_updateStoriesArePinned(account: Account, peerId: PeerId, ids: [In
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
isMy: item.isMy,
|
||||
myReaction: item.myReaction
|
||||
myReaction: item.myReaction,
|
||||
forwardInfo: item.forwardInfo
|
||||
)
|
||||
if let entry = CodableEntry(Stories.StoredItem.item(updatedItem)) {
|
||||
items[index] = StoryItemsTableEntry(value: entry, id: item.id, expirationTimestamp: updatedItem.expirationTimestamp, isCloseFriends: updatedItem.isCloseFriends)
|
||||
@@ -1463,7 +1581,8 @@ func _internal_updateStoriesArePinned(account: Account, peerId: PeerId, ids: [In
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
isMy: item.isMy,
|
||||
myReaction: item.myReaction
|
||||
myReaction: item.myReaction,
|
||||
forwardInfo: item.forwardInfo
|
||||
)
|
||||
updatedItems.append(updatedItem)
|
||||
}
|
||||
@@ -1538,11 +1657,26 @@ extension Stories.Item.Views {
|
||||
}
|
||||
}
|
||||
|
||||
extension Stories.Item.ForwardInfo {
|
||||
init?(apiForwardInfo: Api.StoryFwdHeader) {
|
||||
switch apiForwardInfo {
|
||||
case let .storyFwdHeader(_, from, fromName, storyId):
|
||||
if let from = from, let storyId = storyId {
|
||||
self = .known(peerId: from.peerId, storyId: storyId)
|
||||
return
|
||||
} else if let fromName = fromName {
|
||||
self = .unknown(name: fromName)
|
||||
return
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
extension Stories.StoredItem {
|
||||
init?(apiStoryItem: Api.StoryItem, existingItem: Stories.Item? = nil, peerId: PeerId, transaction: Transaction) {
|
||||
switch apiStoryItem {
|
||||
case let .storyItem(flags, id, date, fwdFrom, expireDate, caption, entities, media, mediaAreas, privacy, views, sentReaction):
|
||||
let _ = fwdFrom
|
||||
case let .storyItem(flags, id, date, forwardFrom, expireDate, caption, entities, media, mediaAreas, privacy, views, sentReaction):
|
||||
let (parsedMedia, _, _, _, _) = textMediaAndExpirationTimerFromApiMedia(media, peerId)
|
||||
if let parsedMedia = parsedMedia {
|
||||
var parsedPrivacy: Stories.Item.Privacy?
|
||||
@@ -1613,6 +1747,13 @@ extension Stories.StoredItem {
|
||||
mergedIsMy = (flags & (1 << 16)) != 0
|
||||
}
|
||||
|
||||
var mergedForwardInfo: Stories.Item.ForwardInfo?
|
||||
if isMin, let existingItem = existingItem {
|
||||
mergedForwardInfo = existingItem.forwardInfo
|
||||
} else {
|
||||
mergedForwardInfo = forwardFrom.flatMap(Stories.Item.ForwardInfo.init(apiForwardInfo:))
|
||||
}
|
||||
|
||||
let item = Stories.Item(
|
||||
id: id,
|
||||
timestamp: date,
|
||||
@@ -1632,7 +1773,8 @@ extension Stories.StoredItem {
|
||||
isForwardingDisabled: isForwardingDisabled,
|
||||
isEdited: isEdited,
|
||||
isMy: mergedIsMy,
|
||||
myReaction: mergedMyReaction
|
||||
myReaction: mergedMyReaction,
|
||||
forwardInfo: mergedForwardInfo
|
||||
)
|
||||
self = .item(item)
|
||||
} else {
|
||||
@@ -2104,7 +2246,8 @@ func _internal_setStoryReaction(account: Account, peerId: EnginePeer.Id, id: Int
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
isMy: item.isMy,
|
||||
myReaction: reaction
|
||||
myReaction: reaction,
|
||||
forwardInfo: item.forwardInfo
|
||||
))
|
||||
updatedItemValue = updatedItem
|
||||
if let entry = CodableEntry(updatedItem) {
|
||||
@@ -2135,7 +2278,8 @@ func _internal_setStoryReaction(account: Account, peerId: EnginePeer.Id, id: Int
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
isMy: item.isMy,
|
||||
myReaction: reaction
|
||||
myReaction: reaction,
|
||||
forwardInfo: item.forwardInfo
|
||||
))
|
||||
updatedItemValue = updatedItem
|
||||
if let entry = CodableEntry(updatedItem) {
|
||||
|
||||
@@ -51,6 +51,11 @@ public final class EngineStoryItem: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public enum ForwardInfo: Equatable {
|
||||
case known(peer: EnginePeer, storyId: Int32)
|
||||
case unknown(name: String)
|
||||
}
|
||||
|
||||
public let id: Int32
|
||||
public let timestamp: Int32
|
||||
public let expirationTimestamp: Int32
|
||||
@@ -71,8 +76,9 @@ public final class EngineStoryItem: Equatable {
|
||||
public let isEdited: Bool
|
||||
public let isMy: Bool
|
||||
public let myReaction: MessageReaction.Reaction?
|
||||
public let forwardInfo: ForwardInfo?
|
||||
|
||||
public init(id: Int32, timestamp: Int32, expirationTimestamp: Int32, media: EngineMedia, mediaAreas: [MediaArea], text: String, entities: [MessageTextEntity], views: Views?, privacy: EngineStoryPrivacy?, isPinned: Bool, isExpired: Bool, isPublic: Bool, isPending: Bool, isCloseFriends: Bool, isContacts: Bool, isSelectedContacts: Bool, isForwardingDisabled: Bool, isEdited: Bool, isMy: Bool, myReaction: MessageReaction.Reaction?) {
|
||||
public init(id: Int32, timestamp: Int32, expirationTimestamp: Int32, media: EngineMedia, mediaAreas: [MediaArea], text: String, entities: [MessageTextEntity], views: Views?, privacy: EngineStoryPrivacy?, isPinned: Bool, isExpired: Bool, isPublic: Bool, isPending: Bool, isCloseFriends: Bool, isContacts: Bool, isSelectedContacts: Bool, isForwardingDisabled: Bool, isEdited: Bool, isMy: Bool, myReaction: MessageReaction.Reaction?, forwardInfo: ForwardInfo?) {
|
||||
self.id = id
|
||||
self.timestamp = timestamp
|
||||
self.expirationTimestamp = expirationTimestamp
|
||||
@@ -93,6 +99,7 @@ public final class EngineStoryItem: Equatable {
|
||||
self.isEdited = isEdited
|
||||
self.isMy = isMy
|
||||
self.myReaction = myReaction
|
||||
self.forwardInfo = forwardInfo
|
||||
}
|
||||
|
||||
public static func ==(lhs: EngineStoryItem, rhs: EngineStoryItem) -> Bool {
|
||||
@@ -156,11 +163,25 @@ public final class EngineStoryItem: Equatable {
|
||||
if lhs.myReaction != rhs.myReaction {
|
||||
return false
|
||||
}
|
||||
if lhs.forwardInfo != rhs.forwardInfo {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension EngineStoryItem {
|
||||
extension EngineStoryItem.ForwardInfo {
|
||||
var storedForwardInfo: Stories.Item.ForwardInfo {
|
||||
switch self {
|
||||
case let .known(peer, storyId):
|
||||
return .known(peerId: peer.id, storyId: storyId)
|
||||
case let .unknown(name):
|
||||
return .unknown(name: name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension EngineStoryItem {
|
||||
func asStoryItem() -> Stories.Item {
|
||||
return Stories.Item(
|
||||
id: self.id,
|
||||
@@ -195,7 +216,8 @@ extension EngineStoryItem {
|
||||
isForwardingDisabled: self.isForwardingDisabled,
|
||||
isEdited: self.isEdited,
|
||||
isMy: self.isMy,
|
||||
myReaction: self.myReaction
|
||||
myReaction: self.myReaction,
|
||||
forwardInfo: self.forwardInfo?.storedForwardInfo
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -570,7 +592,8 @@ public final class PeerStoryListContext {
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
isMy: item.isMy,
|
||||
myReaction: item.myReaction
|
||||
myReaction: item.myReaction,
|
||||
forwardInfo: item.forwardInfo.flatMap { EngineStoryItem.ForwardInfo($0, transaction: transaction) }
|
||||
)
|
||||
items.append(mappedItem)
|
||||
|
||||
@@ -713,7 +736,8 @@ public final class PeerStoryListContext {
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
isMy: item.isMy,
|
||||
myReaction: item.myReaction
|
||||
myReaction: item.myReaction,
|
||||
forwardInfo: item.forwardInfo.flatMap { EngineStoryItem.ForwardInfo($0, transaction: transaction) }
|
||||
)
|
||||
storyItems.append(mappedItem)
|
||||
}
|
||||
@@ -802,6 +826,11 @@ public final class PeerStoryListContext {
|
||||
}
|
||||
}
|
||||
}
|
||||
if let forwardInfo = item.forwardInfo, case let .known(peerId, _) = forwardInfo {
|
||||
if let peer = transaction.getPeer(peerId) {
|
||||
peers[peer.id] = peer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
@@ -868,7 +897,8 @@ public final class PeerStoryListContext {
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
isMy: item.isMy,
|
||||
myReaction: item.myReaction
|
||||
myReaction: item.myReaction,
|
||||
forwardInfo: item.forwardInfo.flatMap { EngineStoryItem.ForwardInfo($0, peers: peers) }
|
||||
)
|
||||
finalUpdatedState = updatedState
|
||||
}
|
||||
@@ -914,7 +944,8 @@ public final class PeerStoryListContext {
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
isMy: item.isMy,
|
||||
myReaction: item.myReaction
|
||||
myReaction: item.myReaction,
|
||||
forwardInfo: item.forwardInfo.flatMap { EngineStoryItem.ForwardInfo($0, peers: peers) }
|
||||
)
|
||||
finalUpdatedState = updatedState
|
||||
} else {
|
||||
@@ -962,7 +993,8 @@ public final class PeerStoryListContext {
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
isMy: item.isMy,
|
||||
myReaction: item.myReaction
|
||||
myReaction: item.myReaction,
|
||||
forwardInfo: item.forwardInfo.flatMap { EngineStoryItem.ForwardInfo($0, peers: peers) }
|
||||
))
|
||||
updatedState.items.sort(by: { lhs, rhs in
|
||||
return lhs.timestamp > rhs.timestamp
|
||||
@@ -1006,7 +1038,8 @@ public final class PeerStoryListContext {
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
isMy: item.isMy,
|
||||
myReaction: item.myReaction
|
||||
myReaction: item.myReaction,
|
||||
forwardInfo: item.forwardInfo.flatMap { EngineStoryItem.ForwardInfo($0, peers: peers) }
|
||||
))
|
||||
updatedState.items.sort(by: { lhs, rhs in
|
||||
return lhs.timestamp > rhs.timestamp
|
||||
@@ -1174,7 +1207,8 @@ public final class PeerExpiringStoryListContext {
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
isMy: item.isMy,
|
||||
myReaction: item.myReaction
|
||||
myReaction: item.myReaction,
|
||||
forwardInfo: item.forwardInfo.flatMap { EngineStoryItem.ForwardInfo($0, transaction: transaction) }
|
||||
)
|
||||
items.append(.item(mappedItem))
|
||||
}
|
||||
|
||||
@@ -476,7 +476,7 @@ public extension TelegramEngine {
|
||||
public func transcribeAudio(messageId: MessageId) -> Signal<EngineAudioTranscriptionResult, NoError> {
|
||||
return _internal_transcribeAudio(postbox: self.account.postbox, network: self.account.network, messageId: messageId)
|
||||
}
|
||||
|
||||
|
||||
public func storeLocallyTranscribedAudio(messageId: MessageId, text: String, isFinal: Bool, error: AudioTranscriptionMessageAttribute.TranscriptionError?) -> Signal<Never, NoError> {
|
||||
return self.account.postbox.transaction { transaction -> Void in
|
||||
transaction.updateMessage(messageId, update: { currentMessage in
|
||||
@@ -1178,7 +1178,8 @@ public extension TelegramEngine {
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
isMy: item.isMy,
|
||||
myReaction: item.myReaction
|
||||
myReaction: item.myReaction,
|
||||
forwardInfo: item.forwardInfo
|
||||
))
|
||||
if let entry = CodableEntry(updatedItem) {
|
||||
currentItems[i] = StoryItemsTableEntry(value: entry, id: updatedItem.id, expirationTimestamp: updatedItem.expirationTimestamp, isCloseFriends: updatedItem.isCloseFriends)
|
||||
@@ -1192,8 +1193,8 @@ public extension TelegramEngine {
|
||||
}
|
||||
}
|
||||
|
||||
public func uploadStory(target: Stories.PendingTarget, media: EngineStoryInputMedia, mediaAreas: [MediaArea], text: String, entities: [MessageTextEntity], pin: Bool, privacy: EngineStoryPrivacy, isForwardingDisabled: Bool, period: Int, randomId: Int64) -> Signal<Int32, NoError> {
|
||||
return _internal_uploadStory(account: self.account, target: target, media: media, mediaAreas: mediaAreas, text: text, entities: entities, pin: pin, privacy: privacy, isForwardingDisabled: isForwardingDisabled, period: period, randomId: randomId)
|
||||
public func uploadStory(target: Stories.PendingTarget, media: EngineStoryInputMedia, mediaAreas: [MediaArea], text: String, entities: [MessageTextEntity], pin: Bool, privacy: EngineStoryPrivacy, isForwardingDisabled: Bool, period: Int, randomId: Int64, forwardInfo: Stories.PendingForwardInfo?) -> Signal<Int32, NoError> {
|
||||
return _internal_uploadStory(account: self.account, target: target, media: media, mediaAreas: mediaAreas, text: text, entities: entities, pin: pin, privacy: privacy, isForwardingDisabled: isForwardingDisabled, period: period, randomId: randomId, forwardInfo: forwardInfo)
|
||||
}
|
||||
|
||||
public func allStoriesUploadEvents() -> Signal<(Int32, Int32), NoError> {
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import TelegramApi
|
||||
import MtProtoKit
|
||||
|
||||
public enum EngineAudioTranscriptionResult {
|
||||
case success
|
||||
case error
|
||||
}
|
||||
|
||||
func _internal_transcribeAudio(postbox: Postbox, network: Network, messageId: MessageId) -> Signal<EngineAudioTranscriptionResult, NoError> {
|
||||
return postbox.transaction { transaction -> Api.InputPeer? in
|
||||
return transaction.getPeer(messageId.peerId).flatMap(apiInputPeer)
|
||||
}
|
||||
|> mapToSignal { inputPeer -> Signal<EngineAudioTranscriptionResult, NoError> in
|
||||
guard let inputPeer = inputPeer else {
|
||||
return .single(.error)
|
||||
}
|
||||
return network.request(Api.functions.messages.transcribeAudio(peer: inputPeer, msgId: messageId.id))
|
||||
|> map { result -> Result<Api.messages.TranscribedAudio, AudioTranscriptionMessageAttribute.TranscriptionError> in
|
||||
return .success(result)
|
||||
}
|
||||
|> `catch` { error -> Signal<Result<Api.messages.TranscribedAudio, AudioTranscriptionMessageAttribute.TranscriptionError>, NoError> in
|
||||
let mappedError: AudioTranscriptionMessageAttribute.TranscriptionError
|
||||
if error.errorDescription == "MSG_VOICE_TOO_LONG" {
|
||||
mappedError = .tooLong
|
||||
} else {
|
||||
mappedError = .generic
|
||||
}
|
||||
return .single(.failure(mappedError))
|
||||
}
|
||||
|> mapToSignal { result -> Signal<EngineAudioTranscriptionResult, NoError> in
|
||||
return postbox.transaction { transaction -> EngineAudioTranscriptionResult in
|
||||
let updatedAttribute: AudioTranscriptionMessageAttribute
|
||||
switch result {
|
||||
case let .success(transcribedAudio):
|
||||
switch transcribedAudio {
|
||||
case let .transcribedAudio(flags, transcriptionId, text, trialRemainingCount, trialUntilDate):
|
||||
let isPending = (flags & (1 << 0)) != 0
|
||||
|
||||
_internal_updateAudioTranscriptionTrialState(transaction: transaction) { current in
|
||||
var updated = current
|
||||
if let trialRemainingCount = trialRemainingCount, trialRemainingCount > 0 {
|
||||
updated = updated.withUpdatedRemainingCount(trialRemainingCount)
|
||||
} else if let trialUntilDate = trialUntilDate {
|
||||
updated = updated.withUpdatedCooldownUntilTime(trialUntilDate)
|
||||
} else {
|
||||
updated = updated.withUpdatedCooldownUntilTime(nil)
|
||||
}
|
||||
return updated
|
||||
}
|
||||
updatedAttribute = AudioTranscriptionMessageAttribute(id: transcriptionId, text: text, isPending: isPending, didRate: false, error: nil)
|
||||
}
|
||||
case let .failure(error):
|
||||
updatedAttribute = AudioTranscriptionMessageAttribute(id: 0, text: "", isPending: false, didRate: false, error: error)
|
||||
}
|
||||
|
||||
transaction.updateMessage(messageId, update: { currentMessage in
|
||||
let storeForwardInfo = currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init)
|
||||
var attributes = currentMessage.attributes.filter { !($0 is AudioTranscriptionMessageAttribute) }
|
||||
|
||||
attributes.append(updatedAttribute)
|
||||
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
|
||||
if updatedAttribute.error == nil {
|
||||
return .success
|
||||
} else {
|
||||
return .error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_rateAudioTranscription(postbox: Postbox, network: Network, messageId: MessageId, id: Int64, isGood: Bool) -> Signal<Never, NoError> {
|
||||
return postbox.transaction { transaction -> Api.InputPeer? in
|
||||
transaction.updateMessage(messageId, update: { currentMessage in
|
||||
var storeForwardInfo: StoreMessageForwardInfo?
|
||||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
|
||||
}
|
||||
var attributes = currentMessage.attributes
|
||||
for i in 0 ..< attributes.count {
|
||||
if let attribute = attributes[i] as? AudioTranscriptionMessageAttribute {
|
||||
attributes[i] = attribute.withDidRate()
|
||||
}
|
||||
}
|
||||
return .update(StoreMessage(
|
||||
id: currentMessage.id,
|
||||
globallyUniqueId: currentMessage.globallyUniqueId,
|
||||
groupingKey: currentMessage.groupingKey,
|
||||
threadId: currentMessage.threadId,
|
||||
timestamp: currentMessage.timestamp,
|
||||
flags: StoreMessageFlags(currentMessage.flags),
|
||||
tags: currentMessage.tags,
|
||||
globalTags: currentMessage.globalTags,
|
||||
localTags: currentMessage.localTags,
|
||||
forwardInfo: storeForwardInfo,
|
||||
authorId: currentMessage.author?.id,
|
||||
text: currentMessage.text,
|
||||
attributes: attributes,
|
||||
media: currentMessage.media
|
||||
))
|
||||
})
|
||||
|
||||
return transaction.getPeer(messageId.peerId).flatMap(apiInputPeer)
|
||||
}
|
||||
|> mapToSignal { inputPeer -> Signal<Never, NoError> in
|
||||
guard let inputPeer = inputPeer else {
|
||||
return .complete()
|
||||
}
|
||||
return network.request(Api.functions.messages.rateTranscribedAudio(peer: inputPeer, msgId: messageId.id, transcriptionId: id, good: isGood ? .boolTrue : .boolFalse))
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
}
|
||||
|
||||
public enum AudioTranscription {
|
||||
public struct TrialState: Equatable, Codable {
|
||||
public let cooldownUntilTime: Int32?
|
||||
public let remainingCount: Int32
|
||||
|
||||
func withUpdatedCooldownUntilTime(_ time: Int32?) -> AudioTranscription.TrialState {
|
||||
return AudioTranscription.TrialState(cooldownUntilTime: time, remainingCount: time != nil ? 0 : max(1, self.remainingCount))
|
||||
}
|
||||
|
||||
func withUpdatedRemainingCount(_ remainingCount: Int32) -> AudioTranscription.TrialState {
|
||||
return AudioTranscription.TrialState(remainingCount: remainingCount)
|
||||
}
|
||||
|
||||
public init(cooldownUntilTime: Int32? = nil, remainingCount: Int32) {
|
||||
self.cooldownUntilTime = cooldownUntilTime
|
||||
self.remainingCount = remainingCount
|
||||
}
|
||||
|
||||
public static var defaultValue: AudioTranscription.TrialState {
|
||||
return AudioTranscription.TrialState(
|
||||
cooldownUntilTime: nil,
|
||||
remainingCount: 1
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_updateAudioTranscriptionTrialState(transaction: Transaction, _ f: (AudioTranscription.TrialState) -> AudioTranscription.TrialState) {
|
||||
let current = transaction.getPreferencesEntry(key: PreferencesKeys.audioTranscriptionTrialState)?.get(AudioTranscription.TrialState.self) ?? .defaultValue
|
||||
transaction.setPreferencesEntry(key: PreferencesKeys.audioTranscriptionTrialState, value: PreferencesEntry(f(current)))
|
||||
}
|
||||
@@ -155,108 +155,3 @@ func _internal_togglePeerMessagesTranslationHidden(account: Account, peerId: Eng
|
||||
|> ignoreValues
|
||||
}
|
||||
}
|
||||
|
||||
public enum EngineAudioTranscriptionResult {
|
||||
case success
|
||||
case error
|
||||
}
|
||||
|
||||
func _internal_transcribeAudio(postbox: Postbox, network: Network, messageId: MessageId) -> Signal<EngineAudioTranscriptionResult, NoError> {
|
||||
return postbox.transaction { transaction -> Api.InputPeer? in
|
||||
return transaction.getPeer(messageId.peerId).flatMap(apiInputPeer)
|
||||
}
|
||||
|> mapToSignal { inputPeer -> Signal<EngineAudioTranscriptionResult, NoError> in
|
||||
guard let inputPeer = inputPeer else {
|
||||
return .single(.error)
|
||||
}
|
||||
return network.request(Api.functions.messages.transcribeAudio(peer: inputPeer, msgId: messageId.id))
|
||||
|> map { result -> Result<Api.messages.TranscribedAudio, AudioTranscriptionMessageAttribute.TranscriptionError> in
|
||||
return .success(result)
|
||||
}
|
||||
|> `catch` { error -> Signal<Result<Api.messages.TranscribedAudio, AudioTranscriptionMessageAttribute.TranscriptionError>, NoError> in
|
||||
let mappedError: AudioTranscriptionMessageAttribute.TranscriptionError
|
||||
if error.errorDescription == "MSG_VOICE_TOO_LONG" {
|
||||
mappedError = .tooLong
|
||||
} else {
|
||||
mappedError = .generic
|
||||
}
|
||||
return .single(.failure(mappedError))
|
||||
}
|
||||
|> mapToSignal { result -> Signal<EngineAudioTranscriptionResult, NoError> in
|
||||
return postbox.transaction { transaction -> EngineAudioTranscriptionResult in
|
||||
let updatedAttribute: AudioTranscriptionMessageAttribute
|
||||
switch result {
|
||||
case let .success(transcribedAudio):
|
||||
switch transcribedAudio {
|
||||
case let .transcribedAudio(flags, transcriptionId, text):
|
||||
let isPending = (flags & (1 << 0)) != 0
|
||||
|
||||
updatedAttribute = AudioTranscriptionMessageAttribute(id: transcriptionId, text: text, isPending: isPending, didRate: false, error: nil)
|
||||
}
|
||||
case let .failure(error):
|
||||
updatedAttribute = AudioTranscriptionMessageAttribute(id: 0, text: "", isPending: false, didRate: false, error: error)
|
||||
}
|
||||
|
||||
transaction.updateMessage(messageId, update: { currentMessage in
|
||||
let storeForwardInfo = currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init)
|
||||
var attributes = currentMessage.attributes.filter { !($0 is AudioTranscriptionMessageAttribute) }
|
||||
|
||||
attributes.append(updatedAttribute)
|
||||
|
||||
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
|
||||
})
|
||||
|
||||
if updatedAttribute.error == nil {
|
||||
return .success
|
||||
} else {
|
||||
return .error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_rateAudioTranscription(postbox: Postbox, network: Network, messageId: MessageId, id: Int64, isGood: Bool) -> Signal<Never, NoError> {
|
||||
return postbox.transaction { transaction -> Api.InputPeer? in
|
||||
transaction.updateMessage(messageId, update: { currentMessage in
|
||||
var storeForwardInfo: StoreMessageForwardInfo?
|
||||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
|
||||
}
|
||||
var attributes = currentMessage.attributes
|
||||
for i in 0 ..< attributes.count {
|
||||
if let attribute = attributes[i] as? AudioTranscriptionMessageAttribute {
|
||||
attributes[i] = attribute.withDidRate()
|
||||
}
|
||||
}
|
||||
return .update(StoreMessage(
|
||||
id: currentMessage.id,
|
||||
globallyUniqueId: currentMessage.globallyUniqueId,
|
||||
groupingKey: currentMessage.groupingKey,
|
||||
threadId: currentMessage.threadId,
|
||||
timestamp: currentMessage.timestamp,
|
||||
flags: StoreMessageFlags(currentMessage.flags),
|
||||
tags: currentMessage.tags,
|
||||
globalTags: currentMessage.globalTags,
|
||||
localTags: currentMessage.localTags,
|
||||
forwardInfo: storeForwardInfo,
|
||||
authorId: currentMessage.author?.id,
|
||||
text: currentMessage.text,
|
||||
attributes: attributes,
|
||||
media: currentMessage.media
|
||||
))
|
||||
})
|
||||
|
||||
return transaction.getPeer(messageId.peerId).flatMap(apiInputPeer)
|
||||
}
|
||||
|> mapToSignal { inputPeer -> Signal<Never, NoError> in
|
||||
guard let inputPeer = inputPeer else {
|
||||
return .complete()
|
||||
}
|
||||
return network.request(Api.functions.messages.rateTranscribedAudio(peer: inputPeer, msgId: messageId.id, transcriptionId: id, good: isGood ? .boolTrue : .boolFalse))
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,17 +104,23 @@ func _internal_recommendedChannels(account: Account, peerId: EnginePeer.Id) -> S
|
||||
let key = PostboxViewKey.cachedItem(entryId(peerId: peerId))
|
||||
return account.postbox.combinedView(keys: [key])
|
||||
|> mapToSignal { views -> Signal<RecommendedChannels?, NoError> in
|
||||
guard let cachedChannels = (views.views[key] as? CachedItemView)?.value?.get(CachedRecommendedChannels.self) else {
|
||||
guard let cachedChannels = (views.views[key] as? CachedItemView)?.value?.get(CachedRecommendedChannels.self), !cachedChannels.peerIds.isEmpty else {
|
||||
return .single(nil)
|
||||
}
|
||||
return account.postbox.transaction { transaction -> RecommendedChannels? in
|
||||
var channels: [RecommendedChannels.Channel] = []
|
||||
for peerId in cachedChannels.peerIds {
|
||||
if let peer = transaction.getPeer(peerId), let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData {
|
||||
channels.append(RecommendedChannels.Channel(peer: EnginePeer(peer), subscribers: cachedData.participantsSummary.memberCount ?? 0))
|
||||
return account.postbox.multiplePeersView(cachedChannels.peerIds)
|
||||
|> mapToSignal { view in
|
||||
return account.postbox.transaction { transaction -> RecommendedChannels? in
|
||||
var channels: [RecommendedChannels.Channel] = []
|
||||
for peerId in cachedChannels.peerIds {
|
||||
if let peer = view.peers[peerId] as? TelegramChannel, let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData {
|
||||
if case .member = peer.participationStatus {
|
||||
} else {
|
||||
channels.append(RecommendedChannels.Channel(peer: EnginePeer(peer), subscribers: cachedData.participantsSummary.memberCount ?? 0))
|
||||
}
|
||||
}
|
||||
}
|
||||
return RecommendedChannels(channels: channels, isHidden: cachedChannels.isHidden)
|
||||
}
|
||||
return RecommendedChannels(channels: channels, isHidden: cachedChannels.isHidden)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ func _internal_revertChatWallpaper(account: Account, peerId: EnginePeer.Id) -> S
|
||||
return account.network.request(Api.functions.messages.setChatWallPaper(flags: flags, peer: inputPeer, wallpaper: nil, settings: nil, id: nil), automaticFloodWait: false)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { error -> Signal<Api.Updates?, RevertChatWallpaperError> in
|
||||
if error.description == "WALLPAPER_NOT_FOUND" {
|
||||
if error.errorDescription == "WALLPAPER_NOT_FOUND" {
|
||||
return .single(nil)
|
||||
}
|
||||
return .fail(.generic)
|
||||
@@ -215,7 +215,7 @@ public enum SetExistingChatWallpaperError {
|
||||
case generic
|
||||
}
|
||||
|
||||
func _internal_setExistingChatWallpaper(account: Account, messageId: MessageId, settings: WallpaperSettings?) -> Signal<Void, SetExistingChatWallpaperError> {
|
||||
func _internal_setExistingChatWallpaper(account: Account, messageId: MessageId, settings: WallpaperSettings?, forBoth: Bool) -> Signal<Void, SetExistingChatWallpaperError> {
|
||||
return account.postbox.transaction { transaction -> Peer? in
|
||||
if let peer = transaction.getPeer(messageId.peerId), let message = transaction.getMessage(messageId) {
|
||||
if let action = message.media.first(where: { $0 is TelegramMediaAction }) as? TelegramMediaAction, case let .setChatWallpaper(wallpaper, _) = action.action {
|
||||
@@ -248,6 +248,9 @@ func _internal_setExistingChatWallpaper(account: Account, messageId: MessageId,
|
||||
flags |= 1 << 2
|
||||
inputSettings = apiWallpaperSettings(settings)
|
||||
}
|
||||
if forBoth {
|
||||
flags |= 1 << 3
|
||||
}
|
||||
return account.network.request(Api.functions.messages.setChatWallPaper(flags: flags, peer: inputPeer, wallpaper: nil, settings: inputSettings, id: messageId.id), automaticFloodWait: false)
|
||||
|> `catch` { _ -> Signal<Api.Updates, SetExistingChatWallpaperError> in
|
||||
return .fail(.generic)
|
||||
|
||||
@@ -22,8 +22,8 @@ public extension TelegramEngine {
|
||||
|> ignoreValues
|
||||
}
|
||||
|
||||
public func setExistingChatWallpaper(messageId: MessageId, settings: WallpaperSettings?) -> Signal<Void, SetExistingChatWallpaperError> {
|
||||
return _internal_setExistingChatWallpaper(account: self.account, messageId: messageId, settings: settings)
|
||||
public func setExistingChatWallpaper(messageId: MessageId, settings: WallpaperSettings?, forBoth: Bool) -> Signal<Void, SetExistingChatWallpaperError> {
|
||||
return _internal_setExistingChatWallpaper(account: self.account, messageId: messageId, settings: settings, forBoth: forBoth)
|
||||
}
|
||||
|
||||
public func revertChatWallpaper(peerId: EnginePeer.Id) -> Signal<Void, RevertChatWallpaperError> {
|
||||
|
||||
Reference in New Issue
Block a user