Rename repeat options to Disabled, Track, and Playlist
Change track and playlist to repeat current track indefinitely.
This commit is contained in:
parent
ff97fa2f62
commit
b559de8fc5
4 changed files with 33 additions and 52 deletions
|
|
@ -36,5 +36,5 @@ quit = Quit
|
|||
# Controls
|
||||
|
||||
repeat-disabled = Repeat disabled
|
||||
repeat-always = Repeat always
|
||||
repeat-once = Repeat once
|
||||
repeat-playlist = Repeat playlist
|
||||
repeat-track = Repeat track
|
||||
|
|
|
|||
|
|
@ -40,11 +40,12 @@ impl Default for Config {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
|
||||
pub enum RepeatState {
|
||||
#[default]
|
||||
Disabled,
|
||||
Once,
|
||||
Always,
|
||||
Track,
|
||||
Playlist,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
|
|
|
|||
55
src/main.rs
55
src/main.rs
|
|
@ -232,7 +232,7 @@ pub struct MprisState {
|
|||
position_micros: i64,
|
||||
paused: bool,
|
||||
volume: f64,
|
||||
will_repeat: bool,
|
||||
repeat_state: RepeatState,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
@ -322,7 +322,6 @@ pub struct App {
|
|||
current_text: Option<i32>,
|
||||
#[cfg(feature = "xdg-portal")]
|
||||
inhibit: tokio::sync::watch::Sender<bool>,
|
||||
has_media_repeated: bool,
|
||||
}
|
||||
|
||||
impl App {
|
||||
|
|
@ -347,7 +346,6 @@ impl App {
|
|||
self.current_audio = -1;
|
||||
self.text_codes.clear();
|
||||
self.current_text = None;
|
||||
self.has_media_repeated = false;
|
||||
self.update_mpris_meta();
|
||||
self.update_nav_bar_active();
|
||||
self.allow_idle();
|
||||
|
|
@ -379,7 +377,6 @@ impl App {
|
|||
};
|
||||
|
||||
self.duration = video.duration().as_secs_f64();
|
||||
self.has_media_repeated = false;
|
||||
let pipeline = video.pipeline();
|
||||
self.video_opt = Some(video);
|
||||
|
||||
|
|
@ -743,15 +740,12 @@ impl App {
|
|||
position_micros: (self.position * 1_000_000.0) as i64,
|
||||
paused: true,
|
||||
volume: 0.0,
|
||||
will_repeat: false,
|
||||
repeat_state: RepeatState::Disabled,
|
||||
};
|
||||
if let Some(video) = &self.video_opt {
|
||||
new.paused = video.paused();
|
||||
new.volume = video.volume();
|
||||
|
||||
let repeat_state = &self.flags.config_state.player_state.repeat;
|
||||
new.will_repeat = *repeat_state == RepeatState::Always
|
||||
|| (*repeat_state == RepeatState::Once && !self.has_media_repeated);
|
||||
new.repeat_state = self.flags.config_state.player_state.repeat;
|
||||
}
|
||||
if new != *old {
|
||||
*old = new.clone();
|
||||
|
|
@ -885,7 +879,6 @@ impl Application for App {
|
|||
current_text: None,
|
||||
#[cfg(feature = "xdg-portal")]
|
||||
inhibit,
|
||||
has_media_repeated: false,
|
||||
};
|
||||
|
||||
// Do not show nav bar by default. Will be opened by open_project if needed
|
||||
|
|
@ -1321,27 +1314,17 @@ impl Application for App {
|
|||
}
|
||||
Message::EndOfStream => {
|
||||
let repeat_state = &self.flags.config_state.player_state.repeat;
|
||||
println!(
|
||||
"end of stream, repeat={:?}, has_media_repeated={:?}",
|
||||
repeat_state, self.has_media_repeated
|
||||
);
|
||||
println!("end of stream, repeat={:?}", repeat_state);
|
||||
|
||||
match repeat_state {
|
||||
RepeatState::Always | RepeatState::Once
|
||||
if (*repeat_state == RepeatState::Always || !self.has_media_repeated) =>
|
||||
{
|
||||
if let Some(video) = &mut self.video_opt {
|
||||
self.has_media_repeated = true;
|
||||
|
||||
// Workaround: Explicitly seeking to the start before `restart_stream`.
|
||||
// This prevents its internal `pause(false)` from triggering a second EndOfStream message
|
||||
// that breaks RepeatState::Once. This results in a double seek but avoids single repeat
|
||||
// not working at all. `restart_stream` is still required to set internal `is_eos` value.
|
||||
video.seek(0, false).expect("seek");
|
||||
video.restart_stream().expect("restart_stream");
|
||||
}
|
||||
if matches!(repeat_state, RepeatState::Playlist | RepeatState::Track) {
|
||||
if let Some(video) = &mut self.video_opt {
|
||||
// Workaround: Explicitly seeking to the start before `restart_stream`.
|
||||
// This prevents its internal `pause(false)` from triggering a second EndOfStream message
|
||||
// that breaks RepeatState::Once. This results in a double seek but avoids single repeat
|
||||
// not working at all. `restart_stream` is still required to set internal `is_eos` value.
|
||||
video.seek(0, false).expect("seek");
|
||||
video.restart_stream().expect("restart_stream");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Message::MissingPlugin(element) => {
|
||||
|
|
@ -1675,22 +1658,22 @@ impl Application for App {
|
|||
widget::button::icon(
|
||||
widget::icon::from_name(match self.flags.config_state.player_state.repeat {
|
||||
RepeatState::Disabled => "media-playlist-no-repeat-symbolic",
|
||||
RepeatState::Always => "media-playlist-repeat-symbolic",
|
||||
RepeatState::Once => "media-playlist-repeat-song-symbolic",
|
||||
RepeatState::Playlist => "media-playlist-repeat-symbolic",
|
||||
RepeatState::Track => "media-playlist-repeat-song-symbolic",
|
||||
})
|
||||
.size(16),
|
||||
)
|
||||
.on_press(Message::RepeatToggled(
|
||||
match self.flags.config_state.player_state.repeat {
|
||||
RepeatState::Disabled => RepeatState::Always,
|
||||
RepeatState::Always => RepeatState::Once,
|
||||
RepeatState::Once => RepeatState::Disabled,
|
||||
RepeatState::Disabled => RepeatState::Playlist,
|
||||
RepeatState::Playlist => RepeatState::Track,
|
||||
RepeatState::Track => RepeatState::Disabled,
|
||||
},
|
||||
)),
|
||||
match self.flags.config_state.player_state.repeat {
|
||||
RepeatState::Disabled => fl!("repeat-disabled"),
|
||||
RepeatState::Always => fl!("repeat-always"),
|
||||
RepeatState::Once => fl!("repeat-once"),
|
||||
RepeatState::Playlist => fl!("repeat-playlist"),
|
||||
RepeatState::Track => fl!("repeat-track"),
|
||||
},
|
||||
widget::tooltip::Position::Top,
|
||||
));
|
||||
|
|
|
|||
19
src/mpris.rs
19
src/mpris.rs
|
|
@ -60,12 +60,10 @@ impl MprisState {
|
|||
}
|
||||
|
||||
fn loop_status(&self) -> LoopStatus {
|
||||
if self.will_repeat {
|
||||
// TODO: Our choice is between Track and Playlist. Track is the best match for current repeat behavior,
|
||||
// but this may change when we implement mpris playlists.
|
||||
LoopStatus::Track
|
||||
} else {
|
||||
LoopStatus::None
|
||||
match self.repeat_state {
|
||||
RepeatState::Disabled => LoopStatus::None,
|
||||
RepeatState::Playlist => LoopStatus::Playlist,
|
||||
RepeatState::Track => LoopStatus::Track,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -210,11 +208,10 @@ impl PlayerInterface for Player {
|
|||
|
||||
async fn set_loop_status(&self, loop_status: LoopStatus) -> Result<()> {
|
||||
log::info!("SetLoopStatus({})", loop_status);
|
||||
let repeat_state = if loop_status == LoopStatus::None {
|
||||
RepeatState::Disabled
|
||||
} else {
|
||||
// TODO: This may change when we implement mpris playlists.
|
||||
RepeatState::Always
|
||||
let repeat_state = match loop_status {
|
||||
LoopStatus::None => RepeatState::Disabled,
|
||||
LoopStatus::Playlist => RepeatState::Playlist,
|
||||
LoopStatus::Track => RepeatState::Track,
|
||||
};
|
||||
self.message(Message::RepeatToggled(repeat_state)).await?;
|
||||
Ok(())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue