Skip to content

Commit 9b02db3

Browse files
authored
Hide album cover and apply bubble activity theme while loading music files (#95)
* fix(ChatUI): hide album cover and apply bubble activity theme while loading music files * fix(ChatUI): observe received music transfer status without changing playback * fix(ChatUI): preserve music playback during streaming and downloads * fix(ChatUI): avoid placeholder animations on initial music downloads
1 parent b18dcd8 commit 9b02db3

6 files changed

Lines changed: 479 additions & 68 deletions

File tree

‎packages/ChatUI/Package.swift‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ let deps: [(String, String)] = [
3333
("CurrencyFormat", "../CurrencyFormat"),
3434
("AlertsUI", "../AlertsUI"),
3535
("AudioPlayerCore", "../AudioPlayerCore"),
36+
("FetchManager", "../FetchManager"),
3637
("AvatarUI", "../AvatarUI"),
3738
("BoostUI", "../BoostUI"),
3839
("FilePanels", "../FilePanels"),
@@ -100,6 +101,6 @@ let package = Package(
100101
linkerSettings: [
101102
.linkedFramework("Speech"),
102103
]),
103-
.testTarget(name: "ChatUITests", dependencies: ["ChatUI", .product(name: "SceneEffects", package: "SceneEffects", condition: nil), .product(name: "TGUIKit", package: "TGUIKit", condition: nil), .product(name: "TelegramTheme", package: "TelegramTheme", condition: nil), .product(name: "GeneralRows", package: "GeneralRows", condition: nil), .product(name: "InAppSettings", package: "InAppSettings", condition: nil), .product(name: "ColorPalette", package: "ColorPalette", condition: nil), .product(name: "ThemeSettings", package: "ThemeSettings", condition: nil), .product(name: "rnoise", package: "rnoise", condition: nil), .product(name: "Localization", package: "Localization", condition: nil), .product(name: "TelegramCore", package: "TelegramCore", condition: nil)], path: "Tests/ChatUITests"),
104+
.testTarget(name: "ChatUITests", dependencies: ["ChatUI", .product(name: "AudioPlayerCore", package: "AudioPlayerCore", condition: nil), .product(name: "FetchManager", package: "FetchManager", condition: nil), .product(name: "SwiftSignalKit", package: "SSignalKit", condition: nil), .product(name: "SceneEffects", package: "SceneEffects", condition: nil), .product(name: "TGUIKit", package: "TGUIKit", condition: nil), .product(name: "TelegramTheme", package: "TelegramTheme", condition: nil), .product(name: "GeneralRows", package: "GeneralRows", condition: nil), .product(name: "InAppSettings", package: "InAppSettings", condition: nil), .product(name: "ColorPalette", package: "ColorPalette", condition: nil), .product(name: "ThemeSettings", package: "ThemeSettings", condition: nil), .product(name: "rnoise", package: "rnoise", condition: nil), .product(name: "Localization", package: "Localization", condition: nil), .product(name: "TelegramCore", package: "TelegramCore", condition: nil)], path: "Tests/ChatUITests"),
104105
]
105106
)

‎packages/ChatUI/Sources/ChatUI/ChatAudioContentView.swift‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -300,13 +300,17 @@ public class ChatAudioContentView: ChatMediaContentView, APDelegate {
300300
}
301301
self.setNeedsDisplay()
302302

303-
if !self.hasFetchStatusForCurrentMedia {
304-
self.fetchStatus = self.initialFetchStatus
305-
}
303+
initializeFetchStatus()
306304
checkState(animated: animated)
307305

308306
}
309307

308+
func initializeFetchStatus() {
309+
if !hasFetchStatusForCurrentMedia {
310+
fetchStatus = initialFetchStatus
311+
}
312+
}
313+
310314
public var leftInset:CGFloat {
311315
return 40.0 + 10.0;
312316
}

‎packages/ChatUI/Sources/ChatUI/ChatMusicContentView.swift‎

Lines changed: 78 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ import ColorPalette
1616
import MessageUtils
1717
import FoundationUtils
1818
import AudioPlayerCore
19+
import FetchManager
20+
21+
func chatMusicFetchStatus(fetchManager: FetchManager, message: Message?, file: TelegramMediaFile) -> Signal<MediaResourceStatus, NoError> {
22+
guard let message = message, !(file.resource is LocalFileReferenceMediaResource) else {
23+
return .single(.Local)
24+
}
25+
return fetchManager.fetchStatus(category: .file, location: .chat(message.id.peerId), locationKey: .messageId(message.id), resource: file.resource, reportExternalFetches: false)
26+
}
1927

