mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 13:35:19 +00:00
Refactoring [skip ci]
This commit is contained in:
parent
b4c5ca2b4d
commit
00b6826303
@ -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))
|
||||
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 {
|
||||
let imageReference = ImageMediaReference.webPage(webPage: WebpageReference(webPage), media: image)
|
||||
self.imageNode.setSignal(chatMessagePhoto(postbox: context.account.postbox, photoReference: imageReference))
|
||||
|
@ -11,7 +11,7 @@ import ShimmerEffect
|
||||
|
||||
public final class ItemListVenueItem: ListViewItem, ItemListItem {
|
||||
let presentationData: ItemListPresentationData
|
||||
let account: Account
|
||||
let engine: TelegramEngine
|
||||
let venue: TelegramMediaMap?
|
||||
let title: String?
|
||||
let subtitle: String?
|
||||
@ -22,9 +22,9 @@ public final class ItemListVenueItem: ListViewItem, ItemListItem {
|
||||
public let sectionId: ItemListSectionId
|
||||
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.account = account
|
||||
self.engine = engine
|
||||
self.venue = venue
|
||||
self.title = title
|
||||
self.subtitle = subtitle
|
||||
@ -281,7 +281,7 @@ public class ItemListVenueItemNode: ListViewItemNode, ItemListItemNode {
|
||||
let _ = addressApply()
|
||||
|
||||
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()))
|
||||
|
@ -217,7 +217,7 @@ public final class ChatMessageLiveLocationPositionNode: ASDisplayNode {
|
||||
|
||||
if let updatedVenueType = 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)
|
||||
|
@ -11,10 +11,10 @@ swift_library(
|
||||
],
|
||||
deps = [
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
"//submodules/PersistentStringHash:PersistentStringHash",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -1,7 +1,6 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import MapKit
|
||||
import SwiftSignalKit
|
||||
@ -21,7 +20,7 @@ public struct MapSnapshotMediaResourceId {
|
||||
}
|
||||
}
|
||||
|
||||
public class MapSnapshotMediaResource: TelegramMediaResource {
|
||||
public class MapSnapshotMediaResource {
|
||||
public let latitude: Double
|
||||
public let longitude: Double
|
||||
public let width: Int32
|
||||
@ -34,49 +33,8 @@ public class MapSnapshotMediaResource: TelegramMediaResource {
|
||||
self.height = height
|
||||
}
|
||||
|
||||
public required init(decoder: PostboxDecoder) {
|
||||
self.latitude = decoder.decodeDoubleForKey("lt", orElse: 0.0)
|
||||
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
|
||||
}
|
||||
public var id: EngineMediaResource.Id {
|
||||
return EngineMediaResource.Id(MapSnapshotMediaResourceId(latitude: self.latitude, longitude: self.longitude, width: self.width, height: self.height).uniqueId)
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,7 +54,7 @@ private func adjustGMapLatitude(_ latitude: Double, offset: Int, zoom: Int) -> D
|
||||
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
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
@ -113,9 +71,9 @@ public func fetchMapSnapshotResource(resource: MapSnapshotMediaResource) -> Sign
|
||||
snapshotter.start(with: DispatchQueue.global(), completionHandler: { result, error in
|
||||
if let image = result?.image {
|
||||
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) {
|
||||
subscriber.putNext(.tempFile(tempFile))
|
||||
subscriber.putNext(.moveTempFile(file: tempFile))
|
||||
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
|
||||
let dataDisposable = account.postbox.mediaBox.cachedResourceRepresentation(resource, representation: MapSnapshotMediaResourceRepresentation(), complete: true).start(next: { next in
|
||||
if next.size != 0 {
|
||||
subscriber.putNext(next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []))
|
||||
let dataDisposable = engine.resources.custom(
|
||||
id: resource.id.stringRepresentation,
|
||||
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)
|
||||
|
||||
@ -144,8 +108,8 @@ public func chatMapSnapshotData(account: Account, resource: MapSnapshotMediaReso
|
||||
}
|
||||
}
|
||||
|
||||
public func chatMapSnapshotImage(account: Account, resource: MapSnapshotMediaResource) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
let signal = chatMapSnapshotData(account: account, resource: resource)
|
||||
public func chatMapSnapshotImage(engine: TelegramEngine, resource: MapSnapshotMediaResource) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
let signal = chatMapSnapshotData(engine: engine, resource: resource)
|
||||
|
||||
return signal |> map { fullSizeData in
|
||||
return { arguments in
|
||||
|
@ -1,10 +1,10 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import AppBundle
|
||||
import PersistentStringHash
|
||||
|
||||
public struct VenueIconResourceId {
|
||||
public let type: String
|
||||
@ -22,79 +22,51 @@ public struct VenueIconResourceId {
|
||||
}
|
||||
}
|
||||
|
||||
public class VenueIconResource: TelegramMediaResource {
|
||||
public class VenueIconResource {
|
||||
public let type: String
|
||||
|
||||
public init(type: String) {
|
||||
self.type = type
|
||||
}
|
||||
|
||||
public required init(decoder: PostboxDecoder) {
|
||||
self.type = decoder.decodeStringForKey("t", orElse: "")
|
||||
}
|
||||
|
||||
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 var id: EngineMediaResource.Id {
|
||||
return EngineMediaResource.Id(VenueIconResourceId(type: self.type).uniqueId)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
subscriber.putNext(.reset)
|
||||
|
||||
let url = "https://ss3.4sqi.net/img/categories_v2/\(resource.type)_88.png"
|
||||
|
||||
let fetchDisposable = MetaDisposable()
|
||||
fetchDisposable.set(fetchHttpResource(url: url).start(next: { next in
|
||||
subscriber.putNext(next)
|
||||
return engine.resources.httpData(url: url).start(next: { data in
|
||||
let file = EngineTempBox.shared.tempFile(fileName: "file.png")
|
||||
let _ = try? data.write(to: URL(fileURLWithPath: file.path))
|
||||
subscriber.putNext(.moveTempFile(file: file))
|
||||
}, completed: {
|
||||
subscriber.putCompletion()
|
||||
}))
|
||||
|
||||
return ActionDisposable {
|
||||
fetchDisposable.dispose()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private func venueIconData(postbox: Postbox, resource: MediaResource) -> Signal<Data?, NoError> {
|
||||
let resourceData = postbox.mediaBox.resourceData(resource)
|
||||
private func venueIconData(engine: TelegramEngine, resource: VenueIconResource) -> Signal<Data?, NoError> {
|
||||
let resourceData = engine.resources.custom(
|
||||
id: resource.id.stringRepresentation,
|
||||
fetch: EngineMediaResource.Fetch {
|
||||
return fetchVenueIconResource(engine: engine, resource: resource)
|
||||
},
|
||||
cacheTimeout: .shortLived
|
||||
)
|
||||
|
||||
let signal = resourceData
|
||||
|> take(1)
|
||||
|> mapToSignal { maybeData -> Signal<Data?, NoError> in
|
||||
if maybeData.complete {
|
||||
let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: [])
|
||||
return .single((loadedData))
|
||||
if maybeData.isComplete {
|
||||
return .single(try? Data(contentsOf: URL(fileURLWithPath: maybeData.path)))
|
||||
} else {
|
||||
let fetched = postbox.mediaBox.fetchedResource(resource, parameters: 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
|
||||
return .single(nil)
|
||||
}
|
||||
} |> distinctUntilChanged(isEqual: { lhs, rhs in
|
||||
}
|
||||
|> distinctUntilChanged(isEqual: { lhs, rhs in
|
||||
if lhs == nil && rhs == nil {
|
||||
return true
|
||||
} else {
|
||||
@ -141,7 +113,7 @@ public func venueIconColor(type: String) -> UIColor {
|
||||
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]
|
||||
}
|
||||
|
||||
@ -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 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 { arguments in
|
||||
let context = DrawingContext(size: arguments.drawingSize, clear: true)
|
||||
|
@ -81,7 +81,7 @@ private func generateLiveLocationIcon(theme: PresentationTheme, stop: Bool) -> U
|
||||
|
||||
final class LocationActionListItem: ListViewItem {
|
||||
let presentationData: ItemListPresentationData
|
||||
let account: Account
|
||||
let engine: TelegramEngine
|
||||
let title: String
|
||||
let subtitle: String
|
||||
let icon: LocationActionListItemIcon
|
||||
@ -89,9 +89,9 @@ final class LocationActionListItem: ListViewItem {
|
||||
let action: () -> 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.account = account
|
||||
self.engine = engine
|
||||
self.title = title
|
||||
self.subtitle = subtitle
|
||||
self.icon = icon
|
||||
@ -279,7 +279,7 @@ final class LocationActionListItemNode: ListViewItemNode {
|
||||
case let .venue(venue):
|
||||
strongSelf.iconNode.isHidden = true
|
||||
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 {
|
||||
|
@ -307,8 +307,8 @@ class LocationPinAnnotationView: MKAnnotationView {
|
||||
let venueType = location.venue?.type ?? ""
|
||||
let color = venueType.isEmpty ? annotation.theme.list.itemAccentColor : venueIconColor(type: venueType)
|
||||
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.smallIconNode.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(engine: annotation.context.engine, type: venueType, background: false))
|
||||
self.smallNode.image = generateSmallBackgroundImage(color: color)
|
||||
self.dotNode.image = generateFilledCircleImage(diameter: 6.0, color: color)
|
||||
|
||||
@ -619,7 +619,7 @@ class LocationPinAnnotationView: MKAnnotationView {
|
||||
|
||||
func setCustom(_ custom: Bool, animated: Bool) {
|
||||
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 {
|
||||
|
@ -13,7 +13,7 @@ import SolidRoundedButtonNode
|
||||
|
||||
final class LocationInfoListItem: ListViewItem {
|
||||
let presentationData: ItemListPresentationData
|
||||
let account: Account
|
||||
let engine: TelegramEngine
|
||||
let location: TelegramMediaMap
|
||||
let address: String?
|
||||
let distance: String?
|
||||
@ -21,9 +21,9 @@ final class LocationInfoListItem: ListViewItem {
|
||||
let action: () -> 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.account = account
|
||||
self.engine = engine
|
||||
self.location = location
|
||||
self.address = address
|
||||
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)
|
||||
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))
|
||||
|
@ -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 {
|
||||
case let .location(_, title, subtitle, venue, coordinate):
|
||||
let icon: LocationActionListItemIcon
|
||||
@ -138,7 +138,7 @@ private enum LocationPickerEntry: Comparable, Identifiable {
|
||||
} else {
|
||||
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 {
|
||||
interaction?.sendVenue(venue)
|
||||
} else if let coordinate = coordinate {
|
||||
@ -148,7 +148,7 @@ private enum LocationPickerEntry: Comparable, Identifiable {
|
||||
interaction?.updateSendActionHighlight(highlighted)
|
||||
})
|
||||
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 {
|
||||
interaction?.sendLiveLocation(coordinate)
|
||||
}
|
||||
@ -157,7 +157,7 @@ private enum LocationPickerEntry: Comparable, Identifiable {
|
||||
return LocationSectionHeaderItem(presentationData: ItemListPresentationData(presentationData), title: title)
|
||||
case let .venue(_, venue, _):
|
||||
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) }
|
||||
}, infoAction: ["home", "work"].contains(venueType) ? {
|
||||
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 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 updates = updateIndices.map { ListViewUpdateItem(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(engine: engine, presentationData: presentationData, interaction: interaction), directionHint: nil) }
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
var displayingPlacesButton = false
|
||||
|
@ -50,7 +50,7 @@ private struct LocationSearchEntry: Identifiable, Comparable {
|
||||
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 header: ChatListSearchItemHeader
|
||||
let subtitle: String?
|
||||
@ -61,7 +61,7 @@ private struct LocationSearchEntry: Identifiable, Comparable {
|
||||
header = ChatListSearchItemHeader(type: .mapAddress, theme: presentationData.theme, strings: presentationData.strings)
|
||||
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)
|
||||
}, header: header)
|
||||
}
|
||||
@ -76,12 +76,12 @@ struct LocationSearchContainerTransition {
|
||||
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 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 updates = updateIndices.map { ListViewUpdateItem(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(engine: engine, presentationData: presentationData, sendVenue: sendVenue), directionHint: nil) }
|
||||
|
||||
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 {
|
||||
let (items, query) = itemsAndQuery ?? (nil, "")
|
||||
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 {
|
||||
self?.interaction.sendVenue(venue)
|
||||
} else {
|
||||
|
@ -126,7 +126,7 @@ private enum LocationViewEntry: Comparable, Identifiable {
|
||||
distanceString = nil
|
||||
}
|
||||
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)
|
||||
}, getDirections: {
|
||||
interaction?.requestDirections()
|
||||
@ -138,7 +138,7 @@ private enum LocationViewEntry: Comparable, Identifiable {
|
||||
} else {
|
||||
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 {
|
||||
interaction?.stopLiveLocation()
|
||||
} else {
|
||||
|
@ -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 : "")
|
||||
}
|
||||
|
||||
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 editingName: ItemListAvatarAndNameInfoItemName?
|
||||
@ -731,7 +731,7 @@ private func deviceContactInfoEntries(account: Account, presentationData: Presen
|
||||
|> mapToSignal { coordinates -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
|
||||
if let (latitude, longitude) = coordinates {
|
||||
let resource = MapSnapshotMediaResource(latitude: latitude, longitude: longitude, width: 90, height: 90)
|
||||
return chatMapSnapshotImage(account: account, resource: resource)
|
||||
return chatMapSnapshotImage(engine: engine, resource: resource)
|
||||
} else {
|
||||
return .single({ _ in return nil })
|
||||
}
|
||||
@ -1220,7 +1220,7 @@ public func deviceContactInfoController(context: AccountContext, updatedPresenta
|
||||
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))
|
||||
}
|
||||
|
@ -98,17 +98,8 @@ public enum CachedMediaRepresentationKeepDuration {
|
||||
}
|
||||
|
||||
private struct CachedMediaResourceRepresentationKey: Hashable {
|
||||
let resourceId: MediaResourceId
|
||||
let representation: CachedMediaResourceRepresentation
|
||||
|
||||
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)
|
||||
}
|
||||
let resourceId: String?
|
||||
let representation: String
|
||||
}
|
||||
|
||||
private final class CachedMediaResourceRepresentationSubscriber {
|
||||
@ -157,7 +148,7 @@ public final class MediaBox {
|
||||
private var keepResourceContexts: [MediaResourceId: MediaBoxKeepResourceContext] = [:]
|
||||
|
||||
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>)? {
|
||||
didSet {
|
||||
if let fetchResource = self.fetchResource {
|
||||
@ -222,15 +213,15 @@ public final class MediaBox {
|
||||
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
|
||||
switch representation.keepDuration {
|
||||
switch keepDuration {
|
||||
case .general:
|
||||
cacheString = "cache"
|
||||
case .shortLived:
|
||||
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 {
|
||||
@ -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> {
|
||||
let signal = Signal<MediaResourceStatus, NoError> { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
@ -337,16 +322,6 @@ public final class MediaBox {
|
||||
subscriber.putNext(.Local)
|
||||
subscriber.putCompletion()
|
||||
} 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 {
|
||||
let resourceId = resource.id
|
||||
let statusContext: ResourceStatusContext
|
||||
@ -371,7 +346,7 @@ public final class MediaBox {
|
||||
if let statusUpdateDisposable = statusUpdateDisposable {
|
||||
let statusQueue = self.statusQueue
|
||||
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
|
||||
statusQueue.async {
|
||||
if let current = self.statusContexts[resourceId], current === statusContext, current.status != value {
|
||||
@ -457,19 +432,17 @@ public final class MediaBox {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
let begin: () -> Void = {
|
||||
let paths = self.storePathsForId(resource.id)
|
||||
|
||||
var completeSize = fileSize(paths.complete)
|
||||
if completeSize == nil {
|
||||
self.maybeCopiedPreFetchedResource(completePath: paths.complete, resource: resource)
|
||||
completeSize = fileSize(paths.complete)
|
||||
}
|
||||
let paths = self.storePathsForId(id)
|
||||
|
||||
if let completeSize = fileSize(paths.complete) {
|
||||
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))
|
||||
}
|
||||
self.dataQueue.async {
|
||||
if let (fileContext, releaseContext) = self.fileContext(for: resource) {
|
||||
if let (fileContext, releaseContext) = self.fileContext(for: id) {
|
||||
let waitUntilAfterInitialFetch: Bool
|
||||
switch option {
|
||||
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())
|
||||
|
||||
let resourceId = resource.id
|
||||
let resourceId = id
|
||||
|
||||
var context: MediaBoxFileContext?
|
||||
if let current = self.fileContexts[resourceId] {
|
||||
context = current
|
||||
} else {
|
||||
let paths = self.storePathsForId(resource.id)
|
||||
let paths = self.storePathsForId(id)
|
||||
self.timeBasedCleanup.touch(paths: [
|
||||
paths.complete,
|
||||
paths.partial,
|
||||
@ -581,7 +554,7 @@ public final class MediaBox {
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
self.dataQueue.async {
|
||||
guard let (fileContext, releaseContext) = self.fileContext(for: resource) else {
|
||||
guard let (fileContext, releaseContext) = self.fileContext(for: resource.id) else {
|
||||
subscriber.putCompletion()
|
||||
return
|
||||
}
|
||||
@ -613,13 +586,17 @@ public final class MediaBox {
|
||||
return disposable
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
if attemptSynchronously {
|
||||
let paths = self.storePathsForId(resource.id)
|
||||
let paths = self.storePathsForId(id)
|
||||
|
||||
if let completeSize = fileSize(paths.complete) {
|
||||
self.timeBasedCleanup.touch(paths: [
|
||||
@ -649,7 +626,7 @@ public final class MediaBox {
|
||||
}
|
||||
|
||||
self.dataQueue.async {
|
||||
guard let (fileContext, releaseContext) = self.fileContext(for: resource) else {
|
||||
guard let (fileContext, releaseContext) = self.fileContext(for: id) else {
|
||||
subscriber.putCompletion()
|
||||
return
|
||||
}
|
||||
@ -700,7 +677,7 @@ public final class MediaBox {
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
self.dataQueue.async {
|
||||
guard let (fileContext, releaseContext) = self.fileContext(for: resource) else {
|
||||
guard let (fileContext, releaseContext) = self.fileContext(for: resource.id) else {
|
||||
subscriber.putCompletion()
|
||||
return
|
||||
}
|
||||
@ -734,7 +711,7 @@ public final class MediaBox {
|
||||
}
|
||||
subscriber.putCompletion()
|
||||
} else {
|
||||
if let (fileContext, releaseContext) = self.fileContext(for: resource) {
|
||||
if let (fileContext, releaseContext) = self.fileContext(for: resource.id) {
|
||||
let fetchResource = self.wrappedFetchResource.get()
|
||||
let fetchedDisposable = fileContext.fetchedFullRange(fetch: { ranges in
|
||||
return fetchResource
|
||||
@ -796,7 +773,7 @@ public final class MediaBox {
|
||||
|
||||
public func cancelInteractiveResourceFetch(_ resource: MediaResource) {
|
||||
self.dataQueue.async {
|
||||
if let (fileContext, releaseContext) = self.fileContext(for: resource) {
|
||||
if let (fileContext, releaseContext) = self.fileContext(for: resource.id) {
|
||||
fileContext.cancelFullRangeFetches()
|
||||
releaseContext()
|
||||
}
|
||||
@ -805,7 +782,7 @@ public final class MediaBox {
|
||||
|
||||
public func storeCachedResourceRepresentation(_ resource: MediaResource, representation: CachedMediaResourceRepresentation, data: Data) {
|
||||
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))
|
||||
}
|
||||
}
|
||||
@ -815,7 +792,7 @@ public final class MediaBox {
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
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) {
|
||||
self.timeBasedCleanup.touch(paths: [
|
||||
paths.complete
|
||||
@ -837,7 +814,7 @@ public final class MediaBox {
|
||||
subscriber.putNext(MediaResourceData(path: paths.partial, offset: 0, size: 0, complete: false))
|
||||
}
|
||||
self.dataQueue.async {
|
||||
let key = CachedMediaResourceRepresentationKey(resourceId: resource.id, representation: representation)
|
||||
let key = CachedMediaResourceRepresentationKey(resourceId: resource.id.stringRepresentation, representation: representation.uniqueId)
|
||||
let context: CachedMediaResourceRepresentationContext
|
||||
if let currentContext = self.cachedRepresentationContexts[key] {
|
||||
context = currentContext
|
||||
@ -976,6 +953,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> {
|
||||
return Signal { subscriber in
|
||||
@ -1160,7 +1292,7 @@ public final class MediaBox {
|
||||
return EmptyDisposable
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func allFileContexts() -> Signal<[(partial: String, complete: String)], NoError> {
|
||||
return Signal { subscriber in
|
||||
self.dataQueue.async {
|
||||
|
@ -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 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 }) {
|
||||
account.postbox.mediaBox.preFetchedResourcePath = preFetchedResourcePath
|
||||
public func setupAccount(_ account: Account, fetchCachedResourceRepresentation: FetchCachedResourceRepresentation? = nil, transformOutgoingMessageMedia: TransformOutgoingMessageMedia? = nil) {
|
||||
account.postbox.mediaBox.fetchResource = { [weak account] resource, intervals, parameters -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> in
|
||||
if let strongAccount = account {
|
||||
if let result = strongAccount.auxiliaryMethods.fetchResource(strongAccount, resource, intervals, parameters) {
|
||||
|
@ -2,7 +2,15 @@ import Foundation
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
|
||||
public typealias EngineTempBox = TempBox
|
||||
public typealias EngineTempBoxFile = TempBoxFile
|
||||
|
||||
public final class EngineMediaResource: Equatable {
|
||||
public enum CacheTimeout {
|
||||
case `default`
|
||||
case shortLived
|
||||
}
|
||||
|
||||
public struct ByteRange {
|
||||
public enum Priority {
|
||||
case `default`
|
||||
@ -21,27 +29,16 @@ public final class EngineMediaResource: Equatable {
|
||||
|
||||
public final class Fetch {
|
||||
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 copyLocalItem(MediaResourceDataFetchCopyLocalItem)
|
||||
case reset
|
||||
}
|
||||
|
||||
public enum Error {
|
||||
case generic
|
||||
}
|
||||
|
||||
public let signal: (
|
||||
Signal<[EngineMediaResource.ByteRange], NoError>
|
||||
) -> Signal<Result, Error>
|
||||
public let signal: () -> Signal<Result, Error>
|
||||
|
||||
public init(_ signal: @escaping (
|
||||
Signal<[EngineMediaResource.ByteRange], NoError>
|
||||
) -> Signal<Result, Error>) {
|
||||
public init(_ signal: @escaping () -> Signal<Result, Error>) {
|
||||
self.signal = signal
|
||||
}
|
||||
}
|
||||
@ -93,55 +90,9 @@ public final class EngineMediaResource: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public extension MediaResource {
|
||||
func fetch(engine: TelegramEngine, parameters: MediaResourceFetchParameters?) -> EngineMediaResource.Fetch {
|
||||
return EngineMediaResource.Fetch { ranges in
|
||||
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()
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension EngineMediaResource.ResourceData {
|
||||
convenience init(_ data: MediaResourceData) {
|
||||
self.init(path: data.path, availableSize: data.size, isComplete: data.complete)
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,12 +116,66 @@ public extension TelegramEngine {
|
||||
return _internal_clearCachedMediaResources(account: self.account, mediaResourceIds: mediaResourceIds)
|
||||
}
|
||||
|
||||
public func data(id: String) -> Signal<EngineMediaResource.ResourceData, NoError> {
|
||||
preconditionFailure()
|
||||
public func data(id: EngineMediaResource.Id, attemptSynchronously: Bool = false) -> Signal<EngineMediaResource.ResourceData, NoError> {
|
||||
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> {
|
||||
preconditionFailure()
|
||||
public func custom(id: String, fetch: EngineMediaResource.Fetch, cacheTimeout: EngineMediaResource.CacheTimeout = .default, attemptSynchronously: Bool = false) -> Signal<EngineMediaResource.ResourceData, NoError> {
|
||||
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) {
|
||||
|
@ -135,7 +135,7 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
}
|
||||
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)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,7 +247,7 @@ private enum CreateGroupEntry: ItemListNodeEntry {
|
||||
case let .locationHeader(_, title):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
|
||||
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)
|
||||
case let .changeLocation(_, text):
|
||||
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):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: title, sectionId: self.section)
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
@ -119,8 +119,6 @@ public func fetchCachedResourceRepresentation(account: Account, resource: MediaR
|
||||
}
|
||||
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 {
|
||||
return fetchYoutubeEmbedStoryboardResource(resource: resource)
|
||||
} else if let representation = representation as? CachedPreparedPatternWallpaperRepresentation {
|
||||
|
@ -1041,7 +1041,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
||||
if let location = (data.cachedData as? CachedChannelData)?.peerGeoLocation {
|
||||
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(
|
||||
id: ItemLocation,
|
||||
label: "",
|
||||
@ -1271,7 +1271,7 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
if isCreator, let location = cachedData.peerGeoLocation {
|
||||
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(
|
||||
id: ItemLocation,
|
||||
label: "",
|
||||
|
@ -408,9 +408,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
|> mapToSignal { result -> Signal<AddedAccountResult, NoError> in
|
||||
switch result {
|
||||
case let .authorized(account):
|
||||
setupAccount(account, fetchCachedResourceRepresentation: fetchCachedResourceRepresentation, transformOutgoingMessageMedia: transformOutgoingMessageMedia, preFetchedResourcePath: { resource in
|
||||
return nil
|
||||
})
|
||||
setupAccount(account, fetchCachedResourceRepresentation: fetchCachedResourceRepresentation, transformOutgoingMessageMedia: transformOutgoingMessageMedia)
|
||||
return account.postbox.transaction { transaction -> AddedAccountResult in
|
||||
let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration)?.get(LimitsConfiguration.self) ?? LimitsConfiguration.defaultValue
|
||||
let contentSettings = getContentSettings(transaction: transaction)
|
||||
|
@ -31,8 +31,6 @@ public let telegramAccountAuxiliaryMethods = AccountAuxiliaryMethods(fetchResour
|
||||
return fetchOpenInAppIconResource(resource: resource)
|
||||
} else if let resource = resource as? EmojiSpriteResource {
|
||||
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 {
|
||||
return Signal { subscriber in
|
||||
subscriber.putNext(.reset)
|
||||
|
Loading…
x
Reference in New Issue
Block a user