From 1e61f5d569a0519240ffbef4d13b6bf846accb5c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?No=C3=ABlle?= <27908024+jannuary@users.noreply.github.com>
Date: Tue, 9 Nov 2021 21:56:43 +0700
Subject: [PATCH 01/44] dev: use latest GTK/adwaita (master runtime) (#365)
---
Cargo.toml | 6 ++--
dev.alextren.Spot.develoment.json | 41 +-----------------------
src/app/components/album/album.ui | 7 ++--
src/app/components/playback/playback.css | 3 +-
src/main.rs | 9 ++++--
src/window.ui.in | 2 +-
6 files changed, 16 insertions(+), 52 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
index 058663ae..39896cae 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,11 +5,11 @@ edition = "2018"
license = "MIT"
[dependencies.gtk]
-version = "^0.2.0"
+version = "^0.3.0"
package = "gtk4"
[dependencies.gdk]
-version = "^0.2.0"
+version = "^0.3.0"
package = "gdk4"
[dependencies.gio]
@@ -58,7 +58,7 @@ features = ["gettext-system"]
[dependencies]
secret-service = "^2.0.1"
gdk-pixbuf = "^0.14.0"
-libadwaita = "0.1.0-alpha-2"
+libadwaita = "^0.1.0-alpha-3"
ref_filter_map = "^1.0.1"
regex = "^1.4.6"
async-std = "^1.10.0"
diff --git a/dev.alextren.Spot.develoment.json b/dev.alextren.Spot.develoment.json
index d70d5a7c..8fa7e565 100644
--- a/dev.alextren.Spot.develoment.json
+++ b/dev.alextren.Spot.develoment.json
@@ -1,7 +1,7 @@
{
"app-id": "dev.alextren.Spot",
"runtime": "org.gnome.Platform",
- "runtime-version": "40",
+ "runtime-version": "master",
"sdk": "org.gnome.Sdk",
"sdk-extensions": [
"org.freedesktop.Sdk.Extension.rust-stable"
@@ -37,45 +37,6 @@
"*.a"
],
"modules": [
- {
- "name": "libadwaita",
- "buildsystem": "meson",
- "config-opts": [
- "-Dexamples=false",
- "-Dtests=false"
- ],
- "sources": [
- {
- "type": "git",
- "url": "https://gitlab.gnome.org/GNOME/libadwaita.git",
- "branch": "1.0.0-alpha.2"
- }
- ],
- "modules": [
- {
- "name": "libsass",
- "buildsystem": "meson",
- "sources": [
- {
- "type": "git",
- "url": "https://github.com/lazka/libsass.git",
- "branch": "meson"
- }
- ]
- },
- {
- "name": "sassc",
- "buildsystem": "meson",
- "sources": [
- {
- "type": "git",
- "url": "https://github.com/lazka/sassc.git",
- "branch": "meson"
- }
- ]
- }
- ]
- },
{
"name": "spot",
"builddir": true,
diff --git a/src/app/components/album/album.ui b/src/app/components/album/album.ui
index 46e1fdf4..21d961af 100644
--- a/src/app/components/album/album.ui
+++ b/src/app/components/album/album.ui
@@ -29,10 +29,10 @@
Album
center
1
- word-char
+ word
end
1
- 2
+ 6
@@ -43,7 +43,8 @@
Artist
center
1
- word-char
+ word
+ end
1
-
\ No newline at end of file
+
From 183a835e22e116d5da557cb3e86a317d99d43950 Mon Sep 17 00:00:00 2001
From: abegert <91668665+abegert@users.noreply.github.com>
Date: Wed, 17 Nov 2021 14:12:38 +0100
Subject: [PATCH 05/44] 232 show album name in playlists and queue (#333)
* Pass worker to SongWidget so it can be later used to load song album covers
* Show cover art for each song in playlist
* Show cover art for songs per default, but not in Albums
Albums instead show the songs' index.
---
.../artist_details/artist_details.rs | 4 ++-
src/app/components/details/details.rs | 2 ++
src/app/components/navigation/factory.rs | 10 ++++--
src/app/components/now_playing/now_playing.rs | 11 ++++--
src/app/components/playlist/playlist.rs | 11 ++++--
src/app/components/playlist/song.rs | 36 ++++++++++++++++---
src/app/components/playlist/song.ui | 8 +++++
.../playlist_details/playlist_details.rs | 2 ++
.../components/saved_tracks/saved_tracks.rs | 11 ++++--
src/app/models/gtypes/song_model.rs | 30 ++++++++++++++--
src/app/models/main.rs | 1 +
11 files changed, 108 insertions(+), 18 deletions(-)
diff --git a/src/app/components/artist_details/artist_details.rs b/src/app/components/artist_details/artist_details.rs
index d917603c..0c180848 100644
--- a/src/app/components/artist_details/artist_details.rs
+++ b/src/app/components/artist_details/artist_details.rs
@@ -132,7 +132,7 @@ impl ArtistDetails {
if let Some(store) = model.get_list_store() {
widget.bind_artist_releases(
- worker,
+ worker.clone(),
&*store,
clone!(@weak model => move |id| {
model.open_album(id);
@@ -143,6 +143,8 @@ impl ArtistDetails {
let playlist = Box::new(Playlist::new(
widget.top_tracks_widget().clone(),
Rc::clone(&model),
+ worker,
+ true,
));
Self {
diff --git a/src/app/components/details/details.rs b/src/app/components/details/details.rs
index 82b55ec4..84a18b9f 100644
--- a/src/app/components/details/details.rs
+++ b/src/app/components/details/details.rs
@@ -185,6 +185,8 @@ impl Details {
let playlist = Box::new(Playlist::new(
widget.album_tracks_widget().clone(),
model.clone(),
+ worker.clone(),
+ false,
));
let modal = ReleaseDetailsWindow::new();
diff --git a/src/app/components/navigation/factory.rs b/src/app/components/navigation/factory.rs
index 0fe3cfa5..fb88e1ec 100644
--- a/src/app/components/navigation/factory.rs
+++ b/src/app/components/navigation/factory.rs
@@ -38,7 +38,10 @@ impl ScreenFactory {
Rc::clone(&self.app_model),
self.dispatcher.box_clone(),
));
- SelectionTools::new(NowPlaying::new(Rc::clone(&model)), model)
+ SelectionTools::new(
+ NowPlaying::new(Rc::clone(&model), self.worker.clone()),
+ model,
+ )
}
pub fn make_saved_tracks(&self) -> impl ListenerComponent {
@@ -46,7 +49,10 @@ impl ScreenFactory {
Rc::clone(&self.app_model),
self.dispatcher.box_clone(),
));
- SelectionTools::new(SavedTracks::new(Rc::clone(&model)), model)
+ SelectionTools::new(
+ SavedTracks::new(Rc::clone(&model), self.worker.clone()),
+ model,
+ )
}
pub fn make_album_details(&self, id: String) -> impl ListenerComponent {
diff --git a/src/app/components/now_playing/now_playing.rs b/src/app/components/now_playing/now_playing.rs
index 89a72844..a6c68bcb 100644
--- a/src/app/components/now_playing/now_playing.rs
+++ b/src/app/components/now_playing/now_playing.rs
@@ -4,7 +4,7 @@ use gtk::CompositeTemplate;
use std::rc::Rc;
use crate::app::components::{display_add_css_provider, Component, EventListener, Playlist};
-use crate::app::{state::PlaybackEvent, AppEvent};
+use crate::app::{state::PlaybackEvent, AppEvent, Worker};
use super::NowPlayingModel;
@@ -79,14 +79,19 @@ pub struct NowPlaying {
}
impl NowPlaying {
- pub fn new(model: Rc) -> Self {
+ pub fn new(model: Rc, worker: Worker) -> Self {
let widget = NowPlayingWidget::new();
widget.connect_bottom_edge(clone!(@weak model => move || {
model.load_more();
}));
- let playlist = Playlist::new(widget.song_list_widget().clone(), model.clone());
+ let playlist = Playlist::new(
+ widget.song_list_widget().clone(),
+ model.clone(),
+ worker,
+ true,
+ );
Self {
widget,
diff --git a/src/app/components/playlist/playlist.rs b/src/app/components/playlist/playlist.rs
index d63be6c7..ca44074d 100644
--- a/src/app/components/playlist/playlist.rs
+++ b/src/app/components/playlist/playlist.rs
@@ -8,7 +8,7 @@ use crate::app::components::{Component, EventListener, SongWidget};
use crate::app::models::SongModel;
use crate::app::{
state::{PlaybackEvent, SelectionEvent, SelectionState},
- AppEvent, ListDiff, ListStore,
+ AppEvent, ListDiff, ListStore, Worker,
};
#[derive(Clone, Copy, Debug)]
@@ -64,7 +64,12 @@ impl Playlist
where
Model: PlaylistModel + 'static,
{
- pub fn new(listview: gtk::ListView, model: Rc) -> Self {
+ pub fn new(
+ listview: gtk::ListView,
+ model: Rc,
+ worker: Worker,
+ show_song_covers: bool,
+ ) -> Self {
let list_model = ListStore::new();
let selection_model = gtk::NoSelection::new(Some(list_model.unsafe_store()));
let factory = gtk::SignalListItemFactory::new();
@@ -84,7 +89,7 @@ where
song_model.set_state(Self::get_item_state(&*model, &song_model));
let widget = item.child().unwrap().downcast::().unwrap();
- widget.bind(&song_model);
+ widget.bind(&song_model, worker.clone(), show_song_covers);
let id = &song_model.get_id();
widget.set_actions(model.actions_for(id).as_ref());
diff --git a/src/app/components/playlist/song.rs b/src/app/components/playlist/song.rs
index 3629af25..b4b45da7 100644
--- a/src/app/components/playlist/song.rs
+++ b/src/app/components/playlist/song.rs
@@ -1,6 +1,8 @@
use crate::app::components::display_add_css_provider;
+use crate::app::loader::ImageLoader;
use crate::app::models::SongModel;
+use crate::app::Worker;
use gio::MenuModel;
use gtk::prelude::*;
use gtk::subclass::prelude::*;
@@ -32,6 +34,9 @@ mod imp {
#[template_child]
pub menu_btn: TemplateChild,
+
+ #[template_child]
+ pub song_cover: TemplateChild,
}
#[glib::object_subclass]
@@ -70,9 +75,9 @@ impl SongWidget {
glib::Object::new(&[]).expect("Failed to create an instance of SongWidget")
}
- pub fn for_model(model: SongModel) -> Self {
+ pub fn for_model(model: SongModel, worker: Worker) -> Self {
let _self = Self::new();
- _self.bind(&model);
+ _self.bind(&model, worker, true);
_self
}
@@ -114,13 +119,36 @@ impl SongWidget {
}
}
- pub fn bind(&self, model: &SongModel) {
+ fn set_image(&self, pixbuf: Option<&gdk_pixbuf::Pixbuf>) {
+ imp::SongWidget::from_instance(self)
+ .song_cover
+ .set_from_pixbuf(pixbuf);
+ }
+
+ pub fn bind_art(&self, model: &SongModel, worker: Worker) {
+ if let Some(url) = model.cover_url() {
+ let _self = self.downgrade();
+ worker.send_local_task(async move {
+ if let Some(_self) = _self.upgrade() {
+ let loader = ImageLoader::new();
+ let result = loader.load_remote(&url, "jpg", 100, 100).await;
+ _self.set_image(result.as_ref());
+ }
+ });
+ }
+ }
+
+ pub fn bind(&self, model: &SongModel, worker: Worker, show_cover: bool) {
let widget = imp::SongWidget::from_instance(self);
- model.bind_index(&*widget.song_index, "label");
model.bind_title(&*widget.song_title, "label");
model.bind_artist(&*widget.song_artist, "label");
model.bind_duration(&*widget.song_length, "label");
+ if show_cover {
+ self.bind_art(model, worker);
+ } else {
+ model.bind_index(&*widget.song_index, "label");
+ }
self.set_playing(model.get_playing());
model.connect_playing_local(clone!(@weak self as _self => move |song| {
diff --git a/src/app/components/playlist/song.ui b/src/app/components/playlist/song.ui
index 717c030d..72ee808f 100644
--- a/src/app/components/playlist/song.ui
+++ b/src/app/components/playlist/song.ui
@@ -24,6 +24,14 @@
+
+
+