Commit 574f276e authored by Felix Häcker's avatar Felix Häcker

Add station favicons for station rows

parent bf8e4a7d
......@@ -471,6 +471,8 @@ name = "gdk-pixbuf"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fragile 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-pixbuf-sys 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gio 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gio-sys 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -1748,6 +1750,7 @@ dependencies = [
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gdk-pixbuf 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gettext-rs 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"gio 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
......
......@@ -12,6 +12,7 @@ gobject-sys = "0.9.0"
glib-sys = "0.9.0"
gio = { version = "0.7.0", features = ["v2_46"] }
gdk = "0.11.0"
gdk-pixbuf = { version = "0.7.0", features = ["futures"] }
gstreamer = "0.14.5"
gstreamer-pbutils = "0.14.0"
mpris-player = "0.4.0"
......
......@@ -14,19 +14,27 @@
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">12</property>
<property name="spacing">6</property>
<child>
<object class="GtkRevealer" id="selection_mode_revealer">
<object class="GtkBox">
<property name="width_request">62</property>
<property name="height_request">62</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="transition_type">slide-right</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkCheckButton" id="check_button">
<object class="GtkImage" id="station_favicon">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="pixel_size">32</property>
<property name="icon_name">emblem-music-symbolic</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
......@@ -36,11 +44,10 @@
</packing>
</child>
<child>
<object class="GtkImage" id="station_favicon">
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixel_size">32</property>
<property name="icon_name">emblem-music-symbolic</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
......@@ -52,75 +59,88 @@
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="border_width">12</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="station_label">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">label</property>
<property name="wrap">True</property>
<property name="wrap_mode">char</property>
<property name="ellipsize">end</property>
<property name="xalign">0</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="station_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">label</property>
<property name="wrap">True</property>
<property name="wrap_mode">char</property>
<property name="ellipsize">end</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="subtitle_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">label</property>
<property name="wrap">True</property>
<property name="wrap_mode">char</property>
<property name="ellipsize">end</property>
<property name="xalign">0</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="subtitle_label">
<object class="GtkButton" id="play_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">label</property>
<property name="wrap">True</property>
<property name="wrap_mode">char</property>
<property name="ellipsize">end</property>
<property name="xalign">0</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">media-playback-start-symbolic</property>
</object>
</child>
<style>
<class name="dim-label"/>
<class name="image-button"/>
</style>
</object>
<packing>
<property name="expand">True</property>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
<property name="pack_type">end</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="play_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">media-playback-start-symbolic</property>
</object>
</child>
<style>
<class name="image-button"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
<style>
......
......@@ -7,7 +7,7 @@
}
.tile {
padding: 1px;
padding: 0px;
border-radius: 6px;
border: 1px solid @borders;
color: @theme_fg_color;
......
use soup::prelude::*;
use soup::Session;
use gio::DataInputStream;
use gdk_pixbuf::Pixbuf;
use crate::api::Error;
use crate::config;
#[derive(Clone)]
pub struct FaviconDownloader{
session: Session,
}
impl FaviconDownloader{
pub fn new() -> Self{
let user_agent = format!("{}/{}", config::NAME, config::VERSION);
let session = soup::Session::new();
session.set_property_user_agent(Some(&user_agent));
debug!("Initialized new soup session with user agent \"{}\"", user_agent);
Self { session }
}
// TODO: use Url here instead of String
pub async fn download_favicon(self, url: String, size: i32) -> Result<Pixbuf, Error>{
match soup::Message::new("GET", &url.to_string()){
Some(message) => {
// Send created message
let input_stream = self.session.send_async_future(&message).await?;
// Create DataInputStream and read read received data
let data_input_stream: DataInputStream = gio::DataInputStream::new(&input_stream);
// Create pixbuf
let pixbuf = Pixbuf::new_from_stream_at_scale_async_future(&data_input_stream, size, size, true).await?;
Ok(pixbuf)
},
// Return error when message cannot be created
None => Err(Error::SoupMessageError),
}
}
}
......@@ -4,6 +4,7 @@ static PLAYABLE_STATION_URL: &'static str = "json/url/";
mod client;
mod error;
mod favicon_downloader;
mod object;
mod station;
mod station_request;
......@@ -11,6 +12,7 @@ mod station_url;
pub use client::Client;
pub use error::Error;
pub use favicon_downloader::FaviconDownloader;
pub use object::Object;
pub use station::Station;
pub use station_request::StationRequest;
......
......@@ -94,7 +94,7 @@ impl Search {
get_widget!(self.builder, gtk::SearchEntry, search_entry);
let sender = self.sender.clone();
search_entry.connect_search_changed(move |entry| {
let request = StationRequest::search_for_name(&entry.get_text().unwrap(), 500);
let request = StationRequest::search_for_name(&entry.get_text().unwrap(), 250);
sender.send(Action::SearchFor(request)).unwrap();
});
}
......
......@@ -42,6 +42,7 @@ run_command(
sources = files(
'api/client.rs',
'api/error.rs',
'api/favicon_downloader.rs',
'api/mod.rs',
'api/object.rs',
'api/station.rs',
......
......@@ -5,7 +5,7 @@ use indexmap::IndexMap;
use std::cell::RefCell;
use std::convert::TryInto;
use crate::api::Station;
use crate::api::{Station, FaviconDownloader};
use crate::app::Action;
use crate::ui::station_row::StationRow;
use crate::utils;
......@@ -14,6 +14,7 @@ use crate::utils::{Order, Sorting};
pub struct StationFlowBox {
pub widget: gtk::FlowBox,
stations: RefCell<IndexMap<i32, Station>>,
favicon_downloader: FaviconDownloader,
sorting: RefCell<Sorting>,
order: RefCell<Order>,
......@@ -27,6 +28,8 @@ impl StationFlowBox {
get_widget!(builder, gtk::FlowBox, station_flowbox);
let stations = RefCell::new(IndexMap::new());
let favicon_downloader = FaviconDownloader::new();
let sorting = RefCell::new(Sorting::Default);
let order = RefCell::new(Order::Ascending);
......@@ -48,6 +51,7 @@ impl StationFlowBox {
Self {
widget: station_flowbox,
stations,
favicon_downloader,
sorting,
order,
sender,
......@@ -109,8 +113,9 @@ impl StationFlowBox {
let widget = self.widget.downgrade();
let sender = self.sender.clone();
let favicon_downloader = self.favicon_downloader.clone();
let stations = self.stations.borrow().clone();
let constructor = move |station: (i32, Station)| StationRow::new(sender.clone(), station.1).widget.clone();
let constructor = move |station: (i32, Station)| StationRow::new(sender.clone(), favicon_downloader.clone(), station.1).widget.clone();
// Start lazy loading
utils::lazy_load(stations.clone(), widget.clone(), constructor.clone());
......
use glib::Sender;
use gtk::prelude::*;
use glib::futures::FutureExt;
use crate::api::Station;
use crate::api::{Station, FaviconDownloader};
use crate::app::Action;
use crate::ui::station_dialog::StationDialog;
......@@ -15,7 +16,7 @@ pub struct StationRow {
}
impl StationRow {
pub fn new(sender: Sender<Action>, station: Station) -> Self {
pub fn new(sender: Sender<Action>, favicon_downloader: FaviconDownloader, station: Station) -> Self {
let builder = gtk::Builder::new_from_resource("/de/haeckerfelix/Shortwave/gtk/station_row.ui");
get_widget!(builder, gtk::FlowBoxChild, station_row);
let app = builder.get_application().unwrap();
......@@ -26,6 +27,14 @@ impl StationRow {
station_label.set_text(&station.name);
subtitle_label.set_text(&format!("{} {} · {} Votes", station.country, station.state, station.votes));
// Download & set station favicon
get_widget!(builder, gtk::Image, station_favicon);
let fut = favicon_downloader.download_favicon(station.favicon.clone(), 60).map(move|pixbuf|{
pixbuf.map(|pixbuf| station_favicon.set_from_pixbuf(Some(&pixbuf)));
});
let ctx = glib::MainContext::default();
ctx.spawn_local(fut);
let stationrow = Self {
widget: station_row,
station,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment