mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
222 lines
7.4 KiB
Swift
222 lines
7.4 KiB
Swift
import Foundation
|
|
import SwiftSignalKit
|
|
import Postbox
|
|
import TelegramCore
|
|
|
|
enum SharedMediaPlayerControlAction {
|
|
case next
|
|
case previous
|
|
case play
|
|
case pause
|
|
case togglePlayPause
|
|
}
|
|
|
|
enum SharedMediaPlaylistControlAction {
|
|
case next
|
|
case previous
|
|
}
|
|
|
|
enum SharedMediaPlaybackDataType {
|
|
case music
|
|
case voice
|
|
case instantVideo
|
|
}
|
|
|
|
enum SharedMediaPlaybackDataSource: Equatable {
|
|
case telegramFile(TelegramMediaFile)
|
|
|
|
static func ==(lhs: SharedMediaPlaybackDataSource, rhs: SharedMediaPlaybackDataSource) -> Bool {
|
|
switch lhs {
|
|
case let .telegramFile(lhsFile):
|
|
if case let .telegramFile(rhsFile) = rhs {
|
|
return lhsFile.isEqual(rhsFile)
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct SharedMediaPlaybackData: Equatable {
|
|
let type: SharedMediaPlaybackDataType
|
|
let source: SharedMediaPlaybackDataSource
|
|
|
|
static func ==(lhs: SharedMediaPlaybackData, rhs: SharedMediaPlaybackData) -> Bool {
|
|
return lhs.type == rhs.type && lhs.source == rhs.source
|
|
}
|
|
}
|
|
|
|
enum SharedMediaPlaybackDisplayData: Equatable {
|
|
case music(title: String?, performer: String?)
|
|
case voice(author: Peer?, peer: Peer?)
|
|
case instantVideo(author: Peer?, peer: Peer?)
|
|
|
|
static func ==(lhs: SharedMediaPlaybackDisplayData, rhs: SharedMediaPlaybackDisplayData) -> Bool {
|
|
switch lhs {
|
|
case let .music(lhsTitle, lhsPerformer):
|
|
if case let .music(rhsTitle, rhsPerformer) = rhs, lhsTitle == rhsTitle, lhsPerformer == rhsPerformer {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
case let .voice(lhsAuthor, lhsPeer):
|
|
if case let .voice(rhsAuthor, rhsPeer) = rhs, arePeersEqual(lhsAuthor, rhsAuthor), arePeersEqual(lhsPeer, rhsPeer) {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
case let .instantVideo(lhsAuthor, lhsPeer):
|
|
if case let .instantVideo(rhsAuthor, rhsPeer) = rhs, arePeersEqual(lhsAuthor, rhsAuthor), arePeersEqual(lhsPeer, rhsPeer) {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protocol SharedMediaPlaylistItem {
|
|
var stableId: AnyHashable { get }
|
|
var playbackData: SharedMediaPlaybackData? { get }
|
|
var displayData: SharedMediaPlaybackDisplayData? { get }
|
|
}
|
|
|
|
final class SharedMediaPlaylistState {
|
|
let loading: Bool
|
|
let item: SharedMediaPlaylistItem?
|
|
|
|
init(loading: Bool, item: SharedMediaPlaylistItem?) {
|
|
self.loading = loading
|
|
self.item = item
|
|
}
|
|
}
|
|
|
|
protocol SharedMediaPlaylist {
|
|
var state: Signal<SharedMediaPlaylistState, NoError> { get }
|
|
|
|
func control(_ action: SharedMediaPlaylistControlAction)
|
|
}
|
|
|
|
private enum SharedMediaPlaybackItem {
|
|
case audio(MediaPlayer)
|
|
case instantVideo(InstantVideoNode)
|
|
|
|
func play() {
|
|
switch self {
|
|
case let .audio(player):
|
|
player.play()
|
|
case let .instantVideo(node):
|
|
node.play()
|
|
}
|
|
}
|
|
|
|
func pause() {
|
|
switch self {
|
|
case let .audio(player):
|
|
player.pause()
|
|
case let .instantVideo(node):
|
|
node.pause()
|
|
}
|
|
}
|
|
|
|
func togglePlayPause() {
|
|
switch self {
|
|
case let .audio(player):
|
|
player.togglePlayPause()
|
|
case let .instantVideo(node):
|
|
node.togglePlayPause()
|
|
}
|
|
}
|
|
|
|
func seek(_ timestamp: Double) {
|
|
switch self {
|
|
case let .audio(player):
|
|
player.seek(timestamp: timestamp)
|
|
case let .instantVideo(node):
|
|
node.seek(timestamp)
|
|
}
|
|
}
|
|
|
|
func setSoundEnabled(_ value: Bool) {
|
|
switch self {
|
|
case .audio:
|
|
break
|
|
case let .instantVideo(node):
|
|
node.setSoundEnabled(value)
|
|
}
|
|
}
|
|
}
|
|
|
|
final class SharedMediaPlayer {
|
|
private let account: Account
|
|
private let manager: MediaManager
|
|
private let playlist: SharedMediaPlaylist
|
|
|
|
private var stateDisposable: Disposable?
|
|
|
|
private var stateValue: SharedMediaPlaylistState?
|
|
private var playbackItem: SharedMediaPlaybackItem?
|
|
|
|
init(account: Account, manager: MediaManager, playlist: SharedMediaPlaylist) {
|
|
self.account = account
|
|
self.manager = manager
|
|
self.playlist = playlist
|
|
|
|
self.stateDisposable = (playlist.state |> deliverOnMainQueue).start(next: { [weak self] state in
|
|
if let strongSelf = self {
|
|
if state.item?.playbackData != strongSelf.stateValue?.item?.playbackData {
|
|
strongSelf.playbackItem?.pause()
|
|
if let playbackItem = strongSelf.playbackItem {
|
|
switch playbackItem {
|
|
case .audio:
|
|
break
|
|
case let .instantVideo(node):
|
|
strongSelf.manager.overlayMediaManager.controller?.removeNode(node)
|
|
}
|
|
}
|
|
strongSelf.playbackItem = nil
|
|
if let item = state.item, let playbackData = item.playbackData {
|
|
switch playbackData.type {
|
|
case .voice, .music:
|
|
switch playbackData.source {
|
|
case let .telegramFile(file):
|
|
strongSelf.playbackItem = .audio(MediaPlayer(audioSessionManager: strongSelf.manager.audioSession, postbox: strongSelf.account.postbox, resource: file.resource, streamable: true, video: false, preferSoftwareDecoding: false, enableSound: true))
|
|
}
|
|
case .instantVideo:
|
|
let presentationData = strongSelf.account.telegramApplicationContext.currentPresentationData.with { $0 }
|
|
switch playbackData.source {
|
|
case let .telegramFile(file):
|
|
strongSelf.playbackItem = .instantVideo(InstantVideoNode(theme: presentationData.theme, manager: strongSelf.manager, account: strongSelf.account, source: .messageMedia(stableId: item.stableId, file: file), priority: 0, withSound: true))
|
|
}
|
|
}
|
|
}
|
|
if let playbackItem = strongSelf.playbackItem {
|
|
switch playbackItem {
|
|
case .audio:
|
|
break
|
|
case let .instantVideo(node):
|
|
strongSelf.manager.overlayMediaManager.controller?.addNode(node)
|
|
}
|
|
}
|
|
}
|
|
strongSelf.stateValue = state
|
|
}
|
|
})
|
|
}
|
|
|
|
deinit {
|
|
self.stateDisposable?.dispose()
|
|
}
|
|
|
|
func control(_ action: SharedMediaPlayerControlAction) {
|
|
switch action {
|
|
case .next:
|
|
self.playlist.control(.next)
|
|
case .previous:
|
|
self.playlist.control(.previous)
|
|
case .play, .pause, .togglePlayPause:
|
|
break
|
|
}
|
|
}
|
|
}
|