Refactoring [skip ci]

This commit is contained in:
Ali 2021-09-24 22:56:48 +03:00
parent b4c5ca2b4d
commit 00b6826303
22 changed files with 346 additions and 280 deletions

View File

@ -130,7 +130,7 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode {
} }
} }
let resource = MapSnapshotMediaResource(latitude: map.latitude, longitude: map.longitude, width: Int32(dimensions.width), height: Int32(dimensions.height)) let resource = MapSnapshotMediaResource(latitude: map.latitude, longitude: map.longitude, width: Int32(dimensions.width), height: Int32(dimensions.height))
self.imageNode.setSignal(chatMapSnapshotImage(account: context.account, resource: resource)) self.imageNode.setSignal(chatMapSnapshotImage(engine: context.engine, resource: resource))
} else if let webPage = media.media as? TelegramMediaWebpage, case let .Loaded(content) = webPage.content, let image = content.image { } else if let webPage = media.media as? TelegramMediaWebpage, case let .Loaded(content) = webPage.content, let image = content.image {
let imageReference = ImageMediaReference.webPage(webPage: WebpageReference(webPage), media: image) let imageReference = ImageMediaReference.webPage(webPage: WebpageReference(webPage), media: image)
self.imageNode.setSignal(chatMessagePhoto(postbox: context.account.postbox, photoReference: imageReference)) self.imageNode.setSignal(chatMessagePhoto(postbox: context.account.postbox, photoReference: imageReference))

View File

@ -11,7 +11,7 @@ import ShimmerEffect
public final class ItemListVenueItem: ListViewItem, ItemListItem { public final class ItemListVenueItem: ListViewItem, ItemListItem {
let presentationData: ItemListPresentationData let presentationData: ItemListPresentationData
let account: Account let engine: TelegramEngine
let venue: TelegramMediaMap? let venue: TelegramMediaMap?
let title: String? let title: String?
let subtitle: String? let subtitle: String?
@ -22,9 +22,9 @@ public final class ItemListVenueItem: ListViewItem, ItemListItem {
public let sectionId: ItemListSectionId public let sectionId: ItemListSectionId
let header: ListViewItemHeader? let header: ListViewItemHeader?
public init(presentationData: ItemListPresentationData, account: Account, venue: TelegramMediaMap?, title: String? = nil, subtitle: String? = nil, sectionId: ItemListSectionId = 0, style: ItemListStyle, action: (() -> Void)?, infoAction: (() -> Void)? = nil, header: ListViewItemHeader? = nil) { public init(presentationData: ItemListPresentationData, engine: TelegramEngine, venue: TelegramMediaMap?, title: String? = nil, subtitle: String? = nil, sectionId: ItemListSectionId = 0, style: ItemListStyle, action: (() -> Void)?, infoAction: (() -> Void)? = nil, header: ListViewItemHeader? = nil) {
self.presentationData = presentationData self.presentationData = presentationData
self.account = account self.engine = engine
self.venue = venue self.venue = venue
self.title = title self.title = title
self.subtitle = subtitle self.subtitle = subtitle
@ -281,7 +281,7 @@ public class ItemListVenueItemNode: ListViewItemNode, ItemListItemNode {
let _ = addressApply() let _ = addressApply()
if let updatedVenueType = updatedVenueType { if let updatedVenueType = updatedVenueType {
strongSelf.iconNode.setSignal(venueIcon(postbox: item.account.postbox, type: updatedVenueType, background: true)) strongSelf.iconNode.setSignal(venueIcon(engine: item.engine, type: updatedVenueType, background: true))
} }
let iconApply = iconLayout(TransformImageArguments(corners: ImageCorners(), imageSize: CGSize(width: iconSize, height: iconSize), boundingSize: CGSize(width: iconSize, height: iconSize), intrinsicInsets: UIEdgeInsets())) let iconApply = iconLayout(TransformImageArguments(corners: ImageCorners(), imageSize: CGSize(width: iconSize, height: iconSize), boundingSize: CGSize(width: iconSize, height: iconSize), intrinsicInsets: UIEdgeInsets()))

View File

@ -217,7 +217,7 @@ public final class ChatMessageLiveLocationPositionNode: ASDisplayNode {
if let updatedVenueType = updatedVenueType { if let updatedVenueType = updatedVenueType {
strongSelf.venueType = updatedVenueType strongSelf.venueType = updatedVenueType
strongSelf.iconNode.setSignal(venueIcon(postbox: context.account.postbox, type: updatedVenueType, background: false)) strongSelf.iconNode.setSignal(venueIcon(engine: context.engine, type: updatedVenueType, background: false))
} }
let arguments = VenueIconArguments(defaultBackgroundColor: theme.chat.inputPanel.actionControlFillColor, defaultForegroundColor: theme.chat.inputPanel.actionControlForegroundColor) let arguments = VenueIconArguments(defaultBackgroundColor: theme.chat.inputPanel.actionControlFillColor, defaultForegroundColor: theme.chat.inputPanel.actionControlForegroundColor)

View File

@ -11,10 +11,10 @@ swift_library(
], ],
deps = [ deps = [
"//submodules/TelegramCore:TelegramCore", "//submodules/TelegramCore:TelegramCore",
"//submodules/Postbox:Postbox",
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/Display:Display", "//submodules/Display:Display",
"//submodules/AppBundle:AppBundle", "//submodules/AppBundle:AppBundle",
"//submodules/PersistentStringHash:PersistentStringHash",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -1,7 +1,6 @@
import Foundation import Foundation
import UIKit import UIKit
import Display import Display
import Postbox
import TelegramCore import TelegramCore
import MapKit import MapKit
import SwiftSignalKit import SwiftSignalKit
@ -21,7 +20,7 @@ public struct MapSnapshotMediaResourceId {
} }
} }
public class MapSnapshotMediaResource: TelegramMediaResource { public class MapSnapshotMediaResource {
public let latitude: Double public let latitude: Double
public let longitude: Double public let longitude: Double
public let width: Int32 public let width: Int32
@ -34,49 +33,8 @@ public class MapSnapshotMediaResource: TelegramMediaResource {
self.height = height self.height = height
} }
public required init(decoder: PostboxDecoder) { public var id: EngineMediaResource.Id {
self.latitude = decoder.decodeDoubleForKey("lt", orElse: 0.0) return EngineMediaResource.Id(MapSnapshotMediaResourceId(latitude: self.latitude, longitude: self.longitude, width: self.width, height: self.height).uniqueId)
self.longitude = decoder.decodeDoubleForKey("ln", orElse: 0.0)
self.width = decoder.decodeInt32ForKey("w", orElse: 0)
self.height = decoder.decodeInt32ForKey("h", orElse: 0)
}
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeDouble(self.latitude, forKey: "lt")
encoder.encodeDouble(self.longitude, forKey: "ln")
encoder.encodeInt32(self.width, forKey: "w")
encoder.encodeInt32(self.height, forKey: "h")
}
public var id: MediaResourceId {
return MediaResourceId(MapSnapshotMediaResourceId(latitude: self.latitude, longitude: self.longitude, width: self.width, height: self.height).uniqueId)
}
public func isEqual(to: MediaResource) -> Bool {
if let to = to as? MapSnapshotMediaResource {
return self.latitude == to.latitude && self.longitude == to.longitude && self.width == to.width && self.height == to.height
} else {
return false
}
}
}
public final class MapSnapshotMediaResourceRepresentation: CachedMediaResourceRepresentation {
public let keepDuration: CachedMediaRepresentationKeepDuration = .shortLived
public var uniqueId: String {
return "cached"
}
public init() {
}
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
if to is MapSnapshotMediaResourceRepresentation {
return true
} else {
return false
}
} }
} }
@ -96,7 +54,7 @@ private func adjustGMapLatitude(_ latitude: Double, offset: Int, zoom: Int) -> D
return yToLatitude(latitudeToY(latitude) + t) return yToLatitude(latitudeToY(latitude) + t)
} }
public func fetchMapSnapshotResource(resource: MapSnapshotMediaResource) -> Signal<CachedMediaResourceRepresentationResult, NoError> { private func fetchMapSnapshotResource(resource: MapSnapshotMediaResource) -> Signal<EngineMediaResource.Fetch.Result, EngineMediaResource.Fetch.Error> {
return Signal { subscriber in return Signal { subscriber in
let disposable = MetaDisposable() let disposable = MetaDisposable()
@ -113,9 +71,9 @@ public func fetchMapSnapshotResource(resource: MapSnapshotMediaResource) -> Sign
snapshotter.start(with: DispatchQueue.global(), completionHandler: { result, error in snapshotter.start(with: DispatchQueue.global(), completionHandler: { result, error in
if let image = result?.image { if let image = result?.image {
if let data = image.jpegData(compressionQuality: 0.9) { if let data = image.jpegData(compressionQuality: 0.9) {
let tempFile = TempBox.shared.tempFile(fileName: "image.jpg") let tempFile = EngineTempBox.shared.tempFile(fileName: "image.jpg")
if let _ = try? data.write(to: URL(fileURLWithPath: tempFile.path), options: .atomic) { if let _ = try? data.write(to: URL(fileURLWithPath: tempFile.path), options: .atomic) {
subscriber.putNext(.tempFile(tempFile)) subscriber.putNext(.moveTempFile(file: tempFile))
subscriber.putCompletion() subscriber.putCompletion()
} }
} }
@ -130,11 +88,17 @@ public func fetchMapSnapshotResource(resource: MapSnapshotMediaResource) -> Sign
} }
} }
public func chatMapSnapshotData(account: Account, resource: MapSnapshotMediaResource) -> Signal<Data?, NoError> { public func chatMapSnapshotData(engine: TelegramEngine, resource: MapSnapshotMediaResource) -> Signal<Data?, NoError> {
return Signal<Data?, NoError> { subscriber in return Signal<Data?, NoError> { subscriber in
let dataDisposable = account.postbox.mediaBox.cachedResourceRepresentation(resource, representation: MapSnapshotMediaResourceRepresentation(), complete: true).start(next: { next in let dataDisposable = engine.resources.custom(
if next.size != 0 { id: resource.id.stringRepresentation,
subscriber.putNext(next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: [])) fetch: EngineMediaResource.Fetch {
return fetchMapSnapshotResource(resource: resource)
},
cacheTimeout: .shortLived
).start(next: { next in
if next.availableSize != 0 {
subscriber.putNext(next.availableSize == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []))
} }
}, error: subscriber.putError, completed: subscriber.putCompletion) }, error: subscriber.putError, completed: subscriber.putCompletion)
@ -144,8 +108,8 @@ public func chatMapSnapshotData(account: Account, resource: MapSnapshotMediaReso
} }
} }
public func chatMapSnapshotImage(account: Account, resource: MapSnapshotMediaResource) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { public func chatMapSnapshotImage(engine: TelegramEngine, resource: MapSnapshotMediaResource) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let signal = chatMapSnapshotData(account: account, resource: resource) let signal = chatMapSnapshotData(engine: engine, resource: resource)
return signal |> map { fullSizeData in return signal |> map { fullSizeData in
return { arguments in return { arguments in

View File

@ -1,10 +1,10 @@
import Foundation import Foundation
import UIKit import UIKit
import Display import Display
import Postbox
import TelegramCore import TelegramCore
import SwiftSignalKit import SwiftSignalKit
import AppBundle import AppBundle
import PersistentStringHash
public struct VenueIconResourceId { public struct VenueIconResourceId {
public let type: String public let type: String
@ -22,79 +22,51 @@ public struct VenueIconResourceId {
} }
} }
public class VenueIconResource: TelegramMediaResource { public class VenueIconResource {
public let type: String public let type: String
public init(type: String) { public init(type: String) {
self.type = type self.type = type
} }
public required init(decoder: PostboxDecoder) { public var id: EngineMediaResource.Id {
self.type = decoder.decodeStringForKey("t", orElse: "") return EngineMediaResource.Id(VenueIconResourceId(type: self.type).uniqueId)
}
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeString(self.type, forKey: "t")
}
public var id: MediaResourceId {
return MediaResourceId(VenueIconResourceId(type: self.type).uniqueId)
}
public func isEqual(to: MediaResource) -> Bool {
if let to = to as? VenueIconResource {
return self.type == to.type
} else {
return false
}
} }
} }
public func fetchVenueIconResource(account: Account, resource: VenueIconResource) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> { private func fetchVenueIconResource(engine: TelegramEngine, resource: VenueIconResource) -> Signal<EngineMediaResource.Fetch.Result, EngineMediaResource.Fetch.Error> {
return Signal { subscriber in return Signal { subscriber in
subscriber.putNext(.reset)
let url = "https://ss3.4sqi.net/img/categories_v2/\(resource.type)_88.png" let url = "https://ss3.4sqi.net/img/categories_v2/\(resource.type)_88.png"
let fetchDisposable = MetaDisposable() return engine.resources.httpData(url: url).start(next: { data in
fetchDisposable.set(fetchHttpResource(url: url).start(next: { next in let file = EngineTempBox.shared.tempFile(fileName: "file.png")
subscriber.putNext(next) let _ = try? data.write(to: URL(fileURLWithPath: file.path))
subscriber.putNext(.moveTempFile(file: file))
}, completed: { }, completed: {
subscriber.putCompletion() subscriber.putCompletion()
})) })
return ActionDisposable {
fetchDisposable.dispose()
}
} }
} }
private func venueIconData(postbox: Postbox, resource: MediaResource) -> Signal<Data?, NoError> { private func venueIconData(engine: TelegramEngine, resource: VenueIconResource) -> Signal<Data?, NoError> {
let resourceData = postbox.mediaBox.resourceData(resource) let resourceData = engine.resources.custom(
id: resource.id.stringRepresentation,
fetch: EngineMediaResource.Fetch {
return fetchVenueIconResource(engine: engine, resource: resource)
},
cacheTimeout: .shortLived
)
let signal = resourceData let signal = resourceData
|> take(1) |> take(1)
|> mapToSignal { maybeData -> Signal<Data?, NoError> in |> mapToSignal { maybeData -> Signal<Data?, NoError> in
if maybeData.complete { if maybeData.isComplete {
let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: []) return .single(try? Data(contentsOf: URL(fileURLWithPath: maybeData.path)))
return .single((loadedData))
} else { } else {
let fetched = postbox.mediaBox.fetchedResource(resource, parameters: nil) return .single(nil)
let data = Signal<Data?, NoError> { subscriber in
let fetchedDisposable = fetched.start()
let resourceDisposable = resourceData.start(next: { next in
subscriber.putNext(next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []))
}, error: subscriber.putError, completed: subscriber.putCompletion)
return ActionDisposable {
fetchedDisposable.dispose()
resourceDisposable.dispose()
}
}
return data
} }
} |> distinctUntilChanged(isEqual: { lhs, rhs in }
|> distinctUntilChanged(isEqual: { lhs, rhs in
if lhs == nil && rhs == nil { if lhs == nil && rhs == nil {
return true return true
} else { } else {
@ -141,7 +113,7 @@ public func venueIconColor(type: String) -> UIColor {
return color return color
} }
let index = Int(abs(persistentHash32(type)) % Int32(randomColors.count)) let index = Int(abs(Int32(bitPattern: UInt32(clamping: type.persistentHashValue))) % Int32(randomColors.count))
return randomColors[index] return randomColors[index]
} }
@ -162,9 +134,9 @@ public struct VenueIconArguments: TransformImageCustomArguments {
} }
} }
public func venueIcon(postbox: Postbox, type: String, background: Bool) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { public func venueIcon(engine: TelegramEngine, type: String, background: Bool) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let isBuiltinIcon = ["", "home", "work"].contains(type) let isBuiltinIcon = ["", "home", "work"].contains(type)
let data: Signal<Data?, NoError> = isBuiltinIcon ? .single(nil) : venueIconData(postbox: postbox, resource: VenueIconResource(type: type)) let data: Signal<Data?, NoError> = isBuiltinIcon ? .single(nil) : venueIconData(engine: engine, resource: VenueIconResource(type: type))
return data |> map { data in return data |> map { data in
return { arguments in return { arguments in
let context = DrawingContext(size: arguments.drawingSize, clear: true) let context = DrawingContext(size: arguments.drawingSize, clear: true)

View File

@ -81,7 +81,7 @@ private func generateLiveLocationIcon(theme: PresentationTheme, stop: Bool) -> U
final class LocationActionListItem: ListViewItem { final class LocationActionListItem: ListViewItem {
let presentationData: ItemListPresentationData let presentationData: ItemListPresentationData
let account: Account let engine: TelegramEngine
let title: String let title: String
let subtitle: String let subtitle: String
let icon: LocationActionListItemIcon let icon: LocationActionListItemIcon
@ -89,9 +89,9 @@ final class LocationActionListItem: ListViewItem {
let action: () -> Void let action: () -> Void
let highlighted: (Bool) -> Void let highlighted: (Bool) -> Void
public init(presentationData: ItemListPresentationData, account: Account, title: String, subtitle: String, icon: LocationActionListItemIcon, beginTimeAndTimeout: (Double, Double)?, action: @escaping () -> Void, highlighted: @escaping (Bool) -> Void = { _ in }) { public init(presentationData: ItemListPresentationData, engine: TelegramEngine, title: String, subtitle: String, icon: LocationActionListItemIcon, beginTimeAndTimeout: (Double, Double)?, action: @escaping () -> Void, highlighted: @escaping (Bool) -> Void = { _ in }) {
self.presentationData = presentationData self.presentationData = presentationData
self.account = account self.engine = engine
self.title = title self.title = title
self.subtitle = subtitle self.subtitle = subtitle
self.icon = icon self.icon = icon
@ -279,7 +279,7 @@ final class LocationActionListItemNode: ListViewItemNode {
case let .venue(venue): case let .venue(venue):
strongSelf.iconNode.isHidden = true strongSelf.iconNode.isHidden = true
strongSelf.venueIconNode.isHidden = false strongSelf.venueIconNode.isHidden = false
strongSelf.venueIconNode.setSignal(venueIcon(postbox: item.account.postbox, type: venue.venue?.type ?? "", background: true)) strongSelf.venueIconNode.setSignal(venueIcon(engine: item.engine, type: venue.venue?.type ?? "", background: true))
} }
if updatedIcon == .stopLiveLocation { if updatedIcon == .stopLiveLocation {

View File

@ -307,8 +307,8 @@ class LocationPinAnnotationView: MKAnnotationView {
let venueType = location.venue?.type ?? "" let venueType = location.venue?.type ?? ""
let color = venueType.isEmpty ? annotation.theme.list.itemAccentColor : venueIconColor(type: venueType) let color = venueType.isEmpty ? annotation.theme.list.itemAccentColor : venueIconColor(type: venueType)
self.backgroundNode.image = generateTintedImage(image: UIImage(bundleImageName: "Location/PinBackground"), color: color) self.backgroundNode.image = generateTintedImage(image: UIImage(bundleImageName: "Location/PinBackground"), color: color)
self.iconNode.setSignal(venueIcon(postbox: annotation.context.account.postbox, type: venueType, background: false)) self.iconNode.setSignal(venueIcon(engine: annotation.context.engine, type: venueType, background: false))
self.smallIconNode.setSignal(venueIcon(postbox: annotation.context.account.postbox, type: venueType, background: false)) self.smallIconNode.setSignal(venueIcon(engine: annotation.context.engine, type: venueType, background: false))
self.smallNode.image = generateSmallBackgroundImage(color: color) self.smallNode.image = generateSmallBackgroundImage(color: color)
self.dotNode.image = generateFilledCircleImage(diameter: 6.0, color: color) self.dotNode.image = generateFilledCircleImage(diameter: 6.0, color: color)
@ -619,7 +619,7 @@ class LocationPinAnnotationView: MKAnnotationView {
func setCustom(_ custom: Bool, animated: Bool) { func setCustom(_ custom: Bool, animated: Bool) {
if let annotation = self.annotation as? LocationPinAnnotation { if let annotation = self.annotation as? LocationPinAnnotation {
self.iconNode.setSignal(venueIcon(postbox: annotation.context.account.postbox, type: "", background: false)) self.iconNode.setSignal(venueIcon(engine: annotation.context.engine, type: "", background: false))
} }
if let avatarNode = self.avatarNode { if let avatarNode = self.avatarNode {

View File

@ -13,7 +13,7 @@ import SolidRoundedButtonNode
final class LocationInfoListItem: ListViewItem { final class LocationInfoListItem: ListViewItem {
let presentationData: ItemListPresentationData let presentationData: ItemListPresentationData
let account: Account let engine: TelegramEngine
let location: TelegramMediaMap let location: TelegramMediaMap
let address: String? let address: String?
let distance: String? let distance: String?
@ -21,9 +21,9 @@ final class LocationInfoListItem: ListViewItem {
let action: () -> Void let action: () -> Void
let getDirections: () -> Void let getDirections: () -> Void
public init(presentationData: ItemListPresentationData, account: Account, location: TelegramMediaMap, address: String?, distance: String?, eta: String?, action: @escaping () -> Void, getDirections: @escaping () -> Void) { public init(presentationData: ItemListPresentationData, engine: TelegramEngine, location: TelegramMediaMap, address: String?, distance: String?, eta: String?, action: @escaping () -> Void, getDirections: @escaping () -> Void) {
self.presentationData = presentationData self.presentationData = presentationData
self.account = account self.engine = engine
self.location = location self.location = location
self.address = address self.address = address
self.distance = distance self.distance = distance
@ -192,7 +192,7 @@ final class LocationInfoListItemNode: ListViewItemNode {
let arguments = VenueIconArguments(defaultBackgroundColor: item.presentationData.theme.chat.inputPanel.actionControlFillColor, defaultForegroundColor: item.presentationData.theme.chat.inputPanel.actionControlForegroundColor) let arguments = VenueIconArguments(defaultBackgroundColor: item.presentationData.theme.chat.inputPanel.actionControlFillColor, defaultForegroundColor: item.presentationData.theme.chat.inputPanel.actionControlForegroundColor)
if let updatedLocation = updatedLocation { if let updatedLocation = updatedLocation {
strongSelf.venueIconNode.setSignal(venueIcon(postbox: item.account.postbox, type: updatedLocation.venue?.type ?? "", background: true)) strongSelf.venueIconNode.setSignal(venueIcon(engine: item.engine, type: updatedLocation.venue?.type ?? "", background: true))
} }
let iconApply = iconLayout(TransformImageArguments(corners: ImageCorners(), imageSize: CGSize(width: iconSize, height: iconSize), boundingSize: CGSize(width: iconSize, height: iconSize), intrinsicInsets: UIEdgeInsets(), custom: arguments)) let iconApply = iconLayout(TransformImageArguments(corners: ImageCorners(), imageSize: CGSize(width: iconSize, height: iconSize), boundingSize: CGSize(width: iconSize, height: iconSize), intrinsicInsets: UIEdgeInsets(), custom: arguments))

View File

@ -129,7 +129,7 @@ private enum LocationPickerEntry: Comparable, Identifiable {
} }
} }
func item(account: Account, presentationData: PresentationData, interaction: LocationPickerInteraction?) -> ListViewItem { func item(engine: TelegramEngine, presentationData: PresentationData, interaction: LocationPickerInteraction?) -> ListViewItem {
switch self { switch self {
case let .location(_, title, subtitle, venue, coordinate): case let .location(_, title, subtitle, venue, coordinate):
let icon: LocationActionListItemIcon let icon: LocationActionListItemIcon
@ -138,7 +138,7 @@ private enum LocationPickerEntry: Comparable, Identifiable {
} else { } else {
icon = .location icon = .location
} }
return LocationActionListItem(presentationData: ItemListPresentationData(presentationData), account: account, title: title, subtitle: subtitle, icon: icon, beginTimeAndTimeout: nil, action: { return LocationActionListItem(presentationData: ItemListPresentationData(presentationData), engine: engine, title: title, subtitle: subtitle, icon: icon, beginTimeAndTimeout: nil, action: {
if let venue = venue { if let venue = venue {
interaction?.sendVenue(venue) interaction?.sendVenue(venue)
} else if let coordinate = coordinate { } else if let coordinate = coordinate {
@ -148,7 +148,7 @@ private enum LocationPickerEntry: Comparable, Identifiable {
interaction?.updateSendActionHighlight(highlighted) interaction?.updateSendActionHighlight(highlighted)
}) })
case let .liveLocation(_, title, subtitle, coordinate): case let .liveLocation(_, title, subtitle, coordinate):
return LocationActionListItem(presentationData: ItemListPresentationData(presentationData), account: account, title: title, subtitle: subtitle, icon: .liveLocation, beginTimeAndTimeout: nil, action: { return LocationActionListItem(presentationData: ItemListPresentationData(presentationData), engine: engine, title: title, subtitle: subtitle, icon: .liveLocation, beginTimeAndTimeout: nil, action: {
if let coordinate = coordinate { if let coordinate = coordinate {
interaction?.sendLiveLocation(coordinate) interaction?.sendLiveLocation(coordinate)
} }
@ -157,7 +157,7 @@ private enum LocationPickerEntry: Comparable, Identifiable {
return LocationSectionHeaderItem(presentationData: ItemListPresentationData(presentationData), title: title) return LocationSectionHeaderItem(presentationData: ItemListPresentationData(presentationData), title: title)
case let .venue(_, venue, _): case let .venue(_, venue, _):
let venueType = venue?.venue?.type ?? "" let venueType = venue?.venue?.type ?? ""
return ItemListVenueItem(presentationData: ItemListPresentationData(presentationData), account: account, venue: venue, style: .plain, action: venue.flatMap { venue in return ItemListVenueItem(presentationData: ItemListPresentationData(presentationData), engine: engine, venue: venue, style: .plain, action: venue.flatMap { venue in
return { interaction?.sendVenue(venue) } return { interaction?.sendVenue(venue) }
}, infoAction: ["home", "work"].contains(venueType) ? { }, infoAction: ["home", "work"].contains(venueType) ? {
interaction?.openHomeWorkInfo() interaction?.openHomeWorkInfo()
@ -168,12 +168,12 @@ private enum LocationPickerEntry: Comparable, Identifiable {
} }
} }
private func preparedTransition(from fromEntries: [LocationPickerEntry], to toEntries: [LocationPickerEntry], isLoading: Bool, isEmpty: Bool, crossFade: Bool, account: Account, presentationData: PresentationData, interaction: LocationPickerInteraction?) -> LocationPickerTransaction { private func preparedTransition(from fromEntries: [LocationPickerEntry], to toEntries: [LocationPickerEntry], isLoading: Bool, isEmpty: Bool, crossFade: Bool, engine: TelegramEngine, presentationData: PresentationData, interaction: LocationPickerInteraction?) -> LocationPickerTransaction {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries) let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) } let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, presentationData: presentationData, interaction: interaction), directionHint: nil) } let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(engine: engine, presentationData: presentationData, interaction: interaction), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, presentationData: presentationData, interaction: interaction), directionHint: nil) } let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(engine: engine, presentationData: presentationData, interaction: interaction), directionHint: nil) }
return LocationPickerTransaction(deletions: deletions, insertions: insertions, updates: updates, isLoading: isLoading, isEmpty: isEmpty, crossFade: crossFade) return LocationPickerTransaction(deletions: deletions, insertions: insertions, updates: updates, isLoading: isLoading, isEmpty: isEmpty, crossFade: crossFade)
} }
@ -527,7 +527,7 @@ final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationM
crossFade = true crossFade = true
} }
let transition = preparedTransition(from: previousEntries ?? [], to: entries, isLoading: displayedVenues == nil, isEmpty: displayedVenues?.isEmpty ?? false, crossFade: crossFade, account: context.account, presentationData: presentationData, interaction: strongSelf.interaction) let transition = preparedTransition(from: previousEntries ?? [], to: entries, isLoading: displayedVenues == nil, isEmpty: displayedVenues?.isEmpty ?? false, crossFade: crossFade, engine: context.engine, presentationData: presentationData, interaction: strongSelf.interaction)
strongSelf.enqueueTransition(transition) strongSelf.enqueueTransition(transition)
var displayingPlacesButton = false var displayingPlacesButton = false

View File

@ -50,7 +50,7 @@ private struct LocationSearchEntry: Identifiable, Comparable {
return lhs.index < rhs.index return lhs.index < rhs.index
} }
func item(account: Account, presentationData: PresentationData, sendVenue: @escaping (TelegramMediaMap) -> Void) -> ListViewItem { func item(engine: TelegramEngine, presentationData: PresentationData, sendVenue: @escaping (TelegramMediaMap) -> Void) -> ListViewItem {
let venue = self.location let venue = self.location
let header: ChatListSearchItemHeader let header: ChatListSearchItemHeader
let subtitle: String? let subtitle: String?
@ -61,7 +61,7 @@ private struct LocationSearchEntry: Identifiable, Comparable {
header = ChatListSearchItemHeader(type: .mapAddress, theme: presentationData.theme, strings: presentationData.strings) header = ChatListSearchItemHeader(type: .mapAddress, theme: presentationData.theme, strings: presentationData.strings)
subtitle = presentationData.strings.Map_DistanceAway(stringForDistance(strings: presentationData.strings, distance: self.distance)).string subtitle = presentationData.strings.Map_DistanceAway(stringForDistance(strings: presentationData.strings, distance: self.distance)).string
} }
return ItemListVenueItem(presentationData: ItemListPresentationData(presentationData), account: account, venue: self.location, title: self.title, subtitle: subtitle, style: .plain, action: { return ItemListVenueItem(presentationData: ItemListPresentationData(presentationData), engine: engine, venue: self.location, title: self.title, subtitle: subtitle, style: .plain, action: {
sendVenue(venue) sendVenue(venue)
}, header: header) }, header: header)
} }
@ -76,12 +76,12 @@ struct LocationSearchContainerTransition {
let isEmpty: Bool let isEmpty: Bool
} }
private func locationSearchContainerPreparedTransition(from fromEntries: [LocationSearchEntry], to toEntries: [LocationSearchEntry], query: String, isSearching: Bool, isEmpty: Bool, account: Account, presentationData: PresentationData, sendVenue: @escaping (TelegramMediaMap) -> Void) -> LocationSearchContainerTransition { private func locationSearchContainerPreparedTransition(from fromEntries: [LocationSearchEntry], to toEntries: [LocationSearchEntry], query: String, isSearching: Bool, isEmpty: Bool, engine: TelegramEngine, presentationData: PresentationData, sendVenue: @escaping (TelegramMediaMap) -> Void) -> LocationSearchContainerTransition {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries) let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) } let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, presentationData: presentationData, sendVenue: sendVenue), directionHint: nil) } let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(engine: engine, presentationData: presentationData, sendVenue: sendVenue), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, presentationData: presentationData, sendVenue: sendVenue), directionHint: nil) } let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(engine: engine, presentationData: presentationData, sendVenue: sendVenue), directionHint: nil) }
return LocationSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, query: query, isSearching: isSearching, isEmpty: isEmpty) return LocationSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, query: query, isSearching: isSearching, isEmpty: isEmpty)
} }
@ -211,7 +211,7 @@ final class LocationSearchContainerNode: ASDisplayNode {
if let strongSelf = self { if let strongSelf = self {
let (items, query) = itemsAndQuery ?? (nil, "") let (items, query) = itemsAndQuery ?? (nil, "")
let previousItems = previousSearchItems.swap(items ?? []) let previousItems = previousSearchItems.swap(items ?? [])
let transition = locationSearchContainerPreparedTransition(from: previousItems, to: items ?? [], query: query, isSearching: items != nil, isEmpty: items?.isEmpty ?? false, account: context.account, presentationData: strongSelf.presentationData, sendVenue: { venue in self?.listNode.clearHighlightAnimated(true) let transition = locationSearchContainerPreparedTransition(from: previousItems, to: items ?? [], query: query, isSearching: items != nil, isEmpty: items?.isEmpty ?? false, engine: context.engine, presentationData: strongSelf.presentationData, sendVenue: { venue in self?.listNode.clearHighlightAnimated(true)
if let _ = venue.venue { if let _ = venue.venue {
self?.interaction.sendVenue(venue) self?.interaction.sendVenue(venue)
} else { } else {

View File

@ -126,7 +126,7 @@ private enum LocationViewEntry: Comparable, Identifiable {
distanceString = nil distanceString = nil
} }
let eta = time.flatMap { stringForEstimatedDuration(strings: presentationData.strings, eta: $0) } let eta = time.flatMap { stringForEstimatedDuration(strings: presentationData.strings, eta: $0) }
return LocationInfoListItem(presentationData: ItemListPresentationData(presentationData), account: context.account, location: location, address: addressString, distance: distanceString, eta: eta, action: { return LocationInfoListItem(presentationData: ItemListPresentationData(presentationData), engine: context.engine, location: location, address: addressString, distance: distanceString, eta: eta, action: {
interaction?.goToCoordinate(location.coordinate) interaction?.goToCoordinate(location.coordinate)
}, getDirections: { }, getDirections: {
interaction?.requestDirections() interaction?.requestDirections()
@ -138,7 +138,7 @@ private enum LocationViewEntry: Comparable, Identifiable {
} else { } else {
beginTimeAndTimeout = nil beginTimeAndTimeout = nil
} }
return LocationActionListItem(presentationData: ItemListPresentationData(presentationData), account: context.account, title: title, subtitle: subtitle, icon: beginTimeAndTimeout != nil ? .stopLiveLocation : .liveLocation, beginTimeAndTimeout: beginTimeAndTimeout, action: { return LocationActionListItem(presentationData: ItemListPresentationData(presentationData), engine: context.engine, title: title, subtitle: subtitle, icon: beginTimeAndTimeout != nil ? .stopLiveLocation : .liveLocation, beginTimeAndTimeout: beginTimeAndTimeout, action: {
if beginTimeAndTimeout != nil { if beginTimeAndTimeout != nil {
interaction?.stopLiveLocation() interaction?.stopLiveLocation()
} else { } else {

View File

@ -614,7 +614,7 @@ private func filteredContactData(contactData: DeviceContactExtendedData, exclude
return DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: contactData.basicData.firstName, lastName: contactData.basicData.lastName, phoneNumbers: phoneNumbers), middleName: contactData.middleName, prefix: contactData.prefix, suffix: contactData.suffix, organization: includeJob ? contactData.organization : "", jobTitle: includeJob ? contactData.jobTitle : "", department: includeJob ? contactData.department : "", emailAddresses: emailAddresses, urls: urls, addresses: addresses, birthdayDate: includeBirthday ? contactData.birthdayDate : nil, socialProfiles: socialProfiles, instantMessagingProfiles: instantMessagingProfiles, note: includeNote ? contactData.note : "") return DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: contactData.basicData.firstName, lastName: contactData.basicData.lastName, phoneNumbers: phoneNumbers), middleName: contactData.middleName, prefix: contactData.prefix, suffix: contactData.suffix, organization: includeJob ? contactData.organization : "", jobTitle: includeJob ? contactData.jobTitle : "", department: includeJob ? contactData.department : "", emailAddresses: emailAddresses, urls: urls, addresses: addresses, birthdayDate: includeBirthday ? contactData.birthdayDate : nil, socialProfiles: socialProfiles, instantMessagingProfiles: instantMessagingProfiles, note: includeNote ? contactData.note : "")
} }
private func deviceContactInfoEntries(account: Account, presentationData: PresentationData, peer: Peer?, isShare: Bool, shareViaException: Bool, contactData: DeviceContactExtendedData, isContact: Bool, state: DeviceContactInfoState, selecting: Bool, editingPhoneNumbers: Bool) -> [DeviceContactInfoEntry] { private func deviceContactInfoEntries(account: Account, engine: TelegramEngine, presentationData: PresentationData, peer: Peer?, isShare: Bool, shareViaException: Bool, contactData: DeviceContactExtendedData, isContact: Bool, state: DeviceContactInfoState, selecting: Bool, editingPhoneNumbers: Bool) -> [DeviceContactInfoEntry] {
var entries: [DeviceContactInfoEntry] = [] var entries: [DeviceContactInfoEntry] = []
var editingName: ItemListAvatarAndNameInfoItemName? var editingName: ItemListAvatarAndNameInfoItemName?
@ -731,7 +731,7 @@ private func deviceContactInfoEntries(account: Account, presentationData: Presen
|> mapToSignal { coordinates -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in |> mapToSignal { coordinates -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
if let (latitude, longitude) = coordinates { if let (latitude, longitude) = coordinates {
let resource = MapSnapshotMediaResource(latitude: latitude, longitude: longitude, width: 90, height: 90) let resource = MapSnapshotMediaResource(latitude: latitude, longitude: longitude, width: 90, height: 90)
return chatMapSnapshotImage(account: account, resource: resource) return chatMapSnapshotImage(engine: engine, resource: resource)
} else { } else {
return .single({ _ in return nil }) return .single({ _ in return nil })
} }
@ -1220,7 +1220,7 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta
focusItemTag = DeviceContactInfoEntryTag.editingPhone(insertedPhoneId) focusItemTag = DeviceContactInfoEntryTag.editingPhone(insertedPhoneId)
} }
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: deviceContactInfoEntries(account: context.account, presentationData: presentationData, peer: peerAndContactData.0, isShare: isShare, shareViaException: shareViaException, contactData: peerAndContactData.2, isContact: peerAndContactData.1 != nil, state: state, selecting: selecting, editingPhoneNumbers: editingPhones), style: isShare ? .blocks : .plain, focusItemTag: focusItemTag) let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: deviceContactInfoEntries(account: context.account, engine: context.engine, presentationData: presentationData, peer: peerAndContactData.0, isShare: isShare, shareViaException: shareViaException, contactData: peerAndContactData.2, isContact: peerAndContactData.1 != nil, state: state, selecting: selecting, editingPhoneNumbers: editingPhones), style: isShare ? .blocks : .plain, focusItemTag: focusItemTag)
return (controllerState, (listState, arguments)) return (controllerState, (listState, arguments))
} }

View File

@ -98,17 +98,8 @@ public enum CachedMediaRepresentationKeepDuration {
} }
private struct CachedMediaResourceRepresentationKey: Hashable { private struct CachedMediaResourceRepresentationKey: Hashable {
let resourceId: MediaResourceId let resourceId: String?
let representation: CachedMediaResourceRepresentation let representation: String
static func ==(lhs: CachedMediaResourceRepresentationKey, rhs: CachedMediaResourceRepresentationKey) -> Bool {
return lhs.resourceId == rhs.resourceId && lhs.representation.isEqual(to: rhs.representation)
}
func hash(into hasher: inout Hasher) {
hasher.combine(self.resourceId.hashValue)
hasher.combine(self.representation.uniqueId)
}
} }
private final class CachedMediaResourceRepresentationSubscriber { private final class CachedMediaResourceRepresentationSubscriber {
@ -157,7 +148,7 @@ public final class MediaBox {
private var keepResourceContexts: [MediaResourceId: MediaBoxKeepResourceContext] = [:] private var keepResourceContexts: [MediaResourceId: MediaBoxKeepResourceContext] = [:]
private var wrappedFetchResource = Promise<(MediaResource, Signal<[(Range<Int>, MediaBoxFetchPriority)], NoError>, MediaResourceFetchParameters?) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError>>() private var wrappedFetchResource = Promise<(MediaResource, Signal<[(Range<Int>, MediaBoxFetchPriority)], NoError>, MediaResourceFetchParameters?) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError>>()
public var preFetchedResourcePath: (MediaResource) -> String? = { _ in return nil }
public var fetchResource: ((MediaResource, Signal<[(Range<Int>, MediaBoxFetchPriority)], NoError>, MediaResourceFetchParameters?) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError>)? { public var fetchResource: ((MediaResource, Signal<[(Range<Int>, MediaBoxFetchPriority)], NoError>, MediaResourceFetchParameters?) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError>)? {
didSet { didSet {
if let fetchResource = self.fetchResource { if let fetchResource = self.fetchResource {
@ -222,15 +213,15 @@ public final class MediaBox {
return ResourceStorePaths(partial: "\(fileNameForId(id))_partial", complete: "\(fileNameForId(id))") return ResourceStorePaths(partial: "\(fileNameForId(id))_partial", complete: "\(fileNameForId(id))")
} }
private func cachedRepresentationPathsForId(_ id: MediaResourceId, representation: CachedMediaResourceRepresentation) -> ResourceStorePaths { private func cachedRepresentationPathsForId(_ id: MediaResourceId, representationId: String, keepDuration: CachedMediaRepresentationKeepDuration) -> ResourceStorePaths {
let cacheString: String let cacheString: String
switch representation.keepDuration { switch keepDuration {
case .general: case .general:
cacheString = "cache" cacheString = "cache"
case .shortLived: case .shortLived:
cacheString = "short-cache" cacheString = "short-cache"
} }
return ResourceStorePaths(partial: "\(self.basePath)/\(cacheString)/\(fileNameForId(id))_partial:\(representation.uniqueId)", complete: "\(self.basePath)/\(cacheString)/\(fileNameForId(id)):\(representation.uniqueId)") return ResourceStorePaths(partial: "\(self.basePath)/\(cacheString)/\(fileNameForId(id))_partial:\(representationId)", complete: "\(self.basePath)/\(cacheString)/\(fileNameForId(id)):\(representationId)")
} }
public func cachedRepresentationPathForId(_ id: String, representationId: String, keepDuration: CachedMediaRepresentationKeepDuration) -> String { public func cachedRepresentationPathForId(_ id: String, representationId: String, keepDuration: CachedMediaRepresentationKeepDuration) -> String {
@ -317,12 +308,6 @@ public final class MediaBox {
} }
} }
private func maybeCopiedPreFetchedResource(completePath: String, resource: MediaResource) {
if let path = self.preFetchedResourcePath(resource) {
let _ = try? FileManager.default.copyItem(atPath: path, toPath: completePath)
}
}
public func resourceStatus(_ resource: MediaResource, approximateSynchronousValue: Bool = false) -> Signal<MediaResourceStatus, NoError> { public func resourceStatus(_ resource: MediaResource, approximateSynchronousValue: Bool = false) -> Signal<MediaResourceStatus, NoError> {
let signal = Signal<MediaResourceStatus, NoError> { subscriber in let signal = Signal<MediaResourceStatus, NoError> { subscriber in
let disposable = MetaDisposable() let disposable = MetaDisposable()
@ -337,16 +322,6 @@ public final class MediaBox {
subscriber.putNext(.Local) subscriber.putNext(.Local)
subscriber.putCompletion() subscriber.putCompletion()
} else { } else {
self.maybeCopiedPreFetchedResource(completePath: paths.complete, resource: resource)
if let _ = fileSize(paths.complete) {
self.timeBasedCleanup.touch(paths: [
paths.complete
])
subscriber.putNext(.Local)
subscriber.putCompletion()
return
}
self.statusQueue.async { self.statusQueue.async {
let resourceId = resource.id let resourceId = resource.id
let statusContext: ResourceStatusContext let statusContext: ResourceStatusContext
@ -371,7 +346,7 @@ public final class MediaBox {
if let statusUpdateDisposable = statusUpdateDisposable { if let statusUpdateDisposable = statusUpdateDisposable {
let statusQueue = self.statusQueue let statusQueue = self.statusQueue
self.dataQueue.async { self.dataQueue.async {
if let (fileContext, releaseContext) = self.fileContext(for: resource) { if let (fileContext, releaseContext) = self.fileContext(for: resource.id) {
let statusDisposable = fileContext.status(next: { [weak statusContext] value in let statusDisposable = fileContext.status(next: { [weak statusContext] value in
statusQueue.async { statusQueue.async {
if let current = self.statusContexts[resourceId], current === statusContext, current.status != value { if let current = self.statusContexts[resourceId], current === statusContext, current.status != value {
@ -459,17 +434,15 @@ public final class MediaBox {
} }
public func resourceData(_ resource: MediaResource, pathExtension: String? = nil, option: ResourceDataRequestOption = .complete(waitUntilFetchStatus: false), attemptSynchronously: Bool = false) -> Signal<MediaResourceData, NoError> { public func resourceData(_ resource: MediaResource, pathExtension: String? = nil, option: ResourceDataRequestOption = .complete(waitUntilFetchStatus: false), attemptSynchronously: Bool = false) -> Signal<MediaResourceData, NoError> {
return self.resourceData(id: resource.id, pathExtension: pathExtension, option: option, attemptSynchronously: attemptSynchronously)
}
public func resourceData(id: MediaResourceId, pathExtension: String? = nil, option: ResourceDataRequestOption = .complete(waitUntilFetchStatus: false), attemptSynchronously: Bool = false) -> Signal<MediaResourceData, NoError> {
return Signal { subscriber in return Signal { subscriber in
let disposable = MetaDisposable() let disposable = MetaDisposable()
let begin: () -> Void = { let begin: () -> Void = {
let paths = self.storePathsForId(resource.id) let paths = self.storePathsForId(id)
var completeSize = fileSize(paths.complete)
if completeSize == nil {
self.maybeCopiedPreFetchedResource(completePath: paths.complete, resource: resource)
completeSize = fileSize(paths.complete)
}
if let completeSize = fileSize(paths.complete) { if let completeSize = fileSize(paths.complete) {
self.timeBasedCleanup.touch(paths: [ self.timeBasedCleanup.touch(paths: [
@ -491,7 +464,7 @@ public final class MediaBox {
subscriber.putNext(MediaResourceData(path: paths.partial, offset: 0, size: fileSize(paths.partial) ?? 0, complete: false)) subscriber.putNext(MediaResourceData(path: paths.partial, offset: 0, size: fileSize(paths.partial) ?? 0, complete: false))
} }
self.dataQueue.async { self.dataQueue.async {
if let (fileContext, releaseContext) = self.fileContext(for: resource) { if let (fileContext, releaseContext) = self.fileContext(for: id) {
let waitUntilAfterInitialFetch: Bool let waitUntilAfterInitialFetch: Bool
switch option { switch option {
case let .complete(waitUntilFetchStatus): case let .complete(waitUntilFetchStatus):
@ -535,16 +508,16 @@ public final class MediaBox {
} }
} }
private func fileContext(for resource: MediaResource) -> (MediaBoxFileContext, () -> Void)? { private func fileContext(for id: MediaResourceId) -> (MediaBoxFileContext, () -> Void)? {
assert(self.dataQueue.isCurrent()) assert(self.dataQueue.isCurrent())
let resourceId = resource.id let resourceId = id
var context: MediaBoxFileContext? var context: MediaBoxFileContext?
if let current = self.fileContexts[resourceId] { if let current = self.fileContexts[resourceId] {
context = current context = current
} else { } else {
let paths = self.storePathsForId(resource.id) let paths = self.storePathsForId(id)
self.timeBasedCleanup.touch(paths: [ self.timeBasedCleanup.touch(paths: [
paths.complete, paths.complete,
paths.partial, paths.partial,
@ -581,7 +554,7 @@ public final class MediaBox {
let disposable = MetaDisposable() let disposable = MetaDisposable()
self.dataQueue.async { self.dataQueue.async {
guard let (fileContext, releaseContext) = self.fileContext(for: resource) else { guard let (fileContext, releaseContext) = self.fileContext(for: resource.id) else {
subscriber.putCompletion() subscriber.putCompletion()
return return
} }
@ -615,11 +588,15 @@ public final class MediaBox {
} }
public func resourceData(_ resource: MediaResource, size: Int, in range: Range<Int>, mode: ResourceDataRangeMode = .complete, notifyAboutIncomplete: Bool = false, attemptSynchronously: Bool = false) -> Signal<(Data, Bool), NoError> { public func resourceData(_ resource: MediaResource, size: Int, in range: Range<Int>, mode: ResourceDataRangeMode = .complete, notifyAboutIncomplete: Bool = false, attemptSynchronously: Bool = false) -> Signal<(Data, Bool), NoError> {
return self.resourceData(id: resource.id, size: size, in: range, mode: mode, notifyAboutIncomplete: notifyAboutIncomplete, attemptSynchronously: attemptSynchronously)
}
public func resourceData(id: MediaResourceId, size: Int, in range: Range<Int>, mode: ResourceDataRangeMode = .complete, notifyAboutIncomplete: Bool = false, attemptSynchronously: Bool = false) -> Signal<(Data, Bool), NoError> {
return Signal { subscriber in return Signal { subscriber in
let disposable = MetaDisposable() let disposable = MetaDisposable()
if attemptSynchronously { if attemptSynchronously {
let paths = self.storePathsForId(resource.id) let paths = self.storePathsForId(id)
if let completeSize = fileSize(paths.complete) { if let completeSize = fileSize(paths.complete) {
self.timeBasedCleanup.touch(paths: [ self.timeBasedCleanup.touch(paths: [
@ -649,7 +626,7 @@ public final class MediaBox {
} }
self.dataQueue.async { self.dataQueue.async {
guard let (fileContext, releaseContext) = self.fileContext(for: resource) else { guard let (fileContext, releaseContext) = self.fileContext(for: id) else {
subscriber.putCompletion() subscriber.putCompletion()
return return
} }
@ -700,7 +677,7 @@ public final class MediaBox {
let disposable = MetaDisposable() let disposable = MetaDisposable()
self.dataQueue.async { self.dataQueue.async {
guard let (fileContext, releaseContext) = self.fileContext(for: resource) else { guard let (fileContext, releaseContext) = self.fileContext(for: resource.id) else {
subscriber.putCompletion() subscriber.putCompletion()
return return
} }
@ -734,7 +711,7 @@ public final class MediaBox {
} }
subscriber.putCompletion() subscriber.putCompletion()
} else { } else {
if let (fileContext, releaseContext) = self.fileContext(for: resource) { if let (fileContext, releaseContext) = self.fileContext(for: resource.id) {
let fetchResource = self.wrappedFetchResource.get() let fetchResource = self.wrappedFetchResource.get()
let fetchedDisposable = fileContext.fetchedFullRange(fetch: { ranges in let fetchedDisposable = fileContext.fetchedFullRange(fetch: { ranges in
return fetchResource return fetchResource
@ -796,7 +773,7 @@ public final class MediaBox {
public func cancelInteractiveResourceFetch(_ resource: MediaResource) { public func cancelInteractiveResourceFetch(_ resource: MediaResource) {
self.dataQueue.async { self.dataQueue.async {
if let (fileContext, releaseContext) = self.fileContext(for: resource) { if let (fileContext, releaseContext) = self.fileContext(for: resource.id) {
fileContext.cancelFullRangeFetches() fileContext.cancelFullRangeFetches()
releaseContext() releaseContext()
} }
@ -805,7 +782,7 @@ public final class MediaBox {
public func storeCachedResourceRepresentation(_ resource: MediaResource, representation: CachedMediaResourceRepresentation, data: Data) { public func storeCachedResourceRepresentation(_ resource: MediaResource, representation: CachedMediaResourceRepresentation, data: Data) {
self.dataQueue.async { self.dataQueue.async {
let path = self.cachedRepresentationPathsForId(resource.id, representation: representation).complete let path = self.cachedRepresentationPathsForId(resource.id, representationId: representation.uniqueId, keepDuration: representation.keepDuration).complete
let _ = try? data.write(to: URL(fileURLWithPath: path)) let _ = try? data.write(to: URL(fileURLWithPath: path))
} }
} }
@ -815,7 +792,7 @@ public final class MediaBox {
let disposable = MetaDisposable() let disposable = MetaDisposable()
let begin: () -> Void = { let begin: () -> Void = {
let paths = self.cachedRepresentationPathsForId(resource.id, representation: representation) let paths = self.cachedRepresentationPathsForId(resource.id, representationId: representation.uniqueId, keepDuration: representation.keepDuration)
if let size = fileSize(paths.complete) { if let size = fileSize(paths.complete) {
self.timeBasedCleanup.touch(paths: [ self.timeBasedCleanup.touch(paths: [
paths.complete paths.complete
@ -837,7 +814,7 @@ public final class MediaBox {
subscriber.putNext(MediaResourceData(path: paths.partial, offset: 0, size: 0, complete: false)) subscriber.putNext(MediaResourceData(path: paths.partial, offset: 0, size: 0, complete: false))
} }
self.dataQueue.async { self.dataQueue.async {
let key = CachedMediaResourceRepresentationKey(resourceId: resource.id, representation: representation) let key = CachedMediaResourceRepresentationKey(resourceId: resource.id.stringRepresentation, representation: representation.uniqueId)
let context: CachedMediaResourceRepresentationContext let context: CachedMediaResourceRepresentationContext
if let currentContext = self.cachedRepresentationContexts[key] { if let currentContext = self.cachedRepresentationContexts[key] {
context = currentContext context = currentContext
@ -977,6 +954,161 @@ public final class MediaBox {
} }
} }
public func customResourceData(id: String, baseResourceId: String?, pathExtension: String?, complete: Bool, fetch: (() -> Signal<CachedMediaResourceRepresentationResult, NoError>)?, keepDuration: CachedMediaRepresentationKeepDuration, attemptSynchronously: Bool) -> Signal<MediaResourceData, NoError> {
return Signal { subscriber in
let disposable = MetaDisposable()
let begin: () -> Void = {
let paths: ResourceStorePaths
if let baseResourceId = baseResourceId {
paths = self.cachedRepresentationPathsForId(MediaResourceId(baseResourceId), representationId: id, keepDuration: keepDuration)
} else {
paths = self.storePathsForId(MediaResourceId(id))
}
if let size = fileSize(paths.complete) {
self.timeBasedCleanup.touch(paths: [
paths.complete
])
if let pathExtension = pathExtension {
let symlinkPath = paths.complete + ".\(pathExtension)"
if fileSize(symlinkPath) == nil {
let _ = try? FileManager.default.linkItem(atPath: paths.complete, toPath: symlinkPath)
}
subscriber.putNext(MediaResourceData(path: symlinkPath, offset: 0, size: size, complete: true))
subscriber.putCompletion()
} else {
subscriber.putNext(MediaResourceData(path: paths.complete, offset: 0, size: size, complete: true))
subscriber.putCompletion()
}
} else if let fetch = fetch {
if attemptSynchronously && complete {
subscriber.putNext(MediaResourceData(path: paths.partial, offset: 0, size: 0, complete: false))
}
self.dataQueue.async {
let key = CachedMediaResourceRepresentationKey(resourceId: baseResourceId, representation: id)
let context: CachedMediaResourceRepresentationContext
if let currentContext = self.cachedRepresentationContexts[key] {
context = currentContext
} else {
context = CachedMediaResourceRepresentationContext()
self.cachedRepresentationContexts[key] = context
}
let index = context.dataSubscribers.add(CachedMediaResourceRepresentationSubscriber(update: { data in
if !complete || data.complete {
if let pathExtension = pathExtension, data.complete {
let symlinkPath = data.path + ".\(pathExtension)"
if fileSize(symlinkPath) == nil {
let _ = try? FileManager.default.linkItem(atPath: data.path, toPath: symlinkPath)
}
subscriber.putNext(MediaResourceData(path: symlinkPath, offset: data.offset, size: data.size, complete: data.complete))
} else {
subscriber.putNext(data)
}
}
if data.complete {
subscriber.putCompletion()
}
}, onlyComplete: complete))
if let currentData = context.currentData {
if !complete || currentData.complete {
subscriber.putNext(currentData)
}
if currentData.complete {
subscriber.putCompletion()
}
} else if !complete {
subscriber.putNext(MediaResourceData(path: paths.partial, offset: 0, size: 0, complete: false))
}
disposable.set(ActionDisposable { [weak context] in
self.dataQueue.async {
if let currentContext = self.cachedRepresentationContexts[key], currentContext === context {
currentContext.dataSubscribers.remove(index)
if currentContext.dataSubscribers.isEmpty {
currentContext.disposable.dispose()
self.cachedRepresentationContexts.removeValue(forKey: key)
}
}
}
})
if !context.initialized {
context.initialized = true
let signal = fetch()
|> deliverOn(self.dataQueue)
context.disposable.set(signal.start(next: { [weak self, weak context] next in
guard let strongSelf = self else {
return
}
var isDone = false
switch next {
case let .temporaryPath(temporaryPath):
rename(temporaryPath, paths.complete)
isDone = true
case let .tempFile(tempFile):
rename(tempFile.path, paths.complete)
TempBox.shared.dispose(tempFile)
isDone = true
case .reset:
let file = ManagedFile(queue: strongSelf.dataQueue, path: paths.partial, mode: .readwrite)
file?.truncate(count: 0)
unlink(paths.complete)
case let .data(dataPart):
let file = ManagedFile(queue: strongSelf.dataQueue, path: paths.partial, mode: .append)
let dataCount = dataPart.count
dataPart.withUnsafeBytes { rawBytes -> Void in
let bytes = rawBytes.baseAddress!.assumingMemoryBound(to: UInt8.self)
let _ = file?.write(bytes, count: dataCount)
}
case .done:
link(paths.partial, paths.complete)
isDone = true
}
if let strongSelf = self, let currentContext = strongSelf.cachedRepresentationContexts[key], currentContext === context {
if isDone {
currentContext.disposable.dispose()
strongSelf.cachedRepresentationContexts.removeValue(forKey: key)
}
if let size = fileSize(paths.complete) {
let data = MediaResourceData(path: paths.complete, offset: 0, size: size, complete: isDone)
currentContext.currentData = data
for subscriber in currentContext.dataSubscribers.copyItems() {
if !subscriber.onlyComplete || isDone {
subscriber.update(data)
}
}
} else if let size = fileSize(paths.partial) {
let data = MediaResourceData(path: paths.partial, offset: 0, size: size, complete: isDone)
currentContext.currentData = data
for subscriber in currentContext.dataSubscribers.copyItems() {
if !subscriber.onlyComplete || isDone {
subscriber.update(data)
}
}
}
}
}))
}
}
} else {
subscriber.putNext(MediaResourceData(path: paths.partial, offset: 0, size: 0, complete: false))
subscriber.putCompletion()
}
}
if attemptSynchronously {
begin()
} else {
self.concurrentQueue.async(begin)
}
return ActionDisposable {
disposable.dispose()
}
}
}
public func collectResourceCacheUsage(_ ids: [MediaResourceId]) -> Signal<[MediaResourceId: Int64], NoError> { public func collectResourceCacheUsage(_ ids: [MediaResourceId]) -> Signal<[MediaResourceId: Int64], NoError> {
return Signal { subscriber in return Signal { subscriber in
self.dataQueue.async { self.dataQueue.async {

View File

@ -1222,8 +1222,7 @@ public func updateAccountNetworkUsageStats(account: Account, category: MediaReso
public typealias FetchCachedResourceRepresentation = (_ account: Account, _ resource: MediaResource, _ representation: CachedMediaResourceRepresentation) -> Signal<CachedMediaResourceRepresentationResult, NoError> public typealias FetchCachedResourceRepresentation = (_ account: Account, _ resource: MediaResource, _ representation: CachedMediaResourceRepresentation) -> Signal<CachedMediaResourceRepresentationResult, NoError>
public typealias TransformOutgoingMessageMedia = (_ postbox: Postbox, _ network: Network, _ media: AnyMediaReference, _ userInteractive: Bool) -> Signal<AnyMediaReference?, NoError> public typealias TransformOutgoingMessageMedia = (_ postbox: Postbox, _ network: Network, _ media: AnyMediaReference, _ userInteractive: Bool) -> Signal<AnyMediaReference?, NoError>
public func setupAccount(_ account: Account, fetchCachedResourceRepresentation: FetchCachedResourceRepresentation? = nil, transformOutgoingMessageMedia: TransformOutgoingMessageMedia? = nil, preFetchedResourcePath: @escaping (MediaResource) -> String? = { _ in return nil }) { public func setupAccount(_ account: Account, fetchCachedResourceRepresentation: FetchCachedResourceRepresentation? = nil, transformOutgoingMessageMedia: TransformOutgoingMessageMedia? = nil) {
account.postbox.mediaBox.preFetchedResourcePath = preFetchedResourcePath
account.postbox.mediaBox.fetchResource = { [weak account] resource, intervals, parameters -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> in account.postbox.mediaBox.fetchResource = { [weak account] resource, intervals, parameters -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> in
if let strongAccount = account { if let strongAccount = account {
if let result = strongAccount.auxiliaryMethods.fetchResource(strongAccount, resource, intervals, parameters) { if let result = strongAccount.auxiliaryMethods.fetchResource(strongAccount, resource, intervals, parameters) {

View File

@ -2,7 +2,15 @@ import Foundation
import SwiftSignalKit import SwiftSignalKit
import Postbox import Postbox
public typealias EngineTempBox = TempBox
public typealias EngineTempBoxFile = TempBoxFile
public final class EngineMediaResource: Equatable { public final class EngineMediaResource: Equatable {
public enum CacheTimeout {
case `default`
case shortLived
}
public struct ByteRange { public struct ByteRange {
public enum Priority { public enum Priority {
case `default` case `default`
@ -21,27 +29,16 @@ public final class EngineMediaResource: Equatable {
public final class Fetch { public final class Fetch {
public enum Result { public enum Result {
case dataPart(resourceOffset: Int, data: Data, range: Range<Int>, complete: Bool)
case resourceSizeUpdated(Int)
case progressUpdated(Float)
case replaceHeader(data: Data, range: Range<Int>)
case moveLocalFile(path: String)
case moveTempFile(file: TempBoxFile) case moveTempFile(file: TempBoxFile)
case copyLocalItem(MediaResourceDataFetchCopyLocalItem)
case reset
} }
public enum Error { public enum Error {
case generic case generic
} }
public let signal: ( public let signal: () -> Signal<Result, Error>
Signal<[EngineMediaResource.ByteRange], NoError>
) -> Signal<Result, Error>
public init(_ signal: @escaping ( public init(_ signal: @escaping () -> Signal<Result, Error>) {
Signal<[EngineMediaResource.ByteRange], NoError>
) -> Signal<Result, Error>) {
self.signal = signal self.signal = signal
} }
} }
@ -93,55 +90,9 @@ public final class EngineMediaResource: Equatable {
} }
} }
public extension MediaResource { public extension EngineMediaResource.ResourceData {
func fetch(engine: TelegramEngine, parameters: MediaResourceFetchParameters?) -> EngineMediaResource.Fetch { convenience init(_ data: MediaResourceData) {
return EngineMediaResource.Fetch { ranges in self.init(path: data.path, availableSize: data.size, isComplete: data.complete)
return Signal { subscriber in
return engine.account.postbox.mediaBox.fetchResource!(
self,
ranges |> map { ranges -> [(Range<Int>, MediaBoxFetchPriority)] in
return ranges.map { range -> (Range<Int>, MediaBoxFetchPriority) in
let mappedPriority: MediaBoxFetchPriority
switch range.priority {
case .default:
mappedPriority = .default
case .elevated:
mappedPriority = .elevated
case .maximum:
mappedPriority = .maximum
}
return (range.range, mappedPriority)
}
},
parameters
).start(next: { result in
let mappedResult: EngineMediaResource.Fetch.Result
switch result {
case let .dataPart(resourceOffset, data, range, complete):
mappedResult = .dataPart(resourceOffset: resourceOffset, data: data, range: range, complete: complete)
case let .resourceSizeUpdated(size):
mappedResult = .resourceSizeUpdated(size)
case let .progressUpdated(progress):
mappedResult = .progressUpdated(progress)
case let .replaceHeader(data, range):
mappedResult = .replaceHeader(data: data, range: range)
case let .moveLocalFile(path):
mappedResult = .moveLocalFile(path: path)
case let .moveTempFile(file):
mappedResult = .moveTempFile(file: file)
case let .copyLocalItem(item):
mappedResult = .copyLocalItem(item)
case .reset:
mappedResult = .reset
}
subscriber.putNext(mappedResult)
}, error: { _ in
subscriber.putError(.generic)
}, completed: {
subscriber.putCompletion()
})
}
}
} }
} }
@ -165,12 +116,66 @@ public extension TelegramEngine {
return _internal_clearCachedMediaResources(account: self.account, mediaResourceIds: mediaResourceIds) return _internal_clearCachedMediaResources(account: self.account, mediaResourceIds: mediaResourceIds)
} }
public func data(id: String) -> Signal<EngineMediaResource.ResourceData, NoError> { public func data(id: EngineMediaResource.Id, attemptSynchronously: Bool = false) -> Signal<EngineMediaResource.ResourceData, NoError> {
preconditionFailure() return self.account.postbox.mediaBox.resourceData(
id: MediaResourceId(id.stringRepresentation),
pathExtension: nil,
option: .complete(waitUntilFetchStatus: false),
attemptSynchronously: attemptSynchronously
)
|> map { data in
return EngineMediaResource.ResourceData(data)
}
} }
public func fetch(id: String, fetch: EngineMediaResource.Fetch) -> Signal<Never, NoError> { public func custom(id: String, fetch: EngineMediaResource.Fetch, cacheTimeout: EngineMediaResource.CacheTimeout = .default, attemptSynchronously: Bool = false) -> Signal<EngineMediaResource.ResourceData, NoError> {
preconditionFailure() let mappedKeepDuration: CachedMediaRepresentationKeepDuration
switch cacheTimeout {
case .default:
mappedKeepDuration = .general
case .shortLived:
mappedKeepDuration = .shortLived
}
return self.account.postbox.mediaBox.customResourceData(
id: id,
baseResourceId: nil,
pathExtension: nil,
complete: true,
fetch: {
return Signal { subscriber in
return fetch.signal().start(next: { result in
let mappedResult: CachedMediaResourceRepresentationResult
switch result {
case let .moveTempFile(file):
mappedResult = .tempFile(file)
}
subscriber.putNext(mappedResult)
}, completed: {
subscriber.putCompletion()
})
}
},
keepDuration: mappedKeepDuration,
attemptSynchronously: attemptSynchronously
)
|> map { data in
return EngineMediaResource.ResourceData(data)
}
}
public func httpData(url: String) -> Signal<Data, EngineMediaResource.Fetch.Error> {
return fetchHttpResource(url: url)
|> mapError { _ -> EngineMediaResource.Fetch.Error in
return .generic
}
|> mapToSignal { value -> Signal<Data, EngineMediaResource.Fetch.Error> in
switch value {
case let .dataPart(_, data, _, _):
return .single(data)
default:
return .complete()
}
}
} }
public func cancelAllFetches(id: String) { public func cancelAllFetches(id: String) {

View File

@ -135,7 +135,7 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
} }
} }
if updated { if updated {
updateImageSignal = chatMapSnapshotImage(account: item.context.account, resource: MapSnapshotMediaResource(latitude: selectedMedia.latitude, longitude: selectedMedia.longitude, width: Int32(imageSize.width), height: Int32(imageSize.height))) updateImageSignal = chatMapSnapshotImage(engine: item.context.engine, resource: MapSnapshotMediaResource(latitude: selectedMedia.latitude, longitude: selectedMedia.longitude, width: Int32(imageSize.width), height: Int32(imageSize.height)))
} }
} }

View File

@ -247,7 +247,7 @@ private enum CreateGroupEntry: ItemListNodeEntry {
case let .locationHeader(_, title): case let .locationHeader(_, title):
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
case let .location(theme, location): case let .location(theme, location):
let imageSignal = chatMapSnapshotImage(account: arguments.context.account, resource: MapSnapshotMediaResource(latitude: location.latitude, longitude: location.longitude, width: 90, height: 90)) let imageSignal = chatMapSnapshotImage(engine: arguments.context.engine, resource: MapSnapshotMediaResource(latitude: location.latitude, longitude: location.longitude, width: 90, height: 90))
return ItemListAddressItem(theme: theme, label: "", text: location.address.replacingOccurrences(of: ", ", with: "\n"), imageSignal: imageSignal, selected: nil, sectionId: self.section, style: .blocks, action: nil) return ItemListAddressItem(theme: theme, label: "", text: location.address.replacingOccurrences(of: ", ", with: "\n"), imageSignal: imageSignal, selected: nil, sectionId: self.section, style: .blocks, action: nil)
case let .changeLocation(_, text): case let .changeLocation(_, text):
return ItemListActionItem(presentationData: presentationData, title: text, kind: .generic, alignment: .natural, sectionId: ItemListSectionId(self.section), style: .blocks, action: { return ItemListActionItem(presentationData: presentationData, title: text, kind: .generic, alignment: .natural, sectionId: ItemListSectionId(self.section), style: .blocks, action: {
@ -258,7 +258,7 @@ private enum CreateGroupEntry: ItemListNodeEntry {
case let .venueHeader(_, title): case let .venueHeader(_, title):
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
case let .venue(_, _, venue): case let .venue(_, _, venue):
return ItemListVenueItem(presentationData: presentationData, account: arguments.context.account, venue: venue, sectionId: self.section, style: .blocks, action: { return ItemListVenueItem(presentationData: presentationData, engine: arguments.context.engine, venue: venue, sectionId: self.section, style: .blocks, action: {
arguments.updateWithVenue(venue) arguments.updateWithVenue(venue)
}) })
} }

View File

@ -119,8 +119,6 @@ public func fetchCachedResourceRepresentation(account: Account, resource: MediaR
} }
return fetchAnimatedStickerFirstFrameRepresentation(account: account, resource: resource, resourceData: data, representation: representation) return fetchAnimatedStickerFirstFrameRepresentation(account: account, resource: resource, resourceData: data, representation: representation)
} }
} else if let resource = resource as? MapSnapshotMediaResource, let _ = representation as? MapSnapshotMediaResourceRepresentation {
return fetchMapSnapshotResource(resource: resource)
} else if let resource = resource as? YoutubeEmbedStoryboardMediaResource, let _ = representation as? YoutubeEmbedStoryboardMediaResourceRepresentation { } else if let resource = resource as? YoutubeEmbedStoryboardMediaResource, let _ = representation as? YoutubeEmbedStoryboardMediaResourceRepresentation {
return fetchYoutubeEmbedStoryboardResource(resource: resource) return fetchYoutubeEmbedStoryboardResource(resource: resource)
} else if let representation = representation as? CachedPreparedPatternWallpaperRepresentation { } else if let representation = representation as? CachedPreparedPatternWallpaperRepresentation {

View File

@ -1041,7 +1041,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
if let location = (data.cachedData as? CachedChannelData)?.peerGeoLocation { if let location = (data.cachedData as? CachedChannelData)?.peerGeoLocation {
items[.groupLocation]!.append(PeerInfoScreenHeaderItem(id: ItemLocationHeader, text: presentationData.strings.GroupInfo_Location.uppercased())) items[.groupLocation]!.append(PeerInfoScreenHeaderItem(id: ItemLocationHeader, text: presentationData.strings.GroupInfo_Location.uppercased()))
let imageSignal = chatMapSnapshotImage(account: context.account, resource: MapSnapshotMediaResource(latitude: location.latitude, longitude: location.longitude, width: 90, height: 90)) let imageSignal = chatMapSnapshotImage(engine: context.engine, resource: MapSnapshotMediaResource(latitude: location.latitude, longitude: location.longitude, width: 90, height: 90))
items[.groupLocation]!.append(PeerInfoScreenAddressItem( items[.groupLocation]!.append(PeerInfoScreenAddressItem(
id: ItemLocation, id: ItemLocation,
label: "", label: "",
@ -1271,7 +1271,7 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
if isCreator, let location = cachedData.peerGeoLocation { if isCreator, let location = cachedData.peerGeoLocation {
items[.groupLocation]!.append(PeerInfoScreenHeaderItem(id: ItemLocationHeader, text: presentationData.strings.GroupInfo_Location.uppercased())) items[.groupLocation]!.append(PeerInfoScreenHeaderItem(id: ItemLocationHeader, text: presentationData.strings.GroupInfo_Location.uppercased()))
let imageSignal = chatMapSnapshotImage(account: context.account, resource: MapSnapshotMediaResource(latitude: location.latitude, longitude: location.longitude, width: 90, height: 90)) let imageSignal = chatMapSnapshotImage(engine: context.engine, resource: MapSnapshotMediaResource(latitude: location.latitude, longitude: location.longitude, width: 90, height: 90))
items[.groupLocation]!.append(PeerInfoScreenAddressItem( items[.groupLocation]!.append(PeerInfoScreenAddressItem(
id: ItemLocation, id: ItemLocation,
label: "", label: "",

View File

@ -408,9 +408,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|> mapToSignal { result -> Signal<AddedAccountResult, NoError> in |> mapToSignal { result -> Signal<AddedAccountResult, NoError> in
switch result { switch result {
case let .authorized(account): case let .authorized(account):
setupAccount(account, fetchCachedResourceRepresentation: fetchCachedResourceRepresentation, transformOutgoingMessageMedia: transformOutgoingMessageMedia, preFetchedResourcePath: { resource in setupAccount(account, fetchCachedResourceRepresentation: fetchCachedResourceRepresentation, transformOutgoingMessageMedia: transformOutgoingMessageMedia)
return nil
})
return account.postbox.transaction { transaction -> AddedAccountResult in return account.postbox.transaction { transaction -> AddedAccountResult in
let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration)?.get(LimitsConfiguration.self) ?? LimitsConfiguration.defaultValue let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration)?.get(LimitsConfiguration.self) ?? LimitsConfiguration.defaultValue
let contentSettings = getContentSettings(transaction: transaction) let contentSettings = getContentSettings(transaction: transaction)

View File

@ -31,8 +31,6 @@ public let telegramAccountAuxiliaryMethods = AccountAuxiliaryMethods(fetchResour
return fetchOpenInAppIconResource(resource: resource) return fetchOpenInAppIconResource(resource: resource)
} else if let resource = resource as? EmojiSpriteResource { } else if let resource = resource as? EmojiSpriteResource {
return fetchEmojiSpriteResource(account: account, resource: resource) return fetchEmojiSpriteResource(account: account, resource: resource)
} else if let resource = resource as? VenueIconResource {
return fetchVenueIconResource(account: account, resource: resource)
} else if let resource = resource as? BundleResource { } else if let resource = resource as? BundleResource {
return Signal { subscriber in return Signal { subscriber in
subscriber.putNext(.reset) subscriber.putNext(.reset)