2028
public class ChatMusicContentView: ChatAudioContentView {
2129
private let imageView: TransformImageView = TransformImageView(frame: NSMakeRect(0, 0, 40, 40))
@@ -24,29 +32,41 @@ public class ChatMusicContentView: ChatAudioContentView {
2432
public required init(frame frameRect: NSRect) {
2533
super.init(frame: frameRect)
2634
addSubview(imageView, positioned: .below, relativeTo: progressView)
27-
progressView.theme = RadialProgressTheme(backgroundColor: theme.colors.blackTransparent, foregroundColor: .white, icon: nil)
2835
}
29-
36+
3037
public override var fetchStatus: MediaResourceStatus? {
3138
didSet {
32-
if let fetchStatus = fetchStatus {
33-
switch fetchStatus {
34-
case let .Fetching(_, progress), let .Paused(progress):
35-
let sentGrouped = parent?.groupingKey != nil && (parent!.flags.contains(.Sending) || parent!.flags.contains(.Unsent))
36-
if progress == 1.0, sentGrouped {
37-
progressView.setState(.Success, animated: statusChangeIsAnimatable)
38-
} else {
39-
progressView.setState(.Fetching(progress: progress, force: false), animated: statusChangeIsAnimatable)
40-
}
41-
progressView.isHidden = false
42-
case .Remote:
43-
progressView.isHidden = true
44-
case .Local:
45-
progressView.isHidden = true
46-
}
47-
}
39+
updateFetchPresentation()
4840
}
4941
}
42+
43+
private func updateFetchPresentation() {
44+
let presentation: ChatMediaPresentation = parameters?.presentation ?? .Empty
45+
let showProgress: Bool
46+
switch fetchStatus {
47+
case .Fetching?, .Paused?:
48+
showProgress = playAnimationView == nil || (parent?.flags.contains(.Unsent) == true && parent?.flags.contains(.Failed) != true)
49+
default:
50+
showProgress = false
51+
}
52+
if showProgress {
53+
progressView.theme = RadialProgressTheme(backgroundColor: presentation.activityBackground, foregroundColor: presentation.activityForeground, icon: nil, blendMode: presentation.blendingMode)
54+
}
55+
progressView.isHidden = !showProgress
56+
imageView.isHidden = showProgress
57+
}
58+
59+
public override func executeInteraction(_ isControl: Bool) {
60+
if !isControl, userInteractionEnabled, parent?.flags.contains(.Unsent) != true || parent?.flags.contains(.Failed) == true {
61+
open()
62+
} else {
63+
super.executeInteraction(isControl)
64+
}
65+
}
66+
67+
public override func draggingAbility(_ event: NSEvent) -> Bool {
68+
return NSPointInRect(convert(event.locationInWindow, from: nil), bounds)
69+
}
5070

5171
public override func viewDidMoveToWindow() {
5272
if window != nil {
@@ -67,8 +87,14 @@ public class ChatMusicContentView: ChatAudioContentView {
6787
}
6888

6989
public override func update(with media: Media, size: NSSize, context: any AccountContextProtocol, parent: Message?, table: TableView?, parameters: ChatMediaLayoutParameters?, animated: Bool, positionFlags: LayoutPositionFlags? = nil, approximateSynchronousValue: Bool = false) {
90+
self.statusDisposable.set(nil)
7091
super.update(with: media, size: size, context: context, parent: parent, table: table, parameters: parameters, animated: animated, positionFlags: positionFlags)
71-
92+
93+
if let file = media as? TelegramMediaFile, parent?.flags.contains(.Unsent) != true || parent?.flags.contains(.Failed) == true {
94+
self.updateFetchStatus(chatMusicFetchStatus(fetchManager: context.fetchManager, message: parent, file: file))
95+
}
96+
updateFetchPresentation()
97+
7298
if let parameters = parameters as? ChatMediaMusicLayoutParameters {
7399
textView.update(parameters.nameLayout)
74100
durationView.update(parameters.durationLayout)
@@ -114,30 +140,44 @@ public class ChatMusicContentView: ChatAudioContentView {
114140
// imageView.layer?.cornerRadius = 20
115141
}
116142

143+
override func initializeFetchStatus() {
144+
if !hasFetchStatusForCurrentMedia {
145+
fetchStatus = nil
146+
}
147+
}
148+
149+
func updateFetchStatus(_ status: Signal<MediaResourceStatus, NoError>) {
150+
self.statusDisposable.set((status |> deliverOnMainQueue).start(next: { [weak self] status in
151+
self?.fetchStatus = status
152+
}))
153+
}
154+
117155
public override func checkState(animated: Bool) {
118-
if let parent = parent, let controller = ChatMediaUIHooks.shared.getAudioPlayer(context), let song = controller.currentSong {
119-
if song.entry.isEqual(to: parent) {
120-
if playAnimationView == nil {
121-
playAnimationView = PeerMediaPlayerAnimationView()
122-
playAnimationView?.layer?.cornerRadius = 20
123-
imageView.addSubview(playAnimationView!)
124-
}
125-
if case .playing = song.state {
126-
playAnimationView?.isPlaying = true
127-
} else if case .stoped = song.state {
128-
playAnimationView?.removeFromSuperview()
129-
playAnimationView = nil
130-
} else {
131-
playAnimationView?.isPlaying = false
132-
}
133-
} else {
134-
playAnimationView?.removeFromSuperview()
135-
playAnimationView = nil
136-
}
156+
if let parent = parent, let controller = ChatMediaUIHooks.shared.getAudioPlayer(context), let song = controller.currentSong, song.entry.isEqual(to: parent) {
157+
updatePlaybackState(song.state)
137158
} else {
159+
updatePlaybackState(nil)
160+
}
161+
}
162+
163+
func updatePlaybackState(_ state: APState?) {
164+
switch state {
165+
case .none, .stoped?:
138166
playAnimationView?.removeFromSuperview()
139167
playAnimationView = nil
168+
default:
169+
if playAnimationView == nil {
170+
playAnimationView = PeerMediaPlayerAnimationView()
171+
playAnimationView?.layer?.cornerRadius = 20
172+
imageView.addSubview(playAnimationView!)
173+
}
174+
if case .playing? = state {
175+
playAnimationView?.isPlaying = true
176+
} else {
177+
playAnimationView?.isPlaying = false
178+
}
140179
}
180+
updateFetchPresentation()
141181
}
142182

143183
public override func preloadStreamblePart() {

0 commit comments

Comments
 (0)