media_controls_progress_view.cc 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/media_message_center/media_controls_progress_view.h"
  5. #include "base/i18n/time_formatting.h"
  6. #include "services/media_session/public/mojom/media_session.mojom.h"
  7. #include "ui/base/metadata/metadata_impl_macros.h"
  8. #include "ui/gfx/color_palette.h"
  9. #include "ui/gfx/font_list.h"
  10. #include "ui/views/border.h"
  11. #include "ui/views/controls/label.h"
  12. #include "ui/views/controls/progress_bar.h"
  13. #include "ui/views/layout/box_layout.h"
  14. #include "ui/views/layout/flex_layout.h"
  15. #include "ui/views/layout/flex_layout_types.h"
  16. #include "ui/views/view_class_properties.h"
  17. namespace media_message_center {
  18. namespace {
  19. constexpr int kProgressBarAndTimeSpacing = 8;
  20. constexpr int kProgressTimeFontSize = 11;
  21. constexpr int kProgressBarHeight = 4;
  22. constexpr int kMinClickHeight = 14;
  23. constexpr int kMaxClickHeight = 24;
  24. constexpr gfx::Size kTimeSpacingSize = gfx::Size(150, 10);
  25. constexpr auto kProgressViewInsets = gfx::Insets::TLBR(15, 0, 0, 0);
  26. constexpr int kModernProgressBarHeight = 2;
  27. constexpr auto kModernProgressViewInsets = gfx::Insets::TLBR(8, 0, 8, 0);
  28. } // namespace
  29. MediaControlsProgressView::MediaControlsProgressView(
  30. base::RepeatingCallback<void(double)> seek_callback,
  31. bool is_modern_notification)
  32. : is_modern_notification_(is_modern_notification),
  33. seek_callback_(std::move(seek_callback)) {
  34. SetLayoutManager(std::make_unique<views::BoxLayout>(
  35. views::BoxLayout::Orientation::kVertical,
  36. is_modern_notification_ ? kModernProgressViewInsets : kProgressViewInsets,
  37. kProgressBarAndTimeSpacing));
  38. progress_bar_ = AddChildView(std::make_unique<views::ProgressBar>(
  39. is_modern_notification_ ? kModernProgressBarHeight : kProgressBarHeight,
  40. false));
  41. // Font list for text views.
  42. gfx::Font default_font;
  43. int font_size_delta = kProgressTimeFontSize - default_font.GetFontSize();
  44. gfx::Font font = default_font.Derive(font_size_delta, gfx::Font::NORMAL,
  45. gfx::Font::Weight::NORMAL);
  46. gfx::FontList font_list(font);
  47. auto time_view = std::make_unique<views::View>();
  48. auto* time_view_layout =
  49. time_view->SetLayoutManager(std::make_unique<views::FlexLayout>());
  50. time_view_layout->SetOrientation(views::LayoutOrientation::kHorizontal)
  51. .SetMainAxisAlignment(views::LayoutAlignment::kCenter)
  52. .SetCrossAxisAlignment(views::LayoutAlignment::kCenter)
  53. .SetCollapseMargins(true);
  54. auto progress_time = std::make_unique<views::Label>();
  55. progress_time->SetFontList(font_list);
  56. progress_time->SetAutoColorReadabilityEnabled(false);
  57. progress_time_ = time_view->AddChildView(std::move(progress_time));
  58. auto time_spacing = std::make_unique<views::View>();
  59. time_spacing->SetPreferredSize(kTimeSpacingSize);
  60. time_spacing->SetProperty(
  61. views::kFlexBehaviorKey,
  62. views::FlexSpecification(views::MinimumFlexSizeRule::kPreferred,
  63. views::MaximumFlexSizeRule::kUnbounded));
  64. time_view->AddChildView(std::move(time_spacing));
  65. auto duration = std::make_unique<views::Label>();
  66. duration->SetFontList(font_list);
  67. duration->SetAutoColorReadabilityEnabled(false);
  68. duration_ = time_view->AddChildView(std::move(duration));
  69. if (is_modern_notification_)
  70. time_view->SetVisible(false);
  71. AddChildView(std::move(time_view));
  72. }
  73. MediaControlsProgressView::~MediaControlsProgressView() = default;
  74. void MediaControlsProgressView::UpdateProgress(
  75. const media_session::MediaPosition& media_position) {
  76. // If the media is paused and |update_progress_timer_| is still running, stop
  77. // the timer.
  78. if (media_position.playback_rate() == 0 && update_progress_timer_.IsRunning())
  79. update_progress_timer_.Stop();
  80. const base::TimeDelta current_position = media_position.GetPosition();
  81. const base::TimeDelta duration = media_position.duration();
  82. SetBarProgress(current_position / duration);
  83. // For durations greater than 24 hours, prefer base::DURATION_WIDTH_NARROW for
  84. // better readability (e.g., 27h 23m 10s rather than 27:23:10).
  85. base::DurationFormatWidth time_format = duration >= base::Days(1)
  86. ? base::DURATION_WIDTH_NARROW
  87. : base::DURATION_WIDTH_NUMERIC;
  88. std::u16string elapsed_time;
  89. bool elapsed_time_received = base::TimeDurationFormatWithSeconds(
  90. current_position, time_format, &elapsed_time);
  91. std::u16string total_time;
  92. bool total_time_received =
  93. base::TimeDurationFormatWithSeconds(duration, time_format, &total_time);
  94. if (elapsed_time_received && total_time_received) {
  95. // If |duration| is less than an hour, we don't want to show "0:" hours on
  96. // the progress times.
  97. if (duration < base::Hours(1)) {
  98. base::ReplaceFirstSubstringAfterOffset(&elapsed_time, 0, u"0:", u"");
  99. base::ReplaceFirstSubstringAfterOffset(&total_time, 0, u"0:", u"");
  100. }
  101. SetProgressTime(elapsed_time);
  102. SetDuration(total_time);
  103. }
  104. if (media_position.playback_rate() != 0) {
  105. base::TimeDelta update_frequency =
  106. base::Seconds(std::abs(1 / media_position.playback_rate()));
  107. update_progress_timer_.Start(
  108. FROM_HERE, update_frequency,
  109. base::BindRepeating(&MediaControlsProgressView::UpdateProgress,
  110. base::Unretained(this), media_position));
  111. }
  112. }
  113. void MediaControlsProgressView::SetForegroundColor(SkColor color) {
  114. progress_bar_->SetForegroundColor(color);
  115. }
  116. void MediaControlsProgressView::SetBackgroundColor(SkColor color) {
  117. progress_bar_->SetBackgroundColor(color);
  118. }
  119. void MediaControlsProgressView::SetTextColor(SkColor color) {
  120. progress_time_->SetEnabledColor(color);
  121. duration_->SetEnabledColor(color);
  122. }
  123. bool MediaControlsProgressView::OnMousePressed(const ui::MouseEvent& event) {
  124. if (!event.IsOnlyLeftMouseButton())
  125. return false;
  126. if (!is_modern_notification_ &&
  127. (event.y() < kMinClickHeight || event.y() > kMaxClickHeight)) {
  128. return false;
  129. }
  130. HandleSeeking(event.location());
  131. return true;
  132. }
  133. void MediaControlsProgressView::OnGestureEvent(ui::GestureEvent* event) {
  134. if (event->type() != ui::ET_GESTURE_TAP)
  135. return;
  136. if (!is_modern_notification_ &&
  137. (event->y() < kMinClickHeight || event->y() > kMaxClickHeight)) {
  138. return;
  139. }
  140. HandleSeeking(event->location());
  141. event->SetHandled();
  142. }
  143. const views::ProgressBar* MediaControlsProgressView::progress_bar_for_testing()
  144. const {
  145. return progress_bar_;
  146. }
  147. const std::u16string& MediaControlsProgressView::progress_time_for_testing()
  148. const {
  149. return progress_time_->GetText();
  150. }
  151. const std::u16string& MediaControlsProgressView::duration_for_testing() const {
  152. return duration_->GetText();
  153. }
  154. void MediaControlsProgressView::SetBarProgress(double progress) {
  155. progress_bar_->SetValue(progress);
  156. }
  157. void MediaControlsProgressView::SetProgressTime(const std::u16string& time) {
  158. progress_time_->SetText(time);
  159. }
  160. void MediaControlsProgressView::SetDuration(const std::u16string& duration) {
  161. duration_->SetText(duration);
  162. }
  163. void MediaControlsProgressView::HandleSeeking(const gfx::Point& location) {
  164. gfx::Point location_in_bar(location);
  165. ConvertPointToTarget(this, progress_bar_, &location_in_bar);
  166. double seek_to_progress =
  167. static_cast<double>(location_in_bar.x()) / progress_bar_->width();
  168. seek_callback_.Run(seek_to_progress);
  169. }
  170. BEGIN_METADATA(MediaControlsProgressView, views::View)
  171. END_METADATA
  172. } // namespace media_message_center