forked from xou816/spot
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add settings window * Remove unnecessary code * Settings changes are reflected on startup * Reflect changes on selecting a theme or closing the preferences window * Fix UI issues in settings window * Player stops when its settings changes * Add missing comment for translators * Improve UI for preferences * Remove unnecessary code * Put settings in the state * Remove redundant action * Fix unused imports * Remove extra cloning * Add paths for settings to meson.build
- Loading branch information
Showing
16 changed files
with
496 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
mod settings; | ||
mod settings_model; | ||
|
||
pub use settings::*; | ||
pub use settings_model::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
use crate::app::components::EventListener; | ||
use crate::app::AppEvent; | ||
use crate::settings::SpotSettings; | ||
|
||
use gtk::prelude::*; | ||
use gtk::subclass::prelude::*; | ||
use gtk::CompositeTemplate; | ||
use libadwaita::prelude::*; | ||
|
||
use super::SettingsModel; | ||
|
||
const SETTINGS: &str = "dev.alextren.Spot"; | ||
|
||
mod imp { | ||
|
||
use super::*; | ||
use libadwaita::subclass::prelude::*; | ||
|
||
#[derive(Debug, Default, CompositeTemplate)] | ||
#[template(resource = "/dev/alextren/Spot/components/settings.ui")] | ||
pub struct SettingsWindow { | ||
#[template_child] | ||
pub player_bitrate: TemplateChild<libadwaita::ComboRow>, | ||
|
||
#[template_child] | ||
pub alsa_device: TemplateChild<gtk::Entry>, | ||
|
||
#[template_child] | ||
pub alsa_device_row: TemplateChild<libadwaita::ActionRow>, | ||
|
||
#[template_child] | ||
pub audio_backend: TemplateChild<libadwaita::ComboRow>, | ||
|
||
#[template_child] | ||
pub ap_port: TemplateChild<gtk::Entry>, | ||
|
||
#[template_child] | ||
pub theme: TemplateChild<libadwaita::ComboRow>, | ||
} | ||
|
||
#[glib::object_subclass] | ||
impl ObjectSubclass for SettingsWindow { | ||
const NAME: &'static str = "SettingsWindow"; | ||
type Type = super::SettingsWindow; | ||
type ParentType = libadwaita::PreferencesWindow; | ||
|
||
fn class_init(klass: &mut Self::Class) { | ||
Self::bind_template(klass); | ||
} | ||
|
||
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) { | ||
obj.init_template(); | ||
} | ||
} | ||
|
||
impl ObjectImpl for SettingsWindow {} | ||
impl WidgetImpl for SettingsWindow {} | ||
impl WindowImpl for SettingsWindow {} | ||
impl AdwWindowImpl for SettingsWindow {} | ||
impl PreferencesWindowImpl for SettingsWindow {} | ||
} | ||
|
||
glib::wrapper! { | ||
pub struct SettingsWindow(ObjectSubclass<imp::SettingsWindow>) @extends gtk::Widget, gtk::Window, libadwaita::Window, libadwaita::PreferencesWindow; | ||
} | ||
|
||
impl SettingsWindow { | ||
pub fn new() -> Self { | ||
let window: Self = | ||
glib::Object::new(&[]).expect("Failed to create an instance of SettingsWindow"); | ||
|
||
window.bind_backend_and_device(); | ||
window.bind_settings(); | ||
window.connect_theme_select(); | ||
window | ||
} | ||
|
||
fn bind_backend_and_device(&self) { | ||
let widget = imp::SettingsWindow::from_instance(self); | ||
|
||
let audio_backend = widget | ||
.audio_backend | ||
.downcast_ref::<libadwaita::ComboRow>() | ||
.unwrap(); | ||
let alsa_device_row = widget | ||
.alsa_device_row | ||
.downcast_ref::<libadwaita::ActionRow>() | ||
.unwrap(); | ||
|
||
audio_backend | ||
.bind_property("selected", alsa_device_row, "visible") | ||
.transform_to(|_, value| value.get::<u32>().ok().map(|u| (u == 1).to_value())) | ||
.build(); | ||
|
||
if audio_backend.selected() == 0 { | ||
alsa_device_row.set_visible(false); | ||
} | ||
} | ||
|
||
fn bind_settings(&self) { | ||
let widget = imp::SettingsWindow::from_instance(self); | ||
let settings = gio::Settings::new(SETTINGS); | ||
|
||
let player_bitrate = widget | ||
.player_bitrate | ||
.downcast_ref::<libadwaita::ComboRow>() | ||
.unwrap(); | ||
settings | ||
.bind("player-bitrate", player_bitrate, "selected") | ||
.mapping(|variant, _| { | ||
variant.str().map(|s| { | ||
match s { | ||
"96" => 0, | ||
"160" => 1, | ||
"320" => 2, | ||
_ => unreachable!(), | ||
} | ||
.to_value() | ||
}) | ||
}) | ||
.set_mapping(|value, _| { | ||
value.get::<u32>().ok().map(|u| { | ||
match u { | ||
0 => "96", | ||
1 => "160", | ||
2 => "320", | ||
_ => unreachable!(), | ||
} | ||
.to_variant() | ||
}) | ||
}) | ||
.build(); | ||
|
||
let alsa_device = widget.alsa_device.downcast_ref::<gtk::Entry>().unwrap(); | ||
settings.bind("alsa-device", alsa_device, "text").build(); | ||
|
||
let audio_backend = widget | ||
.audio_backend | ||
.downcast_ref::<libadwaita::ComboRow>() | ||
.unwrap(); | ||
settings | ||
.bind("audio-backend", audio_backend, "selected") | ||
.mapping(|variant, _| { | ||
variant.str().map(|s| { | ||
match s { | ||
"pulseaudio" => 0, | ||
"alsa" => 1, | ||
_ => unreachable!(), | ||
} | ||
.to_value() | ||
}) | ||
}) | ||
.set_mapping(|value, _| { | ||
value.get::<u32>().ok().map(|u| { | ||
match u { | ||
0 => "pulseaudio", | ||
1 => "alsa", | ||
_ => unreachable!(), | ||
} | ||
.to_variant() | ||
}) | ||
}) | ||
.build(); | ||
|
||
let ap_port = widget.ap_port.downcast_ref::<gtk::Entry>().unwrap(); | ||
settings | ||
.bind("ap-port", ap_port, "text") | ||
.mapping(|variant, _| variant.get::<u32>().map(|s| s.to_value())) | ||
.set_mapping(|value, _| value.get::<u32>().ok().map(|u| u.to_variant())) | ||
.build(); | ||
|
||
let theme = widget.theme.downcast_ref::<libadwaita::ComboRow>().unwrap(); | ||
settings | ||
.bind("prefers-dark-theme", theme, "selected") | ||
.mapping(|variant, _| { | ||
variant | ||
.get::<bool>() | ||
.map(|prefer_dark| if prefer_dark { 1 } else { 0 }.to_value()) | ||
}) | ||
.set_mapping(|value, _| value.get::<u32>().ok().map(|u| (u == 1).to_variant())) | ||
.build(); | ||
} | ||
|
||
fn connect_theme_select(&self) { | ||
let widget = imp::SettingsWindow::from_instance(self); | ||
let theme = widget.theme.downcast_ref::<libadwaita::ComboRow>().unwrap(); | ||
theme.connect_selected_notify(|theme| { | ||
let prefers_dark_theme = theme.selected() == 1; | ||
let manager = libadwaita::StyleManager::default(); | ||
|
||
manager.set_color_scheme(if prefers_dark_theme { | ||
libadwaita::ColorScheme::PreferDark | ||
} else { | ||
libadwaita::ColorScheme::PreferLight | ||
}); | ||
}); | ||
} | ||
|
||
fn connect_close<F>(&self, on_close: F) | ||
where | ||
F: Fn() + 'static, | ||
{ | ||
let window = self.upcast_ref::<libadwaita::Window>(); | ||
|
||
window.connect_close_request( | ||
clone!(@weak self as _self => @default-return gtk::Inhibit(false), move |_| { | ||
on_close(); | ||
gtk::Inhibit(false) | ||
}), | ||
); | ||
} | ||
} | ||
|
||
pub struct Settings { | ||
parent: gtk::Window, | ||
settings_window: SettingsWindow, | ||
} | ||
|
||
impl Settings { | ||
pub fn new(parent: gtk::Window, model: SettingsModel) -> Self { | ||
let settings_window = SettingsWindow::new(); | ||
|
||
settings_window.connect_close(move || { | ||
let new_settings = SpotSettings::new_from_gsettings().unwrap_or_default(); | ||
if model.settings().player_settings != new_settings.player_settings { | ||
model.stop_player(); | ||
} | ||
model.set_settings(); | ||
}); | ||
|
||
Self { | ||
parent, | ||
settings_window, | ||
} | ||
} | ||
|
||
fn window(&self) -> &libadwaita::Window { | ||
self.settings_window.upcast_ref::<libadwaita::Window>() | ||
} | ||
|
||
pub fn show_self(&self) { | ||
self.window().set_transient_for(Some(&self.parent)); | ||
self.window().set_modal(true); | ||
self.window().show(); | ||
} | ||
} | ||
|
||
impl EventListener for Settings { | ||
fn on_event(&mut self, _: &AppEvent) {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<interface> | ||
<requires lib="gtk" version="4.0" /> | ||
<requires lib="libadwaita" version="1.0" /> | ||
<template class="SettingsWindow" parent="AdwPreferencesWindow"> | ||
<property name="default-width">600</property> | ||
<property name="hide-on-close">1</property> | ||
<property name="search-enabled">0</property> | ||
<child> | ||
<object class="AdwPreferencesPage"> | ||
<child> | ||
<object class="AdwPreferencesGroup"> | ||
<property name="title" translatable="yes" comments="Header for a group of preference items regarding audio">Audio</property> | ||
<child> | ||
<object class="AdwComboRow" id="audio_backend"> | ||
<property name="title" translatable="yes" comments="Title for an item in preferences">Audio Backend</property> | ||
<property name="model"> | ||
<object class="GtkStringList"> | ||
<items> | ||
<item>PulseAudio</item> | ||
<item>ALSA</item> | ||
</items> | ||
</object> | ||
</property> | ||
</object> | ||
</child> | ||
<child> | ||
<object class="AdwActionRow" id="alsa_device_row"> | ||
<property name="title" translatable="yes" comments="Title for an item in preferences">ALSA Device</property> | ||
<property name="subtitle" translatable="yes" comments="Description for the item (ALSA Device) in preferences">Applied only if audio backend is ALSA</property> | ||
<child> | ||
<object class="GtkEntry" id="alsa_device"> | ||
<property name="valign">center</property> | ||
</object> | ||
</child> | ||
</object> | ||
</child> | ||
<child> | ||
<object class="AdwComboRow" id="player_bitrate"> | ||
<property name="title" translatable="yes" comments="Title for an item in preferences">Audio Quality</property> | ||
<property name="model"> | ||
<object class="GtkStringList"> | ||
<items> | ||
<item translatable="yes">Normal</item> | ||
<item translatable="yes">High</item> | ||
<item translatable="yes">Very high</item> | ||
</items> | ||
</object> | ||
</property> | ||
</object> | ||
</child> | ||
</object> | ||
</child> | ||
<child> | ||
<object class="AdwPreferencesGroup"> | ||
<property name="title" translatable="yes" comments="Header for a group of preference items regarding the application's appearance">Appearance</property> | ||
<child> | ||
<object class="AdwComboRow" id="theme"> | ||
<property name="title" translatable="yes" comments="Title for an item in preferences">Theme</property> | ||
<property name="model"> | ||
<object class="GtkStringList"> | ||
<items> | ||
<item translatable="yes">Light</item> | ||
<item translatable="yes">Dark</item> | ||
</items> | ||
</object> | ||
</property> | ||
</object> | ||
</child> | ||
</object> | ||
</child> | ||
<child> | ||
<object class="AdwPreferencesGroup"> | ||
<property name="title" translatable="yes" comments="Header for a group of preference items regarding network">Network</property> | ||
<child> | ||
<object class="AdwActionRow"> | ||
<property name="title" translatable="yes" comments="Title for an item in preferences">Access Point Port</property> | ||
<property name="subtitle" translatable="yes" comments="Longer description for an item (Access Point Port) in preferences">Port used for connections to Spotify's Access Point. Set to 0 if any port is fine.</property> | ||
<child> | ||
<object class="GtkEntry" id="ap_port"> | ||
<property name="valign">center</property> | ||
</object> | ||
</child> | ||
</object> | ||
</child> | ||
</object> | ||
</child> | ||
</object> | ||
</child> | ||
</template> | ||
</interface> |
Oops, something went wrong.