root/src/data.rs

use mpd;

#[derive(Debug, Clone)]
pub struct ListPage {
    pub tag: mpd::Tag,
    pub value: String,
    pub top_levels: Vec<(String, mpd::Tag)>,
    pub sub_pages: Vec<mpd::Tag>,
}

#[derive(Debug, PartialEq)]
pub enum ListPageItem {
    ListPageString { string: String },
    ListPageTrack { track: mpd::Track },
}

#[derive(Debug)]
pub enum Action {
    Init,
    Idle,
    Quit,
    SecondPassed,
    GotStatus {
        status: mpd::Status,
    },
    GotQueue {
        tracks: Vec<mpd::Track>,
    },
    GotClient {
        client: mpd::Client,
    },
    GotIdleClient {
        idle_client: mpd::Client,
    },
    SetVolume {
        volume: u16,
    },
    RaiseVolume,
    LowerVolume,
    SetEndless {
        endless: bool,
    },
    SetRandomize {
        randomize: bool,
    },
    SetSingleMode {
        single: bool,
    },
    SetConsumeMode {
        consume: bool,
    },
    ToggleSingleMode,
    ToggleConsumeMode,
    // reundant actions for hotkeys
    ToggleEndless,
    ToggleRandomize,
    TogglePause,
    //
    NextTrack,
    PreviousTrack,
    Search {
        search: String,
        tag: mpd::Tag,
    },
    FindListPage {
        page: ListPage,
    },
    GotListPage {
        page: ListPage,
        results: Vec<mpd::Track>,
    },
    List {
        tag: mpd::Tag,
    },
    GotList {
        tag: mpd::Tag,
        items: Vec<String>,
    },
    GotSearch {
        items: Vec<mpd::Track>,
    },
    AddFilesToQueue {
        files: Vec<String>,
    },
    QueueNext {
        index: usize,
    },
    Play {
        index: usize,
    },
    RemoveTrack {
        index: usize,
    },
    Seek {
        position: f64,
    },
    SeekRelative {
        offset: f64,
    },
    SetPause {
        pause: bool,
    },
    UpdateStatus,
    UpdateQueue,
    OpenQueuePage,
    OpenFilterPage,
    ScrollTracklistTo {
        value: f64,
    },
    ClearQueue,
    ClientError {
        error: anyhow::Error,
    },
    OpenConfig,
    SaveWipConfig,
    // OpenMenuPopup,
    SelectServerDelta {
        delta: i16,
    },

    ConfigRemoveServer {
        index: usize,
    },
    ConfigAddServer,
    ConfigUpdateServerInput,
    ConfigSetActiveServer {
        index: usize,
    },

    InitClient,
    InitMpris,
    RaiseWindow,
    GotCover {
        uri: String,
        texture: Option<gtk::gdk::Texture>,
    },
    SetMprisCover,
}

pub fn track_title(t: &mpd::Track) -> String {
    match &t.title {
        None => std::path::Path::new(&t.file)
            .file_stem()
            .and_then(|s| s.to_str())
            .unwrap_or("")
            .to_owned(),
        Some(title) => title.clone(),
    }
}
pub fn track_subtitle(t: &mpd::Track) -> String {
    match (&t.artist, &t.album) {
        (None, None) => t.file.clone(),
        (Some(artist), None) => format!("{} - ", &artist),
        (None, Some(album)) => format!(" - {}", &album),
        (Some(artist), Some(album)) => format!("{} - {}", &artist, &album),
    }
}

pub fn track_triplet_string(t: &mpd::Track) -> String {
    format!("{} - {}", track_title(t), track_subtitle(t))
}
pub fn make_time_string(time: u16) -> String {
    format!("{:02}:{:02}", time / 60, time % 60)
}

/// Copied from the gtk-macros crate
///
/// Send an event through a glib::Sender
///
/// - Before:
///
///     Example:
///
///     ```no_run
///     sender.send(Action::DoThing).expect("Failed to send DoThing through the glib channel?");
///     ```
///
/// - After:
///
///     Example:
///
///     ```no_run
///     send!(self.sender, Action::DoThing);
///     ```
#[macro_export]
macro_rules! send {
    ($sender:expr, $action:expr) => {
        if let Err(err) = $sender.send($action) {
            panic!(
                "Failed to send \"{}\" action due to {}",
                stringify!($action),
                err
            );
        }
    };
}

#[macro_export]
macro_rules! add_action {
    ($state:expr, $name:expr, $action:expr) => {
        let gaction = gtk::gio::SimpleAction::new($name, None);
        let sender = &($state).sender;
        gaction.connect_activate(clone!(@strong sender => move |_, _| {
            send!(sender, $action);
        }));
        ($state).app.add_action(&gaction);
    }
}