Theme file reference invalidation

This commit is contained in:
Ilya Laktyushin 2019-12-25 13:16:21 +03:00
parent 2f1e573cbf
commit f13301f7d0
6 changed files with 100 additions and 24 deletions

View File

@ -90,7 +90,7 @@ public final class ThemePreviewController: ViewController {
self.theme.get()
|> mapToSignal { theme in
if let file = theme?.file {
return telegramThemeData(account: context.account, accountManager: context.sharedContext.accountManager, resource: file.resource)
return telegramThemeData(account: context.account, accountManager: context.sharedContext.accountManager, reference: .standalone(resource: file.resource))
|> mapToSignal { data -> Signal<PresentationTheme, NoError> in
guard let data = data, let presentationTheme = makePresentationTheme(data: data) else {
return .complete()

View File

@ -142,6 +142,39 @@ public enum WebpageReferenceContent: PostboxCoding, Hashable, Equatable {
}
}
public enum ThemeReference: PostboxCoding, Hashable, Equatable {
case slug(String)
public init(decoder: PostboxDecoder) {
switch decoder.decodeInt32ForKey("r", orElse: 0) {
case 0:
self = .slug(decoder.decodeStringForKey("s", orElse: ""))
default:
self = .slug("")
assertionFailure()
}
}
public func encode(_ encoder: PostboxEncoder) {
switch self {
case let .slug(slug):
encoder.encodeInt32(0, forKey: "r")
encoder.encodeString(slug, forKey: "s")
}
}
public static func ==(lhs: ThemeReference, rhs: ThemeReference) -> Bool {
switch lhs {
case let .slug(slug):
if case .slug(slug) = rhs {
return true
} else {
return false
}
}
}
}
public enum AnyMediaReference: Equatable {
case standalone(media: Media)
case message(message: MessageReference, media: Media)
@ -430,6 +463,7 @@ public enum MediaResourceReference: Equatable {
case messageAuthorAvatar(message: MessageReference, resource: MediaResource)
case wallpaper(resource: MediaResource)
case stickerPackThumbnail(stickerPack: StickerPackReference, resource: MediaResource)
case theme(theme: ThemeReference, resource: MediaResource)
public var resource: MediaResource {
switch self {
@ -445,6 +479,8 @@ public enum MediaResourceReference: Equatable {
return resource
case let .stickerPackThumbnail(_, resource):
return resource
case let .theme(_, resource):
return resource
}
}
@ -486,6 +522,12 @@ public enum MediaResourceReference: Equatable {
} else {
return false
}
case let .theme(lhsTheme, lhsResource):
if case let .theme(rhsTheme, rhsResource) = rhs, lhsTheme == rhsTheme, lhsResource.isEqual(to: rhsResource) {
return true
} else {
return false
}
}
}
}

View File

@ -141,6 +141,7 @@ private enum MediaReferenceRevalidationKey: Hashable {
case savedGifs
case peer(peer: PeerReference)
case wallpapers
case themes
}
private final class MediaReferenceRevalidationItemContext {
@ -402,6 +403,26 @@ final class MediaReferenceRevalidationContext {
}
}
}
func themes(postbox: Postbox, network: Network, background: Bool) -> Signal<[TelegramTheme], RevalidateMediaReferenceError> {
return self.genericItem(key: .themes, background: background, request: { next, error in
return (telegramThemes(postbox: postbox, network: network, accountManager: nil, forceUpdate: true)
|> take(1)
|> mapError { _ -> RevalidateMediaReferenceError in
return .generic
}).start(next: { value in
next(value)
}, error: { _ in
error(.generic)
})
}) |> mapToSignal { next -> Signal<[TelegramTheme], RevalidateMediaReferenceError> in
if let next = next as? [TelegramTheme] {
return .single(next)
} else {
return .fail(.generic)
}
}
}
}
struct RevalidatedMediaResource {
@ -586,6 +607,16 @@ func revalidateMediaResourceReference(postbox: Postbox, network: Network, revali
}
return .fail(.generic)
}
case let .theme(themeReference, resource):
return revalidationContext.themes(postbox: postbox, network: network, background: info.preferBackgroundReferenceRevalidation)
|> mapToSignal { themes -> Signal<RevalidatedMediaResource, RevalidateMediaReferenceError> in
for theme in themes {
if let file = theme.file, file.resource.id.isEqual(to: resource.id) {
return .single(RevalidatedMediaResource(updatedResource: file.resource, updatedReference: nil))
}
}
return .fail(.generic)
}
case .standalone:
return .fail(.generic)
}

View File

@ -13,7 +13,7 @@ let telegramThemeFormat = "ios"
let telegramThemeFileExtension = "tgios-theme"
#endif
public func telegramThemes(postbox: Postbox, network: Network, accountManager: AccountManager, forceUpdate: Bool = false) -> Signal<[TelegramTheme], NoError> {
public func telegramThemes(postbox: Postbox, network: Network, accountManager: AccountManager?, forceUpdate: Bool = false) -> Signal<[TelegramTheme], NoError> {
let fetch: ([TelegramTheme]?, Int32?) -> Signal<[TelegramTheme], NoError> = { current, hash in
network.request(Api.functions.account.getThemes(format: telegramThemeFormat, hash: hash ?? 0))
|> retryRequest
@ -31,18 +31,20 @@ public func telegramThemes(postbox: Postbox, network: Network, accountManager: A
}
}
|> mapToSignal { items, hash -> Signal<[TelegramTheme], NoError> in
let _ = accountManager.transaction { transaction in
transaction.updateSharedData(SharedDataKeys.themeSettings, { current in
var updated = current as? ThemeSettings ?? ThemeSettings(currentTheme: nil)
for theme in items {
if theme.id == updated.currentTheme?.id {
updated = ThemeSettings(currentTheme: theme)
break
if let accountManager = accountManager {
let _ = accountManager.transaction { transaction in
transaction.updateSharedData(SharedDataKeys.themeSettings, { current in
var updated = current as? ThemeSettings ?? ThemeSettings(currentTheme: nil)
for theme in items {
if theme.id == updated.currentTheme?.id {
updated = ThemeSettings(currentTheme: theme)
break
}
}
}
return updated
})
}.start()
return updated
})
}.start()
}
return postbox.transaction { transaction -> [TelegramTheme] in
var entries: [OrderedItemListEntry] = []

View File

@ -84,7 +84,7 @@ final class ThemeUpdateManagerImpl: ThemeUpdateManager {
guard let file = theme.file else {
return .complete()
}
return telegramThemeData(account: account, accountManager: accountManager, resource: file.resource)
return telegramThemeData(account: account, accountManager: accountManager, reference: .standalone(resource: file.resource))
|> mapToSignal { data -> Signal<(PresentationThemeReference, PresentationTheme?), NoError> in
guard let data = data, let presentationTheme = makePresentationTheme(data: data) else {
return .complete()

View File

@ -699,8 +699,8 @@ public func photoWallpaper(postbox: Postbox, photoLibraryResource: PhotoLibraryM
}
}
public func telegramThemeData(account: Account, accountManager: AccountManager, resource: MediaResource, synchronousLoad: Bool = false) -> Signal<Data?, NoError> {
let maybeFetched = accountManager.mediaBox.resourceData(resource, option: .complete(waitUntilFetchStatus: false), attemptSynchronously: synchronousLoad)
public func telegramThemeData(account: Account, accountManager: AccountManager, reference: MediaResourceReference, synchronousLoad: Bool = false) -> Signal<Data?, NoError> {
let maybeFetched = accountManager.mediaBox.resourceData(reference.resource, option: .complete(waitUntilFetchStatus: false), attemptSynchronously: synchronousLoad)
return maybeFetched
|> take(1)
|> mapToSignal { maybeData in
@ -708,15 +708,15 @@ public func telegramThemeData(account: Account, accountManager: AccountManager,
let loadedData: Data? = try? Data(contentsOf: URL(fileURLWithPath: maybeData.path), options: [])
return .single(loadedData)
} else {
let data = account.postbox.mediaBox.resourceData(resource, option: .complete(waitUntilFetchStatus: false), attemptSynchronously: false)
let data = account.postbox.mediaBox.resourceData(reference.resource, option: .complete(waitUntilFetchStatus: false), attemptSynchronously: false)
return Signal { subscriber in
let fetch = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: .standalone(resource: resource)).start()
let fetch = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: reference).start()
let disposable = (data
|> map { data -> Data? in
return data.complete ? try? Data(contentsOf: URL(fileURLWithPath: data.path)) : nil
}).start(next: { next in
if let data = next {
accountManager.mediaBox.storeResourceData(resource.id, data: data)
accountManager.mediaBox.storeResourceData(reference.resource.id, data: data)
}
subscriber.putNext(next)
}, error: { error in
@ -1153,13 +1153,14 @@ public func themeIconImage(account: Account, accountManager: AccountManager, the
colorsSignal = .single(((topBackgroundColor, bottomBackgroundColor), (incomingColor, incomingColor), outgoingColor, nil, rotation))
} else {
var resource: MediaResource?
var reference: MediaResourceReference?
if case let .local(theme) = theme {
resource = theme.resource
} else if case let .cloud(theme) = theme {
resource = theme.theme.file?.resource
reference = .standalone(resource: theme.resource)
} else if case let .cloud(theme) = theme, let resource = theme.theme.file?.resource {
reference = .theme(theme: .slug(theme.theme.slug), resource: resource)
}
if let resource = resource {
colorsSignal = telegramThemeData(account: account, accountManager: accountManager, resource: resource, synchronousLoad: false)
if let reference = reference {
colorsSignal = telegramThemeData(account: account, accountManager: accountManager, reference: reference, synchronousLoad: false)
|> mapToSignal { data -> Signal<((UIColor, UIColor?), (UIColor, UIColor), (UIColor, UIColor), UIImage?, Int32?), NoError> in
if let data = data, let theme = makePresentationTheme(data: data) {
var wallpaperSignal: Signal<((UIColor, UIColor?), (UIColor, UIColor), (UIColor, UIColor), UIImage?, Int32?), NoError> = .complete()