Refactored and moved to separate file audio player in touchbar.

This commit is contained in:
23rd 2020-07-03 17:59:55 +03:00 committed by John Preston
parent 0970728273
commit 2f964d0415
5 changed files with 260 additions and 2 deletions

View file

@ -891,6 +891,8 @@ PRIVATE
platform/mac/specific_mac_p.h
platform/mac/window_title_mac.mm
platform/mac/window_title_mac.h
platform/mac/touchbar/mac_touchbar_audio.h
platform/mac/touchbar/mac_touchbar_audio.mm
platform/mac/touchbar/mac_touchbar_common.h
platform/mac/touchbar/mac_touchbar_common.mm
platform/win/audio_win.cpp

View file

@ -388,7 +388,7 @@ rpl::producer<> Media::Player::Instance::playlistChanges(
return data->playlistChanges.events();
}
Instance *instance() {
not_null<Instance*> instance() {
Expects(SingleInstance != nullptr);
return SingleInstance;
}

View file

@ -47,7 +47,7 @@ void SaveLastPlaybackPosition(
not_null<DocumentData*> document,
const TrackState &state);
Instance *instance();
not_null<Instance*> instance();
class Instance : private base::Subscriber {
public:

View file

@ -0,0 +1,15 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#import <AppKit/NSTouchBar.h>
API_AVAILABLE(macos(10.12.2))
@interface TouchBarAudioPlayer : NSTouchBar<NSTouchBarDelegate>
- (rpl::producer<>)closeRequests;
@end

View file

@ -0,0 +1,241 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "platform/mac/touchbar/mac_touchbar_audio.h"
#include "core/sandbox.h"
#include "media/audio/media_audio.h"
#include "media/player/media_player_instance.h"
#include "platform/mac/touchbar/mac_touchbar_common.h"
#include "styles/style_media_player.h"
#import <AppKit/NSButton.h>
#import <AppKit/NSCustomTouchBarItem.h>
#import <AppKit/NSSlider.h>
#import <AppKit/NSSliderTouchBarItem.h>
#ifndef OS_OSX
NSImage *qt_mac_create_nsimage(const QPixmap &pm);
using TouchBar::kCircleDiameter;
using TouchBar::CreateNSImageFromStyleIcon;
namespace {
constexpr auto kSongType = AudioMsgId::Type::Song;
const auto *kCustomizationIdPlayer = @"telegram.touchbar";
inline NSTouchBarItemIdentifier Format(NSString *s) {
return [NSString stringWithFormat:@"%@.%@", kCustomizationIdPlayer, s];
}
const auto kSeekBarItemIdentifier = Format(@"seekbar");
const auto kPlayItemIdentifier = Format(@"play");
const auto kNextItemIdentifier = Format(@"nextItem");
const auto kPreviousItemIdentifier = Format(@"previousItem");
const auto kClosePlayerItemIdentifier = Format(@"closePlayer");
const auto kCurrentPositionItemIdentifier = Format(@"currentPosition");
API_AVAILABLE(macos(10.12.2))
NSButton* CreateTouchBarButton(
const style::icon &icon,
rpl::lifetime &lifetime,
Fn<void()> callback) {
id block = [^{
Core::Sandbox::Instance().customEnterFromEventLoop(callback);
} copy];
NSButton* button = [NSButton
buttonWithImage:CreateNSImageFromStyleIcon(icon, kCircleDiameter / 2)
target:block
action:@selector(invoke)];
lifetime.add([=] {
[block release];
});
return button;
}
} // namespace
#pragma mark - TouchBarAudioPlayer
@interface TouchBarAudioPlayer()
@end // @interface TouchBarAudioPlayer
@implementation TouchBarAudioPlayer {
rpl::event_stream<> _closeRequests;
rpl::producer< Media::Player::TrackState> _trackState;
rpl::lifetime _lifetime;
}
- (id)init {
self = [super init];
if (!self) {
return self;
}
self.delegate = self;
self.customizationIdentifier = kCustomizationIdPlayer.lowercaseString;
self.defaultItemIdentifiers = @[
kPlayItemIdentifier,
kPreviousItemIdentifier,
kNextItemIdentifier,
kSeekBarItemIdentifier,
kClosePlayerItemIdentifier];
self.customizationAllowedItemIdentifiers = @[
kPlayItemIdentifier,
kPreviousItemIdentifier,
kNextItemIdentifier,
// kCurrentPositionItemIdentifier, // TODO.
kSeekBarItemIdentifier,
kClosePlayerItemIdentifier];
_trackState = Media::Player::instance()->updatedNotifier(
) | rpl::filter([=](const Media::Player::TrackState &state) {
return state.id.type() == kSongType;
});
return self;
}
- (NSTouchBarItem*)touchBar:(NSTouchBar*)touchBar
makeItemForIdentifier:(NSTouchBarItemIdentifier)itemId {
if (!touchBar) {
return nil;
}
const auto mediaPlayer = Media::Player::instance();
const auto isEqual = [&](NSString *string) {
return [itemId isEqualToString:string];
};
if (isEqual(kSeekBarItemIdentifier)) {
auto *item = [[NSSliderTouchBarItem alloc] initWithIdentifier:itemId];
item.slider.minValue = 0.0f;
item.slider.maxValue = 1.0f;
item.customizationLabel = @"Seek Bar";
id block = [^{
// https://stackoverflow.com/a/45891017
auto *event = [[NSApplication sharedApplication] currentEvent];
const auto touchUp = [event
touchesMatchingPhase:NSTouchPhaseEnded
inView:nil].count > 0;
Core::Sandbox::Instance().customEnterFromEventLoop([=] {
if (touchUp) {
mediaPlayer->finishSeeking(kSongType, item.doubleValue);
} else {
mediaPlayer->startSeeking(kSongType);
}
});
} copy];
rpl::duplicate(
_trackState
) | rpl::start_with_next([=](const Media::Player::TrackState &state) {
const auto stop = Media::Player::IsStoppedOrStopping(state.state);
const auto duration = double(stop ? 0 : state.length);
auto slider = item.slider;
if (duration <= 0) {
slider.enabled = false;
slider.doubleValue = 0;
} else {
slider.enabled = true;
if (!slider.highlighted) {
const auto pos = stop
? 0
: std::max(state.position, int64(0));
slider.doubleValue = (pos / duration) * slider.maxValue;
}
}
}, _lifetime);
item.target = block;
item.action = @selector(invoke);
_lifetime.add([=] {
[block release];
});
return [item autorelease];
} else if (isEqual(kNextItemIdentifier)
|| isEqual(kPreviousItemIdentifier)) {
const auto isNext = isEqual(kNextItemIdentifier);
auto *item = [[NSCustomTouchBarItem alloc] initWithIdentifier:itemId];
auto *button = CreateTouchBarButton(
isNext
? st::touchBarIconPlayerNext
: st::touchBarIconPlayerPrevious,
_lifetime,
[=] { isNext // TODO
? mediaPlayer->next(kSongType)
: mediaPlayer->previous(kSongType); });
rpl::duplicate(
_trackState
) | rpl::start_with_next([=] {
const auto newValue = isNext
? mediaPlayer->nextAvailable(kSongType)
: mediaPlayer->previousAvailable(kSongType);
if (button.enabled != newValue) {
button.enabled = newValue;
}
}, _lifetime);
item.view = button;
item.customizationLabel = [NSString
stringWithFormat:@"%@ Playlist Item",
isNext ? @"Next" : @"Previous"];
return [item autorelease];
} else if (isEqual(kPlayItemIdentifier)) {
auto *item = [[NSCustomTouchBarItem alloc] initWithIdentifier:itemId];
auto *button = CreateTouchBarButton(
st::touchBarIconPlayerPause,
_lifetime,
[=] { mediaPlayer->playPause(kSongType); });
auto *pause = [button.image retain];
auto *play = [CreateNSImageFromStyleIcon(
st::touchBarIconPlayerPlay,
kCircleDiameter / 2) retain];
rpl::duplicate(
_trackState
) | rpl::start_with_next([=](const auto &state) {
button.image = (state.state == Media::Player::State::Playing)
? pause
: play;
}, _lifetime);
_lifetime.add([=] {
// Avoid a memory leak from retaining of images.
[pause release];
[play release];
});
item.view = button;
item.customizationLabel = @"Play/Pause";
return [item autorelease];
} else if (isEqual(kClosePlayerItemIdentifier)) {
auto *item = [[NSCustomTouchBarItem alloc] initWithIdentifier:itemId];
auto *button = CreateTouchBarButton(
st::touchBarIconPlayerClose,
_lifetime,
[=] { _closeRequests.fire({}); });
item.view = button;
item.customizationLabel = @"Close Player";
return [item autorelease];
}
return nil;
}
- (rpl::producer<>)closeRequests {
return _closeRequests.events();
}
@end // @implementation TouchBarAudioPlayer
#endif // OS_OSX