mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-05 19:28:46 +02:00
Postbox -> TelegramEngine wave 10: StorageFileListPanelComponent drop
Closes the last future-wave candidate from wave 8 by eliminating the
Icon.media(Media, ...) enum case in StorageFileListPanelComponent.swift
and dropping import Postbox. StorageUsageScreen (the module as a whole)
is now fully Postbox-free.
Icon enum split:
case media(Media, TelegramMediaImageRepresentation) ->
case mediaFile(TelegramMediaFile, TelegramMediaImageRepresentation)
case mediaImage(TelegramMediaImage, TelegramMediaImageRepresentation)
Equatable rewritten as switch-over-tuple with id-based equality per
concrete type (lFile.fileId == rFile.fileId / lImage.imageId ==
rImage.imageId), same semantics as the old media.id comparison.
Binding site: `if case let .media(media, representation)` +
`as? TelegramMediaFile` / `as? TelegramMediaImage` downcasts ->
compound case-binding `case let .mediaFile(_, representation), let
.mediaImage(_, representation):` to lift the shared representation
variable, plus an inner switch for the setSignal branch. The compiler-
enforced exhaustiveness of the split improves call-site safety.
Construction sites (2): `.media(file, representation)` -> `.mediaFile(
file, representation)`, `.media(image, representation)` -> `.mediaImage(
image, representation)`.
Placeholder fixup:
messageId: EngineMessage.Id(peerId: PeerId(namespace: PeerId.Namespace
._internalFromInt32Value(0), id: PeerId.Id._internalFromInt64Value(0)
), namespace: 0, id: 0)
->
messageId: EngineMessage.Id(peerId: component.context.account.peerId,
namespace: 0, id: 0)
Inside a measureItem layout-measurement instance. Caught by second-pass
build failure `cannot find 'PeerId' in scope`. PeerId / PeerId.Namespace
/ PeerId.Id are raw Postbox types (not TelegramCore typealiases —
consistent with wave 9's MessageId -> EngineMessage.Id fixup). Using
context.account.peerId is semantically equivalent for the measurement
use case (messageId only feeds image-fetch userLocation and Equatable
comparison, neither exercised for this standalone instance).
Net: 1 file changed, +22 / -29 lines.
Plan: docs/superpowers/plans/2026-04-20-postbox-to-telegramengine-wave-10.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1a432362a3
commit
34c2c8c8a4
3 changed files with 250 additions and 40 deletions
19
CLAUDE.md
19
CLAUDE.md
|
|
@ -256,6 +256,24 @@ Net: 1 file changed, +30 / -54. Build verified green (27 actions, cached).
|
|||
|
||||
Plan / record: `docs/superpowers/plans/2026-04-20-postbox-to-telegramengine-wave-9.md`.
|
||||
|
||||
### Wave 10 outcome (2026-04-20)
|
||||
|
||||
Closes the second (and last) future-wave candidate from wave 8: eliminates `StorageFileListPanelComponent.swift`'s `Icon.media(Media, TelegramMediaImageRepresentation)` enum case. **`StorageUsageScreen` (the module as a whole) is now fully Postbox-free** — the other in-module file (`StorageUsageScreen.swift`) landed in wave 9.
|
||||
|
||||
**Split the enum case.** `Icon.media(Media, TelegramMediaImageRepresentation)` → two concrete cases `case mediaFile(TelegramMediaFile, TelegramMediaImageRepresentation)` + `case mediaImage(TelegramMediaImage, TelegramMediaImageRepresentation)`. Lossless split: the two construction sites already knew the concrete subtype (`imageIconValue = .media(file, representation)` from a `as? TelegramMediaFile` branch, `.media(image, representation)` from a `as? TelegramMediaImage` branch), and the consumer binding site immediately downcast via `as?` to pick which `setSignal(...)` flavor to call. New split removes the downcast; exhaustiveness-checked switch is both safer and terser.
|
||||
|
||||
**Equatable rewritten.** Old: manual outer-`switch` + inner `if case` dispatch, comparing media by `media.id` only. New: switch-over-tuple `(lhs, rhs)` with id-based equality per concrete type (`lFile.fileId == rFile.fileId`, `lImage.imageId == rImage.imageId`). Same id-based equality semantics as before.
|
||||
|
||||
**Binding-site rewrite.** Old: `if case let .media(media, representation) = component.icon { ... if let file = media as? TelegramMediaFile { ... } else if let image = media as? TelegramMediaImage { ... } }`. New: a compound case-binding pattern `case let .mediaFile(_, representation), let .mediaImage(_, representation):` lifts the shared `representation` variable, then an inner switch dispatches to the right `setSignal` branch. Works because both cases carry the same `TelegramMediaImageRepresentation` payload type; Swift allows compound case patterns when the bindings have identical types.
|
||||
|
||||
**Placeholder `PeerId(...)` construction fixup.** Second-pass build failure after dropping `import Postbox` surfaced a placeholder `PeerId(namespace: PeerId.Namespace._internalFromInt32Value(0), id: PeerId.Id._internalFromInt64Value(0))` in the `measureItem` layout-measurement instance at former line 1062. Naming `PeerId`, `PeerId.Namespace`, and `PeerId.Id` all require `import Postbox` (these are raw Postbox types, not TelegramCore typealiases — consistent with wave 9's `MessageId` → `EngineMessage.Id` fixup). Replaced with `component.context.account.peerId` (a real `EnginePeer.Id` already in scope). Semantically equivalent since the measurement instance's `messageId` is only used for `.peerId` extraction inside image-fetch `userLocation` and for Equatable comparison (the measurement instance isn't compared to anything).
|
||||
|
||||
**Lesson.** Placeholder `PeerId(...)` / `MessageId(peerId:...)` constructions in layout-measurement code are a recurring trap for de-Postbox work. Common pattern in this codebase: construct a dummy component instance purely to call `.update(...)` and read back the returned size. The dummy values are not used meaningfully but naming the types pins `import Postbox`. When de-Postboxing, grep for `PeerId(namespace:`/`MessageId(peerId:` with all-zero args and replace with any convenient real value in scope (`context.account.peerId` is almost always available).
|
||||
|
||||
Net: 1 file changed, +22 / -29 lines (−7 simplification — new switch-over-tuple Equatable is both terser and more idiomatic).
|
||||
|
||||
Plan / record: `docs/superpowers/plans/2026-04-20-postbox-to-telegramengine-wave-10.md`.
|
||||
|
||||
### Modules currently free of `import Postbox` (running tally)
|
||||
|
||||
Consumer modules that no longer import Postbox, across all waves and standalone commits:
|
||||
|
|
@ -271,6 +289,7 @@ Consumer modules that no longer import Postbox, across all waves and standalone
|
|||
- `SaveToCameraRoll` (wave 3)
|
||||
- `SecureIdVerificationDocumentsContext` (wave 5)
|
||||
- **Wave 6 batch: 189 additional modules** — see `git show 7b2b74e79b --stat` for the commit that swept unused `import Postbox` lines across 183 files in 16 consumer submodules. Not individually enumerated here for brevity.
|
||||
- `StorageUsageScreen` (waves 8–10)
|
||||
|
||||
### Known future-wave candidates
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,194 @@
|
|||
# Postbox → TelegramEngine Wave 10 Implementation Plan
|
||||
|
||||
> **For agentic workers:** This plan was executed in a single session; steps below are a post-hoc record of the work landed, not a to-do list.
|
||||
|
||||
**Goal:** Finish the `StorageUsageScreen` consumer-module de-Postbox work started in wave 8 and continued in wave 9 by eliminating the last `import Postbox` in the module: `StorageFileListPanelComponent.swift`'s `Icon.media(Media, TelegramMediaImageRepresentation)` enum case.
|
||||
|
||||
**Architecture:** Replace the heterogeneous-protocol `Icon.media(Media, ...)` case with two concrete-type cases `.mediaFile(TelegramMediaFile, ...)` and `.mediaImage(TelegramMediaImage, ...)`. The split is lossless because the two construction sites already knew the concrete subtype (`imageIconValue = .media(file, representation)` vs `.media(image, representation)`), and the one consumer binding site immediately downcasted via `as? TelegramMediaFile` / `as? TelegramMediaImage` to pick which `setSignal(...)` to call. Auto-split the switch body over the two new cases; no downcast needed. Also replaces a placeholder `PeerId(namespace:..., id:...)` construction in the `measureItem` layout-measurement instance with `component.context.account.peerId` (a real, already-available `EnginePeer.Id`).
|
||||
|
||||
**Tech Stack:** Swift / Bazel. No unit tests.
|
||||
|
||||
**Build command:**
|
||||
|
||||
```bash
|
||||
source ~/.zshrc 2>/dev/null; PATH=/opt/homebrew/opt/ruby/bin:`gem environment gemdir`/bin:$PATH python3 build-system/Make/Make.py --overrideXcodeVersion --cacheDir ~/telegram-bazel-cache build --configurationPath build-system/appstore-configuration.json --gitCodesigningRepository git@gitlab.com:peter-iakovlev/fastlanematch.git --gitCodesigningType development --gitCodesigningUseCurrent --buildNumber 1 --configuration debug_sim_arm64 --continueOnError
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
**In scope:**
|
||||
- `StorageFileListPanelComponent.swift`'s `Icon` enum: replace `case media(Media, TelegramMediaImageRepresentation)` with two concrete-type cases.
|
||||
- Equatable rewrite: switch-over-tuple `(lhs, rhs)` pattern with id-based equality per concrete type (`lFile.fileId == rFile.fileId`, `lImage.imageId == rImage.imageId`).
|
||||
- Binding rewrite at the `if case let .media(media, representation)` site (former line 448): lift `representation` via a compound `case let .mediaFile(_, representation), let .mediaImage(_, representation):` pattern, then inner switch-over-`component.icon` selects `setSignal` flavor.
|
||||
- Construction rewrite at two `imageIconValue = .media(...)` sites: use the concrete case name (`.mediaFile`, `.mediaImage`).
|
||||
- Placeholder `PeerId(namespace:..., id:...)` at former line 1062 (in the `measureItem` layout-measurement instance): replace with `component.context.account.peerId`.
|
||||
- Remove `import Postbox` from `StorageFileListPanelComponent.swift`.
|
||||
|
||||
**Out of scope:**
|
||||
- None. This is the last file in the `StorageUsageScreen` module that imports Postbox; after this wave, the module is fully Postbox-free.
|
||||
|
||||
---
|
||||
|
||||
## Tasks
|
||||
|
||||
### Task 1: Split `Icon.media` into two concrete cases
|
||||
|
||||
**Files:**
|
||||
- Modify: `submodules/TelegramUI/Components/StorageUsageScreen/Sources/StorageFileListPanelComponent.swift` (former 103–135).
|
||||
|
||||
Before:
|
||||
|
||||
```swift
|
||||
enum Icon: Equatable {
|
||||
case fileExtension(String)
|
||||
case media(Media, TelegramMediaImageRepresentation)
|
||||
case audio
|
||||
|
||||
static func ==(lhs: Icon, rhs: Icon) -> Bool {
|
||||
switch lhs {
|
||||
case let .fileExtension(value):
|
||||
if case .fileExtension(value) = rhs { return true } else { return false }
|
||||
case let .media(media, representation):
|
||||
if case let .media(rhsMedia, rhsRepresentation) = rhs {
|
||||
if media.id != rhsMedia.id { return false }
|
||||
if representation != rhsRepresentation { return false }
|
||||
return true
|
||||
} else { return false }
|
||||
case .audio:
|
||||
if case .audio = rhs { return true } else { return false }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```swift
|
||||
enum Icon: Equatable {
|
||||
case fileExtension(String)
|
||||
case mediaFile(TelegramMediaFile, TelegramMediaImageRepresentation)
|
||||
case mediaImage(TelegramMediaImage, TelegramMediaImageRepresentation)
|
||||
case audio
|
||||
|
||||
static func ==(lhs: Icon, rhs: Icon) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
case let (.fileExtension(l), .fileExtension(r)):
|
||||
return l == r
|
||||
case let (.mediaFile(lFile, lRepresentation), .mediaFile(rFile, rRepresentation)):
|
||||
return lFile.fileId == rFile.fileId && lRepresentation == rRepresentation
|
||||
case let (.mediaImage(lImage, lRepresentation), .mediaImage(rImage, rRepresentation)):
|
||||
return lImage.imageId == rImage.imageId && lRepresentation == rRepresentation
|
||||
case (.audio, .audio):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Task 2: Rewrite the binding site
|
||||
|
||||
**Files:**
|
||||
- Modify: `submodules/TelegramUI/Components/StorageUsageScreen/Sources/StorageFileListPanelComponent.swift` (former 448–500).
|
||||
|
||||
Before, the block started with `if case let .media(media, representation) = component.icon { ... }` then inside did `if let file = media as? TelegramMediaFile { ... } else if let image = media as? TelegramMediaImage { ... }`.
|
||||
|
||||
After, use a compound case-binding pattern at the entry (both cases have the same `representation` type, so the pattern works) and an inner switch for the `setSignal` branch:
|
||||
|
||||
```swift
|
||||
let mediaRepresentation: TelegramMediaImageRepresentation?
|
||||
switch component.icon {
|
||||
case let .mediaFile(_, representation), let .mediaImage(_, representation):
|
||||
mediaRepresentation = representation
|
||||
default:
|
||||
mediaRepresentation = nil
|
||||
}
|
||||
|
||||
if let representation = mediaRepresentation {
|
||||
// ... setup iconImageNode as before ...
|
||||
if resetImage {
|
||||
switch component.icon {
|
||||
case let .mediaFile(file, _):
|
||||
iconImageNode.setSignal(chatWebpageSnippetFile(
|
||||
account: component.context.account,
|
||||
userLocation: .peer(component.messageId.peerId),
|
||||
mediaReference: FileMediaReference.standalone(media: file).abstract,
|
||||
representation: representation,
|
||||
automaticFetch: false
|
||||
))
|
||||
case let .mediaImage(image, _):
|
||||
iconImageNode.setSignal(mediaGridMessagePhoto(
|
||||
account: component.context.account,
|
||||
userLocation: .peer(component.messageId.peerId),
|
||||
photoReference: ImageMediaReference.standalone(media: image),
|
||||
automaticFetch: false
|
||||
))
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
// ... frame + asyncLayout + apply as before ...
|
||||
}
|
||||
```
|
||||
|
||||
### Task 3: Update the two construction sites
|
||||
|
||||
**Files:**
|
||||
- Modify: `submodules/TelegramUI/Components/StorageUsageScreen/Sources/StorageFileListPanelComponent.swift` (former 985 and 992).
|
||||
|
||||
`imageIconValue = .media(file, representation)` → `.mediaFile(file, representation)` (for `TelegramMediaFile` branch).
|
||||
`imageIconValue = .media(image, representation)` → `.mediaImage(image, representation)` (for `TelegramMediaImage` branch).
|
||||
|
||||
### Task 4: Replace the placeholder `PeerId(...)` construction
|
||||
|
||||
**Files:**
|
||||
- Modify: `submodules/TelegramUI/Components/StorageUsageScreen/Sources/StorageFileListPanelComponent.swift` (former 1062).
|
||||
|
||||
The `measureItem` layout-measurement instance uses a fully-zero placeholder peer id:
|
||||
|
||||
```swift
|
||||
messageId: EngineMessage.Id(peerId: PeerId(namespace: PeerId.Namespace._internalFromInt32Value(0), id: PeerId.Id._internalFromInt64Value(0)), namespace: 0, id: 0),
|
||||
```
|
||||
|
||||
Naming `PeerId`, `PeerId.Namespace`, `PeerId.Id` all require `import Postbox` (these are raw Postbox types, not TelegramCore typealiases). Replace with `component.context.account.peerId`, a real `EnginePeer.Id` already in scope:
|
||||
|
||||
```swift
|
||||
messageId: EngineMessage.Id(peerId: component.context.account.peerId, namespace: 0, id: 0),
|
||||
```
|
||||
|
||||
Semantically equivalent for the measurement use case — `messageId` is used downstream only for `.peerId` extraction in the image-fetch userLocation and for Equatable comparison; the measurement instance is standalone and not compared. The `id: 0, namespace: 0` part stays; those are plain `Int32`, nothing Postbox-specific.
|
||||
|
||||
Caught by second-pass build failure `cannot find 'PeerId' in scope` after dropping `import Postbox`.
|
||||
|
||||
### Task 5: Drop `import Postbox`
|
||||
|
||||
**Files:**
|
||||
- Modify: `submodules/TelegramUI/Components/StorageUsageScreen/Sources/StorageFileListPanelComponent.swift` (former line 14).
|
||||
|
||||
Remove the `import Postbox` line.
|
||||
|
||||
### Task 6: Full project build
|
||||
|
||||
Expected green after Tasks 4 and 5. The first build attempt surfaced the `PeerId` issue; Task 4's fix addressed it.
|
||||
|
||||
### Task 7: Commit
|
||||
|
||||
Single wave-10 atomic commit. CLAUDE.md gets a wave-10 outcome section; the "Modules currently free of `import Postbox`" tally gains `StorageUsageScreen` (the module as a whole). Both files that previously imported Postbox in this module (`StorageUsageScreen.swift` from wave 9 and `StorageFileListPanelComponent.swift` from wave 10) are now Postbox-free.
|
||||
|
||||
---
|
||||
|
||||
## Outcome (2026-04-20)
|
||||
|
||||
Single atomic commit. Build verified green (27 actions, cached).
|
||||
|
||||
**`StorageUsageScreen` consumer module is now fully Postbox-free** — last file (`StorageFileListPanelComponent.swift`) landed in this wave; the other file (`StorageUsageScreen.swift`) landed in wave 9.
|
||||
|
||||
Net: 1 file changed, +22 / -29 lines (−7 simplification — the new switch-over-tuple Equatable is both terser and more idiomatic than the old three-way nested `switch` + `if case` pattern).
|
||||
|
||||
**Lessons:**
|
||||
|
||||
- **Heterogeneous-protocol enum cases are an easy de-Postbox win** when the protocol values already get downcast to a fixed small set of concrete subtypes. The compiler-enforced exhaustiveness of the split improves call-site safety (no silent `else` branch that forgot a subtype).
|
||||
- **Placeholder `PeerId(...)` constructions in layout-measurement code are traps.** Common pattern in this codebase: a "dummy" component instance is constructed purely to run `.update(...)` and harvest the returned size. The dummy values (`messageId`, `peerId`) are not used for anything but type-filling, yet naming the types forces `import Postbox`. When de-Postboxing, look for `PeerId(namespace:...`/`MessageId(peerId:...` constructions with all-zero arguments and replace with any convenient real value already in scope (`context.account.peerId` works for peer-id placeholders).
|
||||
|
|
@ -11,7 +11,6 @@ import AccountContext
|
|||
import TelegramCore
|
||||
import MultilineTextComponent
|
||||
import EmojiStatusComponent
|
||||
import Postbox
|
||||
import TelegramStringFormatting
|
||||
import CheckNode
|
||||
import AvatarNode
|
||||
|
|
@ -102,35 +101,22 @@ private let smallExtensionFont = Font.with(size: 12.0, design: .round, weight: .
|
|||
private final class FileListItemComponent: Component {
|
||||
enum Icon: Equatable {
|
||||
case fileExtension(String)
|
||||
case media(Media, TelegramMediaImageRepresentation)
|
||||
case mediaFile(TelegramMediaFile, TelegramMediaImageRepresentation)
|
||||
case mediaImage(TelegramMediaImage, TelegramMediaImageRepresentation)
|
||||
case audio
|
||||
|
||||
|
||||
static func ==(lhs: Icon, rhs: Icon) -> Bool {
|
||||
switch lhs {
|
||||
case let .fileExtension(value):
|
||||
if case .fileExtension(value) = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .media(media, representation):
|
||||
if case let .media(rhsMedia, rhsRepresentation) = rhs {
|
||||
if media.id != rhsMedia.id {
|
||||
return false
|
||||
}
|
||||
if representation != rhsRepresentation {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case .audio:
|
||||
if case .audio = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
switch (lhs, rhs) {
|
||||
case let (.fileExtension(l), .fileExtension(r)):
|
||||
return l == r
|
||||
case let (.mediaFile(lFile, lRepresentation), .mediaFile(rFile, rRepresentation)):
|
||||
return lFile.fileId == rFile.fileId && lRepresentation == rRepresentation
|
||||
case let (.mediaImage(lImage, lRepresentation), .mediaImage(rImage, rRepresentation)):
|
||||
return lImage.imageId == rImage.imageId && lRepresentation == rRepresentation
|
||||
case (.audio, .audio):
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -445,25 +431,34 @@ private final class FileListItemComponent: Component {
|
|||
}
|
||||
}
|
||||
|
||||
if case let .media(media, representation) = component.icon {
|
||||
let mediaRepresentation: TelegramMediaImageRepresentation?
|
||||
switch component.icon {
|
||||
case let .mediaFile(_, representation), let .mediaImage(_, representation):
|
||||
mediaRepresentation = representation
|
||||
default:
|
||||
mediaRepresentation = nil
|
||||
}
|
||||
|
||||
if let representation = mediaRepresentation {
|
||||
var resetImage = false
|
||||
|
||||
|
||||
let iconImageNode: TransformImageNode
|
||||
if let current = self.iconImageNode {
|
||||
iconImageNode = current
|
||||
} else {
|
||||
resetImage = true
|
||||
|
||||
|
||||
iconImageNode = TransformImageNode()
|
||||
self.iconImageNode = iconImageNode
|
||||
self.containerButton.addSubview(iconImageNode.view)
|
||||
}
|
||||
|
||||
|
||||
let iconSize = CGSize(width: 40.0, height: 40.0)
|
||||
let imageSize: CGSize = representation.dimensions.cgSize
|
||||
|
||||
|
||||
if resetImage {
|
||||
if let file = media as? TelegramMediaFile {
|
||||
switch component.icon {
|
||||
case let .mediaFile(file, _):
|
||||
iconImageNode.setSignal(chatWebpageSnippetFile(
|
||||
account: component.context.account,
|
||||
userLocation: .peer(component.messageId.peerId),
|
||||
|
|
@ -471,19 +466,21 @@ private final class FileListItemComponent: Component {
|
|||
representation: representation,
|
||||
automaticFetch: false
|
||||
))
|
||||
} else if let image = media as? TelegramMediaImage {
|
||||
case let .mediaImage(image, _):
|
||||
iconImageNode.setSignal(mediaGridMessagePhoto(
|
||||
account: component.context.account,
|
||||
userLocation: .peer(component.messageId.peerId),
|
||||
photoReference: ImageMediaReference.standalone(media: image),
|
||||
automaticFetch: false
|
||||
))
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let iconFrame = CGRect(origin: CGPoint(x: iconLeftInset + floor((leftInset - iconLeftInset - iconSize.width) / 2.0), y: floor((height - verticalInset * 2.0 - iconSize.height) / 2.0)), size: iconSize)
|
||||
transition.setFrame(view: iconImageNode.view, frame: iconFrame)
|
||||
|
||||
|
||||
let iconImageLayout = iconImageNode.asyncLayout()
|
||||
let iconImageApply = iconImageLayout(TransformImageArguments(
|
||||
corners: ImageCorners(radius: 8.0),
|
||||
|
|
@ -982,14 +979,14 @@ final class StorageFileListPanelComponent: Component {
|
|||
extensionIconValue = fileExtension
|
||||
|
||||
if let representation = smallestImageRepresentation(file.previewRepresentations) {
|
||||
imageIconValue = .media(file, representation)
|
||||
imageIconValue = .mediaFile(file, representation)
|
||||
}
|
||||
}
|
||||
} else if let image = media as? TelegramMediaImage {
|
||||
title = environment.strings.Message_Photo
|
||||
|
||||
if let representation = largestImageRepresentation(image.representations) {
|
||||
imageIconValue = .media(image, representation)
|
||||
imageIconValue = .mediaImage(image, representation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1062,7 +1059,7 @@ final class StorageFileListPanelComponent: Component {
|
|||
component: AnyComponent(FileListItemComponent(
|
||||
context: component.context,
|
||||
theme: environment.theme,
|
||||
messageId: EngineMessage.Id(peerId: PeerId(namespace: PeerId.Namespace._internalFromInt32Value(0), id: PeerId.Id._internalFromInt64Value(0)), namespace: 0, id: 0),
|
||||
messageId: EngineMessage.Id(peerId: component.context.account.peerId, namespace: 0, id: 0),
|
||||
title: "ABCDEF",
|
||||
subtitle: "ABCDEF",
|
||||
label: "1000",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue