SRGSSR / pillarbox-apple

A next-generation reactive media playback ecosystem for Apple platforms.
https://testflight.apple.com/join/TS6ngLqf
MIT License
60 stars 9 forks source link

Improve playlist user interface integration #986

Closed defagos closed 2 months ago

defagos commented 3 months ago

Description

This PR improves integration of playlists at the user interface level. This requires:

Design considerations

Implementing better playlist support at the UI level was more difficult than initially expected. Several design options were investigated. The choices made in this PR are motivated below.

Metadata required by a playlist UI

A playlist UI component must be able to display all items stored in a player at any time. But a PlayerItem currently has no associated metadata at creation time: Metadata is only available once the item has been loaded by the player, a process that occurs when the item is about to be played.

This means that at least some metadata must be made immediately available at the time an item is inserted into a player. Otherwise we cannot meaningfully represent the item in a playlist UI, which would lead to a poor user experience.

This is why I introduced the concept of source, added as parameter to all PlayerItem creation methods. This way we can add information about the context of creation of a PlayerItem, readily available for item display in a playlist UI.

The type of this source will be discussed in the next section, but note that we want it to be independent from the metadata that will possibly be loaded with the item. This would namely lead to inconsistent display, with some values displayed initially, replaced by other values when the item has been loaded. Again a poor user experience.

[!NOTE] This approach also avoids pitfalls of our initial demo playlist implementation. Our sync code was namely unidirectional, which means media list mutations would lead to player item list mutations, but not the other way around. In particular, we had no way of inserting a meaningful media if a player item was added directly to the player with its public API.

Source type

In general we want to preserve the type of objects so that we can access their API directly and safely, without any kind of downcasting. This is what we achieved with our tracker API, for example.

If we wanted the same for sources associated with PlayerItems we would need to make PlayerItem generic and, transitively, Player and all surrounding components as well. This would also force items to be accepted by a player only if they all have matching source types and probably force us to introduce protocols for type erasure, a process especially annoying when @Published properties are involved.

For this reason I see no other option than storing source as Any. This of course means a downcasting is required but an app controls the context of creation of its items and therefore the kinds of downcastings that are required.

Playlist UI component

A natural way to display Player items is to use a SwiftUI List:

Changes made

Checklist