mac_touchbar_audio.mm 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "platform/mac/touchbar/mac_touchbar_audio.h"
  8. #include "media/audio/media_audio.h"
  9. #include "media/player/media_player_instance.h"
  10. #include "platform/mac/touchbar/mac_touchbar_common.h"
  11. #include "platform/mac/touchbar/mac_touchbar_controls.h"
  12. #include "styles/style_media_player.h"
  13. #import <AppKit/NSButton.h>
  14. #import <AppKit/NSCustomTouchBarItem.h>
  15. #import <AppKit/NSSlider.h>
  16. #import <AppKit/NSSliderTouchBarItem.h>
  17. using TouchBar::kCircleDiameter;
  18. using TouchBar::CreateNSImageFromStyleIcon;
  19. namespace {
  20. constexpr auto kSongType = AudioMsgId::Type::Song;
  21. const auto *kCustomizationIdPlayer = @"telegram.touchbar";
  22. inline NSTouchBarItemIdentifier Format(NSString *s) {
  23. return [NSString stringWithFormat:@"%@.%@", kCustomizationIdPlayer, s];
  24. }
  25. const auto kSeekBarItemIdentifier = Format(@"seekbar");
  26. const auto kPlayItemIdentifier = Format(@"play");
  27. const auto kNextItemIdentifier = Format(@"nextItem");
  28. const auto kPreviousItemIdentifier = Format(@"previousItem");
  29. const auto kClosePlayerItemIdentifier = Format(@"closePlayer");
  30. const auto kCurrentPositionItemIdentifier = Format(@"currentPosition");
  31. } // namespace
  32. #pragma mark - TouchBarAudioPlayer
  33. @interface TouchBarAudioPlayer()
  34. @end // @interface TouchBarAudioPlayer
  35. @implementation TouchBarAudioPlayer {
  36. rpl::event_stream<> _closeRequests;
  37. rpl::producer< Media::Player::TrackState> _trackState;
  38. rpl::lifetime _lifetime;
  39. }
  40. - (id)init {
  41. self = [super init];
  42. if (!self) {
  43. return self;
  44. }
  45. self.delegate = self;
  46. self.customizationIdentifier = kCustomizationIdPlayer.lowercaseString;
  47. self.defaultItemIdentifiers = @[
  48. kPlayItemIdentifier,
  49. kPreviousItemIdentifier,
  50. kNextItemIdentifier,
  51. kSeekBarItemIdentifier,
  52. kClosePlayerItemIdentifier];
  53. self.customizationAllowedItemIdentifiers = @[
  54. kPlayItemIdentifier,
  55. kPreviousItemIdentifier,
  56. kNextItemIdentifier,
  57. kCurrentPositionItemIdentifier,
  58. kSeekBarItemIdentifier,
  59. kClosePlayerItemIdentifier];
  60. _trackState = Media::Player::instance()->updatedNotifier(
  61. ) | rpl::filter([=](const Media::Player::TrackState &state) {
  62. return state.id.type() == kSongType;
  63. });
  64. return self;
  65. }
  66. - (NSTouchBarItem*)touchBar:(NSTouchBar*)touchBar
  67. makeItemForIdentifier:(NSTouchBarItemIdentifier)itemId {
  68. if (!touchBar) {
  69. return nil;
  70. }
  71. const auto mediaPlayer = Media::Player::instance();
  72. const auto isEqual = [&](NSString *string) {
  73. return [itemId isEqualToString:string];
  74. };
  75. if (isEqual(kSeekBarItemIdentifier)) {
  76. auto *item = TouchBar::CreateTouchBarSlider(
  77. itemId,
  78. _lifetime,
  79. [=](bool touchUp, double value, double duration) {
  80. if (touchUp) {
  81. mediaPlayer->finishSeeking(kSongType, value);
  82. } else {
  83. mediaPlayer->startSeeking(kSongType);
  84. }
  85. },
  86. rpl::duplicate(_trackState));
  87. return [item autorelease];
  88. } else if (isEqual(kNextItemIdentifier)
  89. || isEqual(kPreviousItemIdentifier)) {
  90. const auto isNext = isEqual(kNextItemIdentifier);
  91. auto *item = [[NSCustomTouchBarItem alloc] initWithIdentifier:itemId];
  92. auto *button = TouchBar::CreateTouchBarButton(
  93. isNext
  94. ? st::touchBarIconPlayerNext
  95. : st::touchBarIconPlayerPrevious,
  96. _lifetime,
  97. [=] { isNext // TODO
  98. ? mediaPlayer->next(kSongType)
  99. : mediaPlayer->previous(kSongType); });
  100. rpl::duplicate(
  101. _trackState
  102. ) | rpl::start_with_next([=] {
  103. const auto newValue = isNext
  104. ? mediaPlayer->nextAvailable(kSongType)
  105. : mediaPlayer->previousAvailable(kSongType);
  106. if (button.enabled != newValue) {
  107. button.enabled = newValue;
  108. }
  109. }, _lifetime);
  110. item.view = button;
  111. item.customizationLabel = [NSString
  112. stringWithFormat:@"%@ Playlist Item",
  113. isNext ? @"Next" : @"Previous"];
  114. return [item autorelease];
  115. } else if (isEqual(kPlayItemIdentifier)) {
  116. auto *item = [[NSCustomTouchBarItem alloc] initWithIdentifier:itemId];
  117. auto *button = TouchBar::CreateTouchBarButtonWithTwoStates(
  118. st::touchBarIconPlayerPause,
  119. st::touchBarIconPlayerPlay,
  120. _lifetime,
  121. [=](bool value) { mediaPlayer->playPause(kSongType); },
  122. false,
  123. rpl::duplicate(
  124. _trackState
  125. ) | rpl::map([](const auto &state) {
  126. return (state.state == Media::Player::State::Playing);
  127. }) | rpl::distinct_until_changed());
  128. item.view = button;
  129. item.customizationLabel = @"Play/Pause";
  130. return [item autorelease];
  131. } else if (isEqual(kClosePlayerItemIdentifier)) {
  132. auto *item = [[NSCustomTouchBarItem alloc] initWithIdentifier:itemId];
  133. auto *button = TouchBar::CreateTouchBarButton(
  134. st::touchBarIconPlayerClose,
  135. _lifetime,
  136. [=] { _closeRequests.fire({}); });
  137. item.view = button;
  138. item.customizationLabel = @"Close Player";
  139. return [item autorelease];
  140. } else if (isEqual(kCurrentPositionItemIdentifier)) {
  141. auto *item = TouchBar::CreateTouchBarTrackPosition(
  142. itemId,
  143. rpl::duplicate(_trackState));
  144. return [item autorelease];
  145. }
  146. return nil;
  147. }
  148. - (rpl::producer<>)closeRequests {
  149. return _closeRequests.events();
  150. }
  151. @end // @implementation TouchBarAudioPlayer