Player: Use a wrapper struct to write methods on &self

Previously, methods that required the Player to be ref counted,
were using static methods with s: &Rc<Self> as the first argument.

Now the wrapper type auto-derefs to the inner struct and you can
declare methods on just &self.
This commit is contained in:
Jordan Petridis 2018-11-18 12:41:03 +02:00
parent 201f2e23c7
commit 98f105fda0
2 changed files with 157 additions and 132 deletions

View File

@ -96,7 +96,7 @@ pub(crate) struct App {
settings: gio::Settings,
content: Rc<Content>,
headerbar: Rc<Header>,
player: Rc<player::PlayerWidget>,
player: player::PlayerWrapper,
updater: RefCell<Option<InAppNotification>>,
sender: Sender<Action>,
receiver: Receiver<Action>,
@ -151,7 +151,7 @@ impl App {
// Add the overlay to the main Box
wrap.add(&overlay);
let player = player::PlayerWidget::new(&sender);
let player = player::PlayerWrapper::new(&sender);
// Add the player to the main Box
wrap.add(&player.action_bar);

View File

@ -304,136 +304,6 @@ impl Default for PlayerWidget {
}
impl PlayerWidget {
pub(crate) fn new(sender: &Sender<Action>) -> Rc<Self> {
let w = Rc::new(Self::default());
Self::init(&w, sender);
w
}
fn init(s: &Rc<Self>, sender: &Sender<Action>) {
Self::connect_control_buttons(s);
Self::connect_rate_buttons(s);
Self::connect_mpris_buttons(s, sender);
Self::connect_gst_signals(s, sender);
}
/// Connect the `PlayerControls` buttons to the `PlayerExt` methods.
fn connect_control_buttons(s: &Rc<Self>) {
let weak = Rc::downgrade(s);
// Connect the play button to the gst Player.
s.controls.play.connect_clicked(clone!(weak => move |_| {
weak.upgrade().map(|p| p.play());
}));
// Connect the pause button to the gst Player.
s.controls.pause.connect_clicked(clone!(weak => move |_| {
weak.upgrade().map(|p| p.pause());
}));
// Connect the rewind button to the gst Player.
s.controls.rewind.connect_clicked(clone!(weak => move |_| {
weak.upgrade().map(|p| p.rewind());
}));
// Connect the fast-forward button to the gst Player.
s.controls.forward.connect_clicked(clone!(weak => move |_| {
weak.upgrade().map(|p| p.fast_forward());
}));
}
fn connect_mpris_buttons(s: &Rc<Self>, sender: &Sender<Action>) {
let weak = Rc::downgrade(s);
let mpris = s.info.mpris.clone();
s.info.mpris.connect_play_pause(clone!(weak => move || {
let player = match weak.upgrade() {
Some(s) => s,
None => return
};
if let Ok(status) = mpris.get_playback_status() {
match status.as_ref() {
"Paused" => player.play(),
"Stopped" => player.play(),
_ => player.pause(),
};
}
}));
s.info.mpris.connect_next(clone!(weak => move || {
weak.upgrade().map(|p| p.fast_forward());
}));
s.info.mpris.connect_previous(clone!(weak => move || {
weak.upgrade().map(|p| p.rewind());
}));
s.info
.mpris
.connect_raise(clone!(sender => move || sender.send(Action::RaiseWindow)));
}
#[cfg_attr(rustfmt, rustfmt_skip)]
fn connect_gst_signals(s: &Rc<Self>, sender: &Sender<Action>) {
// Log gst warnings.
s.player.connect_warning(move |_, warn| warn!("gst warning: {}", warn));
// Log gst errors.
s.player.connect_error(clone!(sender => move |_, _error| {
// sender.send(Action::ErrorNotification(format!("Player Error: {}", error)));
let s = i18n("The media player was unable to execute an action.");
sender.send(Action::ErrorNotification(s));
}));
// The following callbacks require `Send` but are handled by the gtk main loop
let weak = Fragile::new(Rc::downgrade(s));
// Update the duration label and the slider
s.player.connect_duration_changed(clone!(weak => move |_, clock| {
weak.get()
.upgrade()
.map(|p| p.timer.on_duration_changed(Duration(clock)));
}));
// Update the position label and the slider
s.player.connect_position_updated(clone!(weak => move |_, clock| {
weak.get()
.upgrade()
.map(|p| p.timer.on_position_updated(Position(clock)));
}));
// Reset the slider to 0 and show a play button
s.player.connect_end_of_stream(clone!(weak => move |_| {
weak.get()
.upgrade()
.map(|p| p.stop());
}));
}
#[cfg_attr(rustfmt, rustfmt_skip)]
fn connect_rate_buttons(s: &Rc<Self>) {
let weak = Rc::downgrade(s);
s.rate
.radio_normal
.connect_toggled(clone!(weak => move |_| {
weak.upgrade().map(|p| p.on_rate_changed(1.00));
}));
s.rate
.radio125
.connect_toggled(clone!(weak => move |_| {
weak.upgrade().map(|p| p.on_rate_changed(1.25));
}));
s.rate
.radio150
.connect_toggled(clone!(weak => move |_| {
weak.upgrade().map(|p| p.on_rate_changed(1.50));
}));
}
fn on_rate_changed(&self, rate: f64) {
self.set_playback_rate(rate);
self.rate.label.set_text(&format!("{:.2}×", rate));
@ -593,3 +463,158 @@ impl PlayerExt for PlayerWidget {
self.player.set_rate(rate);
}
}
#[derive(Debug, Clone)]
pub(crate) struct PlayerWrapper(pub Rc<PlayerWidget>);
impl Default for PlayerWrapper {
fn default() -> Self {
PlayerWrapper(Rc::new(PlayerWidget::default()))
}
}
impl Deref for PlayerWrapper {
type Target = Rc<PlayerWidget>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl PlayerWrapper {
pub(crate) fn new(sender: &Sender<Action>) -> Self {
let w = Self::default();
w.init(sender);
w
}
fn init(&self, sender: &Sender<Action>) {
self.connect_control_buttons();
self.connect_rate_buttons();
self.connect_mpris_buttons(sender);
self.connect_gst_signals(sender);
}
/// Connect the `PlayerControls` buttons to the `PlayerExt` methods.
fn connect_control_buttons(&self) {
let weak = Rc::downgrade(self);
// Connect the play button to the gst Player.
self.controls.play.connect_clicked(clone!(weak => move |_| {
weak.upgrade().map(|p| p.play());
}));
// Connect the pause button to the gst Player.
self.controls
.pause
.connect_clicked(clone!(weak => move |_| {
weak.upgrade().map(|p| p.pause());
}));
// Connect the rewind button to the gst Player.
self.controls
.rewind
.connect_clicked(clone!(weak => move |_| {
weak.upgrade().map(|p| p.rewind());
}));
// Connect the fast-forward button to the gst Player.
self.controls
.forward
.connect_clicked(clone!(weak => move |_| {
weak.upgrade().map(|p| p.fast_forward());
}));
}
#[cfg_attr(rustfmt, rustfmt_skip)]
fn connect_gst_signals(&self, sender: &Sender<Action>) {
// Log gst warnings.
self.player.connect_warning(move |_, warn| warn!("gst warning: {}", warn));
// Log gst errors.
self.player.connect_error(clone!(sender => move |_, _error| {
// sender.send(Action::ErrorNotification(format!("Player Error: {}", error)));
let s = i18n("The media player was unable to execute an action.");
sender.send(Action::ErrorNotification(s));
}));
// The following callbacks require `Send` but are handled by the gtk main loop
let weak = Fragile::new(Rc::downgrade(self));
// Update the duration label and the slider
self.player.connect_duration_changed(clone!(weak => move |_, clock| {
weak.get()
.upgrade()
.map(|p| p.timer.on_duration_changed(Duration(clock)));
}));
// Update the position label and the slider
self.player.connect_position_updated(clone!(weak => move |_, clock| {
weak.get()
.upgrade()
.map(|p| p.timer.on_position_updated(Position(clock)));
}));
// Reset the slider to 0 and show a play button
self.player.connect_end_of_stream(clone!(weak => move |_| {
weak.get()
.upgrade()
.map(|p| p.stop());
}));
}
#[cfg_attr(rustfmt, rustfmt_skip)]
fn connect_rate_buttons(&self) {
let weak = Rc::downgrade(self);
self.rate
.radio_normal
.connect_toggled(clone!(weak => move |_| {
weak.upgrade().map(|p| p.on_rate_changed(1.00));
}));
self.rate
.radio125
.connect_toggled(clone!(weak => move |_| {
weak.upgrade().map(|p| p.on_rate_changed(1.25));
}));
self.rate
.radio150
.connect_toggled(clone!(weak => move |_| {
weak.upgrade().map(|p| p.on_rate_changed(1.50));
}));
}
fn connect_mpris_buttons(&self, sender: &Sender<Action>) {
let weak = Rc::downgrade(self);
// FIXME: Refference cycle with mpris
let mpris = self.info.mpris.clone();
self.info.mpris.connect_play_pause(clone!(weak => move || {
let player = match weak.upgrade() {
Some(s) => s,
None => return
};
if let Ok(status) = mpris.get_playback_status() {
match status.as_ref() {
"Paused" => player.play(),
"Stopped" => player.play(),
_ => player.pause(),
};
}
}));
self.info.mpris.connect_next(clone!(weak => move || {
weak.upgrade().map(|p| p.fast_forward());
}));
self.info.mpris.connect_previous(clone!(weak => move || {
weak.upgrade().map(|p| p.rewind());
}));
self.info
.mpris
.connect_raise(clone!(sender => move || sender.send(Action::RaiseWindow)));
}
}