mirror of
https://github.com/johrpan/musicus.git
synced 2025-10-26 19:57:25 +01:00
Remove server synchronization code
This commit (tries to) remove all code for synchronyzing to a music metadata server. Because the intended use cases of the application have shifted over time, this isn't a central feature anymore. However, it may well be decided to reintroduce the functionality at some point in the future.
This commit is contained in:
parent
384ca255f3
commit
f165c6cae8
48 changed files with 96 additions and 2633 deletions
|
|
@ -5,17 +5,5 @@
|
|||
<default>""</default>
|
||||
<summary>Path to the music library folder</summary>
|
||||
</key>
|
||||
<key name="server-url" type="s">
|
||||
<default>"https://wolfgang.johrpan.de"</default>
|
||||
<summary>URL of the Wolfgang server to use</summary>
|
||||
</key>
|
||||
<key name="use-server" type="b">
|
||||
<default>true</default>
|
||||
<summary>Whether to use the Wolfgang server</summary>
|
||||
<description>
|
||||
This setting determines whether the Wolfgang server will be used for
|
||||
finding new items as well as to upload new additions and edits.
|
||||
</description>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
<gresource prefix="/de/johrpan/musicus">
|
||||
<file preprocess="xml-stripblanks">ui/editor.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/import_screen.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/login_dialog.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/main_screen.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/medium_editor.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/medium_preview.ui</file>
|
||||
|
|
@ -16,7 +15,6 @@
|
|||
<file preprocess="xml-stripblanks">ui/screen.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/section.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/selector.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/server_dialog.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/source_selector.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/track_editor.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/track_selector.ui</file>
|
||||
|
|
|
|||
|
|
@ -45,12 +45,6 @@
|
|||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="server_check_button">
|
||||
<property name="label" translatable="yes">Use the Musicus server</property>
|
||||
<property name="active">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
|
|
|
|||
|
|
@ -1,223 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<requires lib="libadwaita" version="1.0"/>
|
||||
<object class="GtkStack" id="widget">
|
||||
<property name="transition-type">crossfade</property>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">content</property>
|
||||
<property name="child">
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="AdwHeaderBar">
|
||||
<property name="show-start-title-buttons">false</property>
|
||||
<property name="show-end-title-buttons">false</property>
|
||||
<property name="title-widget">
|
||||
<object class="GtkLabel">
|
||||
</object>
|
||||
</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="cancel_button">
|
||||
<property name="label" translatable="yes">Cancel</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="end">
|
||||
<object class="GtkButton" id="login_button">
|
||||
<property name="label" translatable="yes">Login</property>
|
||||
<style>
|
||||
<class name="suggested-action"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkInfoBar" id="info_bar">
|
||||
<property name="revealed">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="vexpand">true</property>
|
||||
<child>
|
||||
<object class="AdwClamp">
|
||||
<property name="margin-start">12</property>
|
||||
<property name="margin-end">12</property>
|
||||
<property name="margin-top">18</property>
|
||||
<property name="margin-bottom">12</property>
|
||||
<property name="maximum-size">800</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Login to existing account</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="valign">start</property>
|
||||
<child>
|
||||
<object class="GtkListBox">
|
||||
<property name="selection-mode">none</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="focusable">False</property>
|
||||
<property name="title" translatable="yes">Username</property>
|
||||
<property name="activatable-widget">username_entry</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="username_entry">
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="focusable">False</property>
|
||||
<property name="title" translatable="yes">Password</property>
|
||||
<property name="activatable-widget">password_entry</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="password_entry">
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="visibility">False</property>
|
||||
<property name="input-purpose">password</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="register_box">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Create a new account</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="valign">start</property>
|
||||
<child>
|
||||
<object class="GtkListBox">
|
||||
<property name="selection-mode">none</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="focusable">False</property>
|
||||
<property name="title" translatable="yes">Register a new account</property>
|
||||
<property name="activatable-widget">register_button</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="register_button">
|
||||
<property name="label" translatable="yes">Start</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="logout_box">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">12</property>
|
||||
<property name="visible">false</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Logout</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="valign">start</property>
|
||||
<child>
|
||||
<object class="GtkListBox">
|
||||
<property name="selection-mode">none</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="focusable">False</property>
|
||||
<property name="title" translatable="yes">Don't use an account</property>
|
||||
<property name="activatable-widget">logout_button</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="logout_button">
|
||||
<property name="label" translatable="yes">Logout</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">loading</property>
|
||||
<property name="child">
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="AdwHeaderBar">
|
||||
<property name="show-start-title-buttons">false</property>
|
||||
<property name="show-end-title-buttons">false</property>
|
||||
<property name="title-widget">
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Login</property>
|
||||
<style>
|
||||
<class name="title"/>
|
||||
</style>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinner">
|
||||
<property name="spinning">true</property>
|
||||
<property name="hexpand">true</property>
|
||||
<property name="vexpand">true</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
|
|
@ -82,19 +82,6 @@
|
|||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="focusable">False</property>
|
||||
<property name="title" translatable="yes">Publish to the server</property>
|
||||
<property name="activatable-widget">publish_switch</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="publish_switch">
|
||||
<property name="valign">center</property>
|
||||
<property name="active">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
|||
|
|
@ -29,49 +29,7 @@
|
|||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
<property name="title" translatable="yes">Server connection</property>
|
||||
<child>
|
||||
<object class="AdwActionRow" id="url_row">
|
||||
<property name="focusable">False</property>
|
||||
<property name="title" translatable="yes">Server URL</property>
|
||||
<property name="activatable-widget">url_button</property>
|
||||
<property name="subtitle" translatable="yes">Not set</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="url_button">
|
||||
<property name="label" translatable="yes">Change</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow" id="login_row">
|
||||
<property name="focusable">False</property>
|
||||
<property name="title" translatable="yes">Login credentials</property>
|
||||
<property name="activatable-widget">login_button</property>
|
||||
<property name="subtitle" translatable="yes">Not logged in</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="login_button">
|
||||
<property name="label" translatable="yes">Change</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkSizeGroup">
|
||||
<widgets>
|
||||
<widget name="select_music_library_path_button"/>
|
||||
<widget name="url_button"/>
|
||||
<widget name="login_button"/>
|
||||
</widgets>
|
||||
</object>
|
||||
</interface>
|
||||
|
|
|
|||
|
|
@ -99,19 +99,6 @@
|
|||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="focusable">False</property>
|
||||
<property name="title" translatable="yes">Publish to the server</property>
|
||||
<property name="activatable-widget">upload_switch</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="upload_switch">
|
||||
<property name="valign">center</property>
|
||||
<property name="active">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
|||
|
|
@ -60,13 +60,6 @@
|
|||
<property name="placeholder-text" translatable="yes">Search …</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="server_check_button">
|
||||
<property name="label" translatable="yes">Use the Musicus server</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="active">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
@ -118,57 +111,6 @@
|
|||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">error</property>
|
||||
<property name="child">
|
||||
<object class="GtkBox">
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-start">18</property>
|
||||
<property name="margin-end">18</property>
|
||||
<property name="margin-top">18</property>
|
||||
<property name="margin-bottom">18</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">18</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="opacity">0.5</property>
|
||||
<property name="pixel-size">80</property>
|
||||
<property name="icon-name">network-error-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="opacity">0.5</property>
|
||||
<property name="label" translatable="yes">An error occured!</property>
|
||||
<attributes>
|
||||
<attribute name="size" value="16384"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="opacity">0.5</property>
|
||||
<property name="label" translatable="yes">The server was not reachable or responded with an error. Please check your internet connection.</property>
|
||||
<property name="justify">center</property>
|
||||
<property name="wrap">True</property>
|
||||
<property name="max-width-chars">40</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="try_again_button">
|
||||
<property name="label" translatable="yes">Try again</property>
|
||||
<property name="halign">center</property>
|
||||
<style>
|
||||
<class name="suggested-action"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<requires lib="libadwaita" version="1.0"/>
|
||||
<object class="AdwWindow" id="window">
|
||||
<property name="modal">True</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="AdwHeaderBar">
|
||||
<property name="show-start-title-buttons">false</property>
|
||||
<property name="show-end-title-buttons">false</property>
|
||||
<property name="title-widget">
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Server</property>
|
||||
<style>
|
||||
<class name="title"/>
|
||||
</style>
|
||||
</object>
|
||||
</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="cancel_button">
|
||||
<property name="label" translatable="yes">Cancel</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="end">
|
||||
<object class="GtkButton" id="set_button">
|
||||
<property name="label" translatable="yes">Set</property>
|
||||
<property name="has-default">True</property>
|
||||
<style>
|
||||
<class name="suggested-action"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkListBox">
|
||||
<property name="selection-mode">none</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="focusable">False</property>
|
||||
<property name="title" translatable="yes">URL</property>
|
||||
<property name="activatable-widget">url_entry</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="url_entry">
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<requires lib="libadwaita" version="1.0"/>
|
||||
<requires lib="gtk" version="4.0" />
|
||||
<requires lib="libadwaita" version="1.0" />
|
||||
<object class="GtkStack" id="widget">
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
|
|
@ -17,13 +17,13 @@
|
|||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Work</property>
|
||||
<style>
|
||||
<class name="title"/>
|
||||
<class name="title" />
|
||||
</style>
|
||||
</object>
|
||||
</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="back_button">
|
||||
<property name="icon-name">go-previous-symbolic</property>
|
||||
<property name="icon-name">go-previous-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="end">
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
<property name="sensitive">False</property>
|
||||
<property name="icon-name">object-select-symbolic</property>
|
||||
<style>
|
||||
<class name="suggested-action"/>
|
||||
<class name="suggested-action" />
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
|
|
@ -64,7 +64,7 @@
|
|||
<property name="margin-bottom">6</property>
|
||||
<property name="label" translatable="yes">Overview</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
<attribute name="weight" value="bold" />
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
|
|
@ -99,19 +99,6 @@
|
|||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="focusable">False</property>
|
||||
<property name="title" translatable="yes">Publish to the server</property>
|
||||
<property name="activatable-widget">upload_switch</property>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="upload_switch">
|
||||
<property name="valign">center</property>
|
||||
<property name="active">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
@ -128,7 +115,7 @@
|
|||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes">Instruments</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
<attribute name="weight" value="bold" />
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
|
|
@ -141,7 +128,7 @@
|
|||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame" id="instrument_frame"/>
|
||||
<object class="GtkFrame" id="instrument_frame" />
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
|
|
@ -155,7 +142,7 @@
|
|||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes">Structure</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
<attribute name="weight" value="bold" />
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
|
|
@ -174,7 +161,7 @@
|
|||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame" id="structure_frame"/>
|
||||
<object class="GtkFrame" id="structure_frame" />
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
|
@ -200,7 +187,7 @@
|
|||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Work</property>
|
||||
<style>
|
||||
<class name="title"/>
|
||||
<class name="title" />
|
||||
</style>
|
||||
</object>
|
||||
</property>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::{Editor, EntryRow, Section, UploadSection, Widget};
|
||||
use crate::widgets::{Editor, EntryRow, Section, Widget};
|
||||
use anyhow::Result;
|
||||
use gettextrs::gettext;
|
||||
use glib::clone;
|
||||
|
|
@ -16,7 +16,6 @@ pub struct EnsembleEditor {
|
|||
|
||||
editor: Editor,
|
||||
name: EntryRow,
|
||||
upload: Rc<UploadSection>,
|
||||
}
|
||||
|
||||
impl Screen<Option<Ensemble>, Ensemble> for EnsembleEditor {
|
||||
|
|
@ -33,10 +32,7 @@ impl Screen<Option<Ensemble>, Ensemble> for EnsembleEditor {
|
|||
list.append(&name.widget);
|
||||
|
||||
let section = Section::new(&gettext("General"), &list);
|
||||
let upload = UploadSection::new(Rc::clone(&handle.backend));
|
||||
|
||||
editor.add_content(§ion.widget);
|
||||
editor.add_content(&upload.widget);
|
||||
|
||||
let id = match ensemble {
|
||||
Some(ensemble) => {
|
||||
|
|
@ -51,7 +47,6 @@ impl Screen<Option<Ensemble>, Ensemble> for EnsembleEditor {
|
|||
id,
|
||||
editor,
|
||||
name,
|
||||
upload,
|
||||
});
|
||||
|
||||
// Connect signals and callbacks
|
||||
|
|
@ -91,7 +86,7 @@ impl EnsembleEditor {
|
|||
self.editor.set_may_save(!self.name.get_text().is_empty());
|
||||
}
|
||||
|
||||
/// Save the ensemble and possibly upload it to the server.
|
||||
/// Save the ensemble.
|
||||
async fn save(&self) -> Result<Ensemble> {
|
||||
let name = self.name.get_text();
|
||||
|
||||
|
|
@ -100,15 +95,12 @@ impl EnsembleEditor {
|
|||
name,
|
||||
};
|
||||
|
||||
if self.upload.get_active() {
|
||||
self.handle.backend.cl().post_ensemble(&ensemble).await?;
|
||||
}
|
||||
|
||||
self.handle
|
||||
.backend
|
||||
.db()
|
||||
.update_ensemble(ensemble.clone())
|
||||
.await?;
|
||||
|
||||
self.handle.backend.library_changed();
|
||||
|
||||
Ok(ensemble)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::{Editor, EntryRow, Section, UploadSection, Widget};
|
||||
use crate::widgets::{Editor, EntryRow, Section, Widget};
|
||||
use anyhow::Result;
|
||||
use gettextrs::gettext;
|
||||
use glib::clone;
|
||||
|
|
@ -16,7 +16,6 @@ pub struct InstrumentEditor {
|
|||
|
||||
editor: Editor,
|
||||
name: EntryRow,
|
||||
upload: Rc<UploadSection>,
|
||||
}
|
||||
|
||||
impl Screen<Option<Instrument>, Instrument> for InstrumentEditor {
|
||||
|
|
@ -33,10 +32,7 @@ impl Screen<Option<Instrument>, Instrument> for InstrumentEditor {
|
|||
list.append(&name.widget);
|
||||
|
||||
let section = Section::new(&gettext("General"), &list);
|
||||
let upload = UploadSection::new(Rc::clone(&handle.backend));
|
||||
|
||||
editor.add_content(§ion.widget);
|
||||
editor.add_content(&upload.widget);
|
||||
|
||||
let id = match instrument {
|
||||
Some(instrument) => {
|
||||
|
|
@ -51,7 +47,6 @@ impl Screen<Option<Instrument>, Instrument> for InstrumentEditor {
|
|||
id,
|
||||
editor,
|
||||
name,
|
||||
upload,
|
||||
});
|
||||
|
||||
// Connect signals and callbacks
|
||||
|
|
@ -91,7 +86,7 @@ impl InstrumentEditor {
|
|||
self.editor.set_may_save(!self.name.get_text().is_empty());
|
||||
}
|
||||
|
||||
/// Save the instrument and possibly upload it to the server.
|
||||
/// Save the instrument.
|
||||
async fn save(&self) -> Result<Instrument> {
|
||||
let name = self.name.get_text();
|
||||
|
||||
|
|
@ -100,19 +95,12 @@ impl InstrumentEditor {
|
|||
name,
|
||||
};
|
||||
|
||||
if self.upload.get_active() {
|
||||
self.handle
|
||||
.backend
|
||||
.cl()
|
||||
.post_instrument(&instrument)
|
||||
.await?;
|
||||
}
|
||||
|
||||
self.handle
|
||||
.backend
|
||||
.db()
|
||||
.update_instrument(instrument.clone())
|
||||
.await?;
|
||||
|
||||
self.handle.backend.library_changed();
|
||||
|
||||
Ok(instrument)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::{Editor, EntryRow, Section, UploadSection, Widget};
|
||||
use crate::widgets::{Editor, EntryRow, Section, Widget};
|
||||
use anyhow::Result;
|
||||
use gettextrs::gettext;
|
||||
use glib::clone;
|
||||
|
|
@ -17,7 +17,6 @@ pub struct PersonEditor {
|
|||
editor: Editor,
|
||||
first_name: EntryRow,
|
||||
last_name: EntryRow,
|
||||
upload: Rc<UploadSection>,
|
||||
}
|
||||
|
||||
impl Screen<Option<Person>, Person> for PersonEditor {
|
||||
|
|
@ -37,10 +36,7 @@ impl Screen<Option<Person>, Person> for PersonEditor {
|
|||
list.append(&last_name.widget);
|
||||
|
||||
let section = Section::new(&gettext("General"), &list);
|
||||
let upload = UploadSection::new(Rc::clone(&handle.backend));
|
||||
|
||||
editor.add_content(§ion.widget);
|
||||
editor.add_content(&upload.widget);
|
||||
|
||||
let id = match person {
|
||||
Some(person) => {
|
||||
|
|
@ -58,7 +54,6 @@ impl Screen<Option<Person>, Person> for PersonEditor {
|
|||
editor,
|
||||
first_name,
|
||||
last_name,
|
||||
upload,
|
||||
});
|
||||
|
||||
// Connect signals and callbacks
|
||||
|
|
@ -104,7 +99,7 @@ impl PersonEditor {
|
|||
);
|
||||
}
|
||||
|
||||
/// Save the person and possibly upload it to the server.
|
||||
/// Save the person.
|
||||
async fn save(self: &Rc<Self>) -> Result<Person> {
|
||||
let first_name = self.first_name.get_text();
|
||||
let last_name = self.last_name.get_text();
|
||||
|
|
@ -115,10 +110,6 @@ impl PersonEditor {
|
|||
last_name,
|
||||
};
|
||||
|
||||
if self.upload.get_active() {
|
||||
self.handle.backend.cl().post_person(&person).await?;
|
||||
}
|
||||
|
||||
self.handle
|
||||
.backend
|
||||
.db()
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ pub struct RecordingEditor {
|
|||
info_bar: gtk::InfoBar,
|
||||
work_row: adw::ActionRow,
|
||||
comment_entry: gtk::Entry,
|
||||
upload_switch: gtk::Switch,
|
||||
performance_list: Rc<List>,
|
||||
id: String,
|
||||
work: RefCell<Option<Work>>,
|
||||
|
|
@ -40,12 +39,9 @@ impl Screen<Option<Recording>, Recording> for RecordingEditor {
|
|||
get_widget!(builder, adw::ActionRow, work_row);
|
||||
get_widget!(builder, gtk::Button, work_button);
|
||||
get_widget!(builder, gtk::Entry, comment_entry);
|
||||
get_widget!(builder, gtk::Switch, upload_switch);
|
||||
get_widget!(builder, gtk::Frame, performance_frame);
|
||||
get_widget!(builder, gtk::Button, add_performer_button);
|
||||
|
||||
upload_switch.set_active(handle.backend.use_server());
|
||||
|
||||
let performance_list = List::new();
|
||||
performance_frame.set_child(Some(&performance_list.widget));
|
||||
|
||||
|
|
@ -64,7 +60,6 @@ impl Screen<Option<Recording>, Recording> for RecordingEditor {
|
|||
info_bar,
|
||||
work_row,
|
||||
comment_entry,
|
||||
upload_switch,
|
||||
performance_list,
|
||||
id,
|
||||
work: RefCell::new(work),
|
||||
|
|
@ -183,7 +178,7 @@ impl RecordingEditor {
|
|||
self.save_button.set_sensitive(true);
|
||||
}
|
||||
|
||||
/// Save the recording and possibly upload it to the server.
|
||||
/// Save the recording.
|
||||
async fn save(self: &Rc<Self>) -> Result<Recording> {
|
||||
let recording = Recording {
|
||||
id: self.id.clone(),
|
||||
|
|
@ -196,11 +191,6 @@ impl RecordingEditor {
|
|||
performances: self.performances.borrow().clone(),
|
||||
};
|
||||
|
||||
let upload = self.upload_switch.state();
|
||||
if upload {
|
||||
self.handle.backend.cl().post_recording(&recording).await?;
|
||||
}
|
||||
|
||||
self.handle
|
||||
.backend
|
||||
.db()
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ pub struct WorkEditor {
|
|||
title_entry: gtk::Entry,
|
||||
info_bar: gtk::InfoBar,
|
||||
composer_row: adw::ActionRow,
|
||||
upload_switch: gtk::Switch,
|
||||
instrument_list: Rc<List>,
|
||||
part_list: Rc<List>,
|
||||
id: String,
|
||||
|
|
@ -59,7 +58,6 @@ impl Screen<Option<Work>, Work> for WorkEditor {
|
|||
get_widget!(builder, gtk::Entry, title_entry);
|
||||
get_widget!(builder, gtk::Button, composer_button);
|
||||
get_widget!(builder, adw::ActionRow, composer_row);
|
||||
get_widget!(builder, gtk::Switch, upload_switch);
|
||||
get_widget!(builder, gtk::Frame, instrument_frame);
|
||||
get_widget!(builder, gtk::Button, add_instrument_button);
|
||||
get_widget!(builder, gtk::Frame, structure_frame);
|
||||
|
|
@ -92,8 +90,6 @@ impl Screen<Option<Work>, Work> for WorkEditor {
|
|||
None => (generate_id(), None, Vec::new(), Vec::new()),
|
||||
};
|
||||
|
||||
upload_switch.set_active(handle.backend.use_server());
|
||||
|
||||
let this = Rc::new(Self {
|
||||
handle,
|
||||
widget,
|
||||
|
|
@ -102,7 +98,6 @@ impl Screen<Option<Work>, Work> for WorkEditor {
|
|||
info_bar,
|
||||
title_entry,
|
||||
composer_row,
|
||||
upload_switch,
|
||||
instrument_list,
|
||||
part_list,
|
||||
composer: RefCell::new(composer),
|
||||
|
|
@ -317,7 +312,7 @@ impl WorkEditor {
|
|||
.set_sensitive(!self.title_entry.text().is_empty() && self.composer.borrow().is_some());
|
||||
}
|
||||
|
||||
/// Save the work and possibly upload it to the server.
|
||||
/// Save the work.
|
||||
async fn save(self: &Rc<Self>) -> Result<Work> {
|
||||
let mut section_count: usize = 0;
|
||||
let mut parts = Vec::new();
|
||||
|
|
@ -348,11 +343,6 @@ impl WorkEditor {
|
|||
sections,
|
||||
};
|
||||
|
||||
let upload = self.upload_switch.state();
|
||||
if upload {
|
||||
self.handle.backend.cl().post_work(&work).await?;
|
||||
}
|
||||
|
||||
self.handle
|
||||
.backend
|
||||
.db()
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ use glib::clone;
|
|||
use gtk_macros::get_widget;
|
||||
use musicus_backend::db::Medium;
|
||||
use musicus_backend::import::ImportSession;
|
||||
use musicus_backend::Error;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
|
@ -17,24 +16,19 @@ pub struct ImportScreen {
|
|||
handle: NavigationHandle<()>,
|
||||
session: Arc<ImportSession>,
|
||||
widget: gtk::Box,
|
||||
server_check_button: gtk::CheckButton,
|
||||
matching_stack: gtk::Stack,
|
||||
error_row: adw::ActionRow,
|
||||
matching_list: gtk::ListBox,
|
||||
}
|
||||
|
||||
impl ImportScreen {
|
||||
/// Find matching mediums on the server.
|
||||
/// Find matching mediums in the library.
|
||||
fn load_matches(self: &Rc<Self>) {
|
||||
self.matching_stack.set_visible_child_name("loading");
|
||||
|
||||
let this = self;
|
||||
spawn!(@clone this, async move {
|
||||
let mediums: Result<Vec<Medium>, Error> = if this.server_check_button.is_active() {
|
||||
this.handle.backend.cl().get_mediums_by_discid(this.session.source_id()).await.map_err(|err| err.into())
|
||||
} else {
|
||||
this.handle.backend.db().get_mediums_by_source_id(this.session.source_id()).await.map_err(|err| err.into())
|
||||
};
|
||||
let mediums = this.handle.backend.db().get_mediums_by_source_id(this.session.source_id()).await;
|
||||
|
||||
match mediums {
|
||||
Ok(mediums) => {
|
||||
|
|
@ -113,18 +107,14 @@ impl Screen<Arc<ImportSession>, ()> for ImportScreen {
|
|||
get_widget!(builder, gtk::Stack, matching_stack);
|
||||
get_widget!(builder, gtk::Button, try_again_button);
|
||||
get_widget!(builder, adw::ActionRow, error_row);
|
||||
get_widget!(builder, gtk::CheckButton, server_check_button);
|
||||
get_widget!(builder, gtk::ListBox, matching_list);
|
||||
get_widget!(builder, gtk::Button, select_button);
|
||||
get_widget!(builder, gtk::Button, add_button);
|
||||
|
||||
server_check_button.set_active(handle.backend.use_server());
|
||||
|
||||
let this = Rc::new(Self {
|
||||
handle,
|
||||
session,
|
||||
widget,
|
||||
server_check_button,
|
||||
matching_stack,
|
||||
error_row,
|
||||
matching_list,
|
||||
|
|
@ -136,12 +126,6 @@ impl Screen<Arc<ImportSession>, ()> for ImportScreen {
|
|||
this.handle.pop(None);
|
||||
}));
|
||||
|
||||
this.server_check_button
|
||||
.connect_toggled(clone!(@weak this => move |_| {
|
||||
this.handle.backend.set_use_server(this.server_check_button.is_active());
|
||||
this.load_matches();
|
||||
}));
|
||||
|
||||
try_again_button.connect_clicked(clone!(@weak this => move |_| {
|
||||
this.load_matches();
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ pub struct MediumEditor {
|
|||
widget: gtk::Stack,
|
||||
done_button: gtk::Button,
|
||||
name_entry: gtk::Entry,
|
||||
publish_switch: gtk::Switch,
|
||||
status_page: adw::StatusPage,
|
||||
track_set_list: Rc<List>,
|
||||
track_sets: RefCell<Vec<TrackSetData>>,
|
||||
|
|
@ -38,15 +37,12 @@ impl Screen<(Arc<ImportSession>, Option<Medium>), Medium> for MediumEditor {
|
|||
get_widget!(builder, gtk::Button, back_button);
|
||||
get_widget!(builder, gtk::Button, done_button);
|
||||
get_widget!(builder, gtk::Entry, name_entry);
|
||||
get_widget!(builder, gtk::Switch, publish_switch);
|
||||
get_widget!(builder, gtk::Button, add_button);
|
||||
get_widget!(builder, gtk::Frame, frame);
|
||||
get_widget!(builder, adw::StatusPage, status_page);
|
||||
get_widget!(builder, gtk::Button, try_again_button);
|
||||
get_widget!(builder, gtk::Button, cancel_button);
|
||||
|
||||
publish_switch.set_active(handle.backend.use_server());
|
||||
|
||||
let list = List::new();
|
||||
frame.set_child(Some(&list.widget));
|
||||
|
||||
|
|
@ -56,7 +52,6 @@ impl Screen<(Arc<ImportSession>, Option<Medium>), Medium> for MediumEditor {
|
|||
widget,
|
||||
done_button,
|
||||
name_entry,
|
||||
publish_switch,
|
||||
status_page,
|
||||
track_set_list: list,
|
||||
track_sets: RefCell::new(Vec::new()),
|
||||
|
|
@ -100,11 +95,6 @@ impl Screen<(Arc<ImportSession>, Option<Medium>), Medium> for MediumEditor {
|
|||
});
|
||||
}));
|
||||
|
||||
this.publish_switch
|
||||
.connect_state_notify(clone!(@weak this => move |_| {
|
||||
this.handle.backend.set_use_server(this.publish_switch.state());
|
||||
}));
|
||||
|
||||
this.track_set_list.set_make_widget_cb(
|
||||
clone!(@weak this => @default-panic, move |index| {
|
||||
let track_set = &this.track_sets.borrow()[index];
|
||||
|
|
@ -188,7 +178,7 @@ impl MediumEditor {
|
|||
);
|
||||
}
|
||||
|
||||
/// Create the medium and, if necessary, upload it to the server.
|
||||
/// Create the medium.
|
||||
async fn save(&self) -> Result<Medium> {
|
||||
// Convert the track set data to real track sets.
|
||||
|
||||
|
|
@ -214,11 +204,6 @@ impl MediumEditor {
|
|||
tracks,
|
||||
};
|
||||
|
||||
let upload = self.publish_switch.state();
|
||||
if upload {
|
||||
self.handle.backend.cl().post_medium(&medium).await?;
|
||||
}
|
||||
|
||||
// The medium is not added to the database, because the track paths are not known until the
|
||||
// medium is actually imported into the music library. This step will be handled by the
|
||||
// medium preview dialog.
|
||||
|
|
|
|||
|
|
@ -29,10 +29,4 @@ impl NavigatorWindow {
|
|||
|
||||
this
|
||||
}
|
||||
|
||||
/// Make the wrapped window transient. This will make the window modal.
|
||||
pub fn set_transient_for<W: IsA<gtk::Window>>(&self, window: &W) {
|
||||
self.window.set_modal(true);
|
||||
self.window.set_transient_for(Some(window));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use crate::navigator::NavigatorWindow;
|
||||
use adw::prelude::*;
|
||||
use gettextrs::gettext;
|
||||
use glib::clone;
|
||||
|
|
@ -6,21 +5,11 @@ use gtk_macros::get_widget;
|
|||
use musicus_backend::Backend;
|
||||
use std::rc::Rc;
|
||||
|
||||
mod login;
|
||||
use login::LoginDialog;
|
||||
|
||||
mod server;
|
||||
use server::ServerDialog;
|
||||
|
||||
mod register;
|
||||
|
||||
/// A dialog for configuring the app.
|
||||
pub struct Preferences {
|
||||
backend: Rc<Backend>,
|
||||
window: adw::Window,
|
||||
music_library_path_row: adw::ActionRow,
|
||||
url_row: adw::ActionRow,
|
||||
login_row: adw::ActionRow,
|
||||
}
|
||||
|
||||
impl Preferences {
|
||||
|
|
@ -32,10 +21,6 @@ impl Preferences {
|
|||
get_widget!(builder, adw::Window, window);
|
||||
get_widget!(builder, adw::ActionRow, music_library_path_row);
|
||||
get_widget!(builder, gtk::Button, select_music_library_path_button);
|
||||
get_widget!(builder, adw::ActionRow, url_row);
|
||||
get_widget!(builder, gtk::Button, url_button);
|
||||
get_widget!(builder, adw::ActionRow, login_row);
|
||||
get_widget!(builder, gtk::Button, login_button);
|
||||
|
||||
window.set_transient_for(Some(parent));
|
||||
|
||||
|
|
@ -43,8 +28,6 @@ impl Preferences {
|
|||
backend,
|
||||
window,
|
||||
music_library_path_row,
|
||||
url_row,
|
||||
login_row,
|
||||
});
|
||||
|
||||
// Connect signals and callbacks
|
||||
|
|
@ -80,31 +63,6 @@ impl Preferences {
|
|||
dialog.show();
|
||||
}));
|
||||
|
||||
url_button.connect_clicked(clone!(@strong this => move |_| {
|
||||
let dialog = ServerDialog::new(this.backend.clone(), &this.window);
|
||||
|
||||
dialog.set_selected_cb(clone!(@strong this => move |url| {
|
||||
this.url_row.set_subtitle(&url);
|
||||
}));
|
||||
|
||||
dialog.show();
|
||||
}));
|
||||
|
||||
login_button.connect_clicked(clone!(@strong this => move |_| {
|
||||
let window = NavigatorWindow::new(this.backend.clone());
|
||||
window.set_transient_for(&this.window);
|
||||
|
||||
spawn!(@clone this, async move {
|
||||
if let Some(data) = replace!(window.navigator, LoginDialog, this.backend.get_login_data()).await {
|
||||
if let Some(data) = data {
|
||||
this.login_row.set_subtitle(&data.username);
|
||||
} else {
|
||||
this.login_row.set_subtitle(&gettext("Not logged in"));
|
||||
}
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
// Initialize
|
||||
|
||||
if let Some(path) = this.backend.get_music_library_path() {
|
||||
|
|
@ -112,14 +70,6 @@ impl Preferences {
|
|||
.set_subtitle(path.to_str().unwrap());
|
||||
}
|
||||
|
||||
if let Some(url) = this.backend.get_server_url() {
|
||||
this.url_row.set_subtitle(&url);
|
||||
}
|
||||
|
||||
if let Some(data) = this.backend.get_login_data() {
|
||||
this.login_row.set_subtitle(&data.username);
|
||||
}
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
use super::register::RegisterDialog;
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::push;
|
||||
use crate::widgets::Widget;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use musicus_backend::client::LoginData;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// A dialog for entering login credentials.
|
||||
pub struct LoginDialog {
|
||||
handle: NavigationHandle<Option<LoginData>>,
|
||||
widget: gtk::Stack,
|
||||
info_bar: gtk::InfoBar,
|
||||
username_entry: gtk::Entry,
|
||||
password_entry: gtk::Entry,
|
||||
}
|
||||
|
||||
impl Screen<Option<LoginData>, Option<LoginData>> for LoginDialog {
|
||||
fn new(data: Option<LoginData>, handle: NavigationHandle<Option<LoginData>>) -> Rc<Self> {
|
||||
// Create UI
|
||||
let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/login_dialog.ui");
|
||||
|
||||
get_widget!(builder, gtk::Stack, widget);
|
||||
get_widget!(builder, gtk::InfoBar, info_bar);
|
||||
get_widget!(builder, gtk::Button, cancel_button);
|
||||
get_widget!(builder, gtk::Button, login_button);
|
||||
get_widget!(builder, gtk::Entry, username_entry);
|
||||
get_widget!(builder, gtk::Entry, password_entry);
|
||||
get_widget!(builder, gtk::Box, register_box);
|
||||
get_widget!(builder, gtk::Button, register_button);
|
||||
get_widget!(builder, gtk::Box, logout_box);
|
||||
get_widget!(builder, gtk::Button, logout_button);
|
||||
|
||||
if let Some(data) = data {
|
||||
username_entry.set_text(&data.username);
|
||||
register_box.hide();
|
||||
logout_box.show();
|
||||
}
|
||||
|
||||
let this = Rc::new(Self {
|
||||
handle,
|
||||
widget,
|
||||
info_bar,
|
||||
username_entry,
|
||||
password_entry,
|
||||
});
|
||||
|
||||
// Connect signals and callbacks
|
||||
|
||||
cancel_button.connect_clicked(clone!(@weak this => move |_| {
|
||||
this.handle.pop(None);
|
||||
}));
|
||||
|
||||
login_button.connect_clicked(clone!(@weak this => move |_| {
|
||||
this.widget.set_visible_child_name("loading");
|
||||
|
||||
let data = LoginData {
|
||||
username: this.username_entry.text().to_string(),
|
||||
password: this.password_entry.text().to_string(),
|
||||
};
|
||||
|
||||
spawn!(@clone this, async move {
|
||||
this.handle.backend.set_login_data(Some(data.clone())).await;
|
||||
if this.handle.backend.cl().login().await.unwrap() {
|
||||
this.handle.pop(Some(Some(data)));
|
||||
} else {
|
||||
this.widget.set_visible_child_name("content");
|
||||
this.info_bar.set_revealed(true);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
register_button.connect_clicked(clone!(@weak this => move |_| {
|
||||
spawn!(@clone this, async move {
|
||||
if let Some(data) = push!(this.handle, RegisterDialog).await {
|
||||
this.handle.pop(Some(Some(data)));
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
logout_button.connect_clicked(clone!(@weak this => move |_| {
|
||||
spawn!(@clone this, async move {
|
||||
this.handle.backend.set_login_data(None).await;
|
||||
this.handle.pop(Some(None));
|
||||
});
|
||||
}));
|
||||
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for LoginDialog {
|
||||
fn get_widget(&self) -> gtk::Widget {
|
||||
self.widget.clone().upcast()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::Widget;
|
||||
use adw::prelude::*;
|
||||
use glib::clone;
|
||||
use gtk_macros::get_widget;
|
||||
use musicus_backend::client::{LoginData, UserRegistration};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// A dialog for creating a new user account.
|
||||
pub struct RegisterDialog {
|
||||
handle: NavigationHandle<LoginData>,
|
||||
widget: gtk::Stack,
|
||||
username_entry: gtk::Entry,
|
||||
email_entry: gtk::Entry,
|
||||
password_entry: gtk::Entry,
|
||||
repeat_password_entry: gtk::Entry,
|
||||
captcha_row: adw::ActionRow,
|
||||
captcha_entry: gtk::Entry,
|
||||
captcha_id: RefCell<Option<String>>,
|
||||
}
|
||||
|
||||
impl Screen<(), LoginData> for RegisterDialog {
|
||||
/// Create a new register dialog.
|
||||
fn new(_: (), handle: NavigationHandle<LoginData>) -> Rc<Self> {
|
||||
// Create UI
|
||||
let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/register_dialog.ui");
|
||||
|
||||
get_widget!(builder, gtk::Stack, widget);
|
||||
get_widget!(builder, gtk::Button, cancel_button);
|
||||
get_widget!(builder, gtk::Button, register_button);
|
||||
get_widget!(builder, gtk::Entry, username_entry);
|
||||
get_widget!(builder, gtk::Entry, email_entry);
|
||||
get_widget!(builder, gtk::Entry, password_entry);
|
||||
get_widget!(builder, gtk::Entry, repeat_password_entry);
|
||||
get_widget!(builder, adw::ActionRow, captcha_row);
|
||||
get_widget!(builder, gtk::Entry, captcha_entry);
|
||||
|
||||
let this = Rc::new(Self {
|
||||
handle,
|
||||
widget,
|
||||
username_entry,
|
||||
email_entry,
|
||||
password_entry,
|
||||
repeat_password_entry,
|
||||
captcha_row,
|
||||
captcha_entry,
|
||||
captcha_id: RefCell::new(None),
|
||||
});
|
||||
|
||||
// Connect signals and callbacks
|
||||
|
||||
cancel_button.connect_clicked(clone!(@weak this => move |_| {
|
||||
this.handle.pop(None);
|
||||
}));
|
||||
|
||||
register_button.connect_clicked(clone!(@weak this => move |_| {
|
||||
let password = this.password_entry.text().to_string();
|
||||
let repeat = this.repeat_password_entry.text().to_string();
|
||||
|
||||
if password != repeat {
|
||||
// TODO: Show error and validate other input.
|
||||
} else {
|
||||
this.widget.set_visible_child_name("loading");
|
||||
|
||||
spawn!(@clone this, async move {
|
||||
let username = this.username_entry.text().to_string();
|
||||
let email = this.email_entry.text().to_string();
|
||||
let captcha_id = this.captcha_id.borrow().clone().unwrap();
|
||||
let answer = this.captcha_entry.text().to_string();
|
||||
|
||||
let email = if email.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(email)
|
||||
};
|
||||
|
||||
let registration = UserRegistration {
|
||||
username: username.clone(),
|
||||
password: password.clone(),
|
||||
email,
|
||||
captcha_id,
|
||||
answer,
|
||||
};
|
||||
|
||||
// TODO: Handle errors.
|
||||
if this.handle.backend.cl().register(registration).await.unwrap() {
|
||||
let data = LoginData {
|
||||
username,
|
||||
password,
|
||||
};
|
||||
|
||||
this.handle.pop(Some(data));
|
||||
} else {
|
||||
this.widget.set_visible_child_name("content");
|
||||
}
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
// Initialize
|
||||
|
||||
spawn!(@clone this, async move {
|
||||
let captcha = this.handle.backend.cl().get_captcha().await.unwrap();
|
||||
this.captcha_row.set_title(&captcha.question);
|
||||
this.captcha_id.replace(Some(captcha.id));
|
||||
this.widget.set_visible_child_name("content");
|
||||
});
|
||||
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for RegisterDialog {
|
||||
fn get_widget(&self) -> gtk::Widget {
|
||||
self.widget.clone().upcast()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use musicus_backend::Backend;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// A dialog for setting up the server.
|
||||
pub struct ServerDialog {
|
||||
backend: Rc<Backend>,
|
||||
window: adw::Window,
|
||||
url_entry: gtk::Entry,
|
||||
selected_cb: RefCell<Option<Box<dyn Fn(String)>>>,
|
||||
}
|
||||
|
||||
impl ServerDialog {
|
||||
/// Create a new server dialog.
|
||||
pub fn new<P: IsA<gtk::Window>>(backend: Rc<Backend>, parent: &P) -> Rc<Self> {
|
||||
// Create UI
|
||||
let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/server_dialog.ui");
|
||||
|
||||
get_widget!(builder, adw::Window, window);
|
||||
get_widget!(builder, gtk::Button, cancel_button);
|
||||
get_widget!(builder, gtk::Button, set_button);
|
||||
get_widget!(builder, gtk::Entry, url_entry);
|
||||
|
||||
window.set_transient_for(Some(parent));
|
||||
|
||||
let this = Rc::new(Self {
|
||||
backend,
|
||||
window,
|
||||
url_entry,
|
||||
selected_cb: RefCell::new(None),
|
||||
});
|
||||
|
||||
// Connect signals and callbacks
|
||||
|
||||
cancel_button.connect_clicked(clone!(@strong this => move |_| {
|
||||
this.window.close();
|
||||
}));
|
||||
|
||||
set_button.connect_clicked(clone!(@strong this => move |_| {
|
||||
let url = this.url_entry.text().to_string();
|
||||
this.backend.set_server_url(&url);
|
||||
|
||||
if let Some(cb) = &*this.selected_cb.borrow() {
|
||||
cb(url);
|
||||
}
|
||||
|
||||
this.window.close();
|
||||
}));
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
/// The closure to call when the server was set.
|
||||
pub fn set_selected_cb<F: Fn(String) + 'static>(&self, cb: F) {
|
||||
self.selected_cb.replace(Some(Box::new(cb)));
|
||||
}
|
||||
|
||||
/// Show the server dialog.
|
||||
pub fn show(&self) {
|
||||
self.window.show();
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ impl Screen<(), Ensemble> for EnsembleSelector {
|
|||
fn new(_: (), handle: NavigationHandle<Ensemble>) -> Rc<Self> {
|
||||
// Create UI
|
||||
|
||||
let selector = Selector::<Ensemble>::new(Rc::clone(&handle.backend));
|
||||
let selector = Selector::<Ensemble>::new();
|
||||
selector.set_title(&gettext("Select ensemble"));
|
||||
|
||||
let this = Rc::new(Self { handle, selector });
|
||||
|
|
@ -38,12 +38,6 @@ impl Screen<(), Ensemble> for EnsembleSelector {
|
|||
});
|
||||
}));
|
||||
|
||||
this.selector
|
||||
.set_load_online(clone!(@weak this => @default-panic, move || {
|
||||
let clone = this;
|
||||
async move { Ok(clone.handle.backend.cl().get_ensembles().await?) }
|
||||
}));
|
||||
|
||||
this.selector
|
||||
.set_load_local(clone!(@weak this => @default-panic, move || {
|
||||
let clone = this;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ impl Screen<(), Instrument> for InstrumentSelector {
|
|||
fn new(_: (), handle: NavigationHandle<Instrument>) -> Rc<Self> {
|
||||
// Create UI
|
||||
|
||||
let selector = Selector::<Instrument>::new(Rc::clone(&handle.backend));
|
||||
let selector = Selector::<Instrument>::new();
|
||||
selector.set_title(&gettext("Select instrument"));
|
||||
|
||||
let this = Rc::new(Self { handle, selector });
|
||||
|
|
@ -38,12 +38,6 @@ impl Screen<(), Instrument> for InstrumentSelector {
|
|||
});
|
||||
}));
|
||||
|
||||
this.selector
|
||||
.set_load_online(clone!(@weak this => @default-panic, move || {
|
||||
let clone = this;
|
||||
async move { Ok(clone.handle.backend.cl().get_instruments().await?) }
|
||||
}));
|
||||
|
||||
this.selector
|
||||
.set_load_local(clone!(@weak this => @default-panic, move || {
|
||||
let clone = this;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ impl Screen<(), Medium> for MediumSelector {
|
|||
fn new(_: (), handle: NavigationHandle<Medium>) -> Rc<Self> {
|
||||
// Create UI
|
||||
|
||||
let selector = Selector::<PersonOrEnsemble>::new(Rc::clone(&handle.backend));
|
||||
let selector = Selector::<PersonOrEnsemble>::new();
|
||||
selector.set_title(&gettext("Select performer"));
|
||||
|
||||
let this = Rc::new(Self { handle, selector });
|
||||
|
|
@ -28,26 +28,6 @@ impl Screen<(), Medium> for MediumSelector {
|
|||
this.handle.pop(None);
|
||||
}));
|
||||
|
||||
this.selector
|
||||
.set_load_online(clone!(@weak this => @default-panic, move || {
|
||||
async move {
|
||||
let mut poes = Vec::new();
|
||||
|
||||
let persons = this.handle.backend.cl().get_persons().await?;
|
||||
let ensembles = this.handle.backend.cl().get_ensembles().await?;
|
||||
|
||||
for person in persons {
|
||||
poes.push(PersonOrEnsemble::Person(person));
|
||||
}
|
||||
|
||||
for ensemble in ensembles {
|
||||
poes.push(PersonOrEnsemble::Ensemble(ensemble));
|
||||
}
|
||||
|
||||
Ok(poes)
|
||||
}
|
||||
}));
|
||||
|
||||
this.selector
|
||||
.set_load_local(clone!(@weak this => @default-panic, move || {
|
||||
async move {
|
||||
|
|
@ -109,7 +89,7 @@ struct MediumSelectorMediumScreen {
|
|||
|
||||
impl Screen<PersonOrEnsemble, Medium> for MediumSelectorMediumScreen {
|
||||
fn new(poe: PersonOrEnsemble, handle: NavigationHandle<Medium>) -> Rc<Self> {
|
||||
let selector = Selector::<Medium>::new(Rc::clone(&handle.backend));
|
||||
let selector = Selector::<Medium>::new();
|
||||
selector.set_title(&gettext("Select medium"));
|
||||
selector.set_subtitle(&poe.get_title());
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ impl Screen<(), Person> for PersonSelector {
|
|||
fn new(_: (), handle: NavigationHandle<Person>) -> Rc<Self> {
|
||||
// Create UI
|
||||
|
||||
let selector = Selector::<Person>::new(Rc::clone(&handle.backend));
|
||||
let selector = Selector::<Person>::new();
|
||||
selector.set_title(&gettext("Select person"));
|
||||
|
||||
let this = Rc::new(Self { handle, selector });
|
||||
|
|
@ -38,12 +38,6 @@ impl Screen<(), Person> for PersonSelector {
|
|||
});
|
||||
}));
|
||||
|
||||
this.selector
|
||||
.set_load_online(clone!(@weak this => @default-panic, move || {
|
||||
let clone = this;
|
||||
async move { Ok(clone.handle.backend.cl().get_persons().await?) }
|
||||
}));
|
||||
|
||||
this.selector
|
||||
.set_load_local(clone!(@weak this => @default-panic, move || {
|
||||
let clone = this;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ impl Screen<(), Recording> for RecordingSelector {
|
|||
fn new(_: (), handle: NavigationHandle<Recording>) -> Rc<Self> {
|
||||
// Create UI
|
||||
|
||||
let selector = Selector::<Person>::new(Rc::clone(&handle.backend));
|
||||
let selector = Selector::<Person>::new();
|
||||
selector.set_title(&gettext("Select composer"));
|
||||
|
||||
let this = Rc::new(Self { handle, selector });
|
||||
|
|
@ -50,11 +50,6 @@ impl Screen<(), Recording> for RecordingSelector {
|
|||
});
|
||||
}));
|
||||
|
||||
this.selector
|
||||
.set_load_online(clone!(@weak this => @default-panic, move || {
|
||||
async move { Ok(this.handle.backend.cl().get_persons().await?) }
|
||||
}));
|
||||
|
||||
this.selector
|
||||
.set_load_local(clone!(@weak this => @default-panic, move || {
|
||||
async move { this.handle.backend.db().get_persons().await.unwrap() }
|
||||
|
|
@ -108,7 +103,7 @@ struct RecordingSelectorWorkScreen {
|
|||
|
||||
impl Screen<Person, Work> for RecordingSelectorWorkScreen {
|
||||
fn new(person: Person, handle: NavigationHandle<Work>) -> Rc<Self> {
|
||||
let selector = Selector::<Work>::new(Rc::clone(&handle.backend));
|
||||
let selector = Selector::<Work>::new();
|
||||
selector.set_title(&gettext("Select work"));
|
||||
selector.set_subtitle(&person.name_fl());
|
||||
|
||||
|
|
@ -131,11 +126,6 @@ impl Screen<Person, Work> for RecordingSelectorWorkScreen {
|
|||
});
|
||||
}));
|
||||
|
||||
this.selector
|
||||
.set_load_online(clone!(@weak this => @default-panic, move || {
|
||||
async move { Ok(this.handle.backend.cl().get_works(&this.person.id).await?) }
|
||||
}));
|
||||
|
||||
this.selector
|
||||
.set_load_local(clone!(@weak this => @default-panic, move || {
|
||||
async move { this.handle.backend.db().get_works(&this.person.id).await.unwrap() }
|
||||
|
|
@ -178,7 +168,7 @@ struct RecordingSelectorRecordingScreen {
|
|||
|
||||
impl Screen<Work, Recording> for RecordingSelectorRecordingScreen {
|
||||
fn new(work: Work, handle: NavigationHandle<Recording>) -> Rc<Self> {
|
||||
let selector = Selector::<Recording>::new(Rc::clone(&handle.backend));
|
||||
let selector = Selector::<Recording>::new();
|
||||
selector.set_title(&gettext("Select recording"));
|
||||
selector.set_subtitle(&work.get_title());
|
||||
|
||||
|
|
@ -201,10 +191,6 @@ impl Screen<Work, Recording> for RecordingSelectorRecordingScreen {
|
|||
});
|
||||
}));
|
||||
|
||||
this.selector.set_load_online(clone!(@weak this => @default-panic, move || {
|
||||
async move { Ok(this.handle.backend.cl().get_recordings_for_work(&this.work.id).await?) }
|
||||
}));
|
||||
|
||||
this.selector.set_load_local(clone!(@weak this => @default-panic, move || {
|
||||
async move { this.handle.backend.db().get_recordings_for_work(&this.work.id).await.unwrap() }
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -2,36 +2,30 @@ use crate::widgets::List;
|
|||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use musicus_backend::{Backend, Result};
|
||||
use std::cell::RefCell;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// A screen that presents a list of items. It allows to switch between the server and the local
|
||||
/// database and to search within the list.
|
||||
/// A screen that presents a list of items from the library.
|
||||
pub struct Selector<T: 'static> {
|
||||
pub widget: gtk::Box,
|
||||
backend: Rc<Backend>,
|
||||
title_label: gtk::Label,
|
||||
subtitle_label: gtk::Label,
|
||||
search_entry: gtk::SearchEntry,
|
||||
server_check_button: gtk::CheckButton,
|
||||
stack: gtk::Stack,
|
||||
list: Rc<List>,
|
||||
items: RefCell<Vec<T>>,
|
||||
back_cb: RefCell<Option<Box<dyn Fn()>>>,
|
||||
add_cb: RefCell<Option<Box<dyn Fn()>>>,
|
||||
make_widget: RefCell<Option<Box<dyn Fn(&T) -> gtk::Widget>>>,
|
||||
load_online: RefCell<Option<Box<dyn Fn() -> Box<dyn Future<Output = Result<Vec<T>>>>>>>,
|
||||
load_local: RefCell<Option<Box<dyn Fn() -> Box<dyn Future<Output = Vec<T>>>>>>,
|
||||
filter: RefCell<Option<Box<dyn Fn(&str, &T) -> bool>>>,
|
||||
}
|
||||
|
||||
impl<T> Selector<T> {
|
||||
/// Create a new selector. `use_server` is used to decide whether to search
|
||||
/// online initially.
|
||||
pub fn new(backend: Rc<Backend>) -> Rc<Self> {
|
||||
/// Create a new selector.
|
||||
pub fn new() -> Rc<Self> {
|
||||
// Create UI
|
||||
|
||||
let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/selector.ui");
|
||||
|
|
@ -42,28 +36,23 @@ impl<T> Selector<T> {
|
|||
get_widget!(builder, gtk::Button, back_button);
|
||||
get_widget!(builder, gtk::Button, add_button);
|
||||
get_widget!(builder, gtk::SearchEntry, search_entry);
|
||||
get_widget!(builder, gtk::CheckButton, server_check_button);
|
||||
get_widget!(builder, gtk::Stack, stack);
|
||||
get_widget!(builder, gtk::Frame, frame);
|
||||
get_widget!(builder, gtk::Button, try_again_button);
|
||||
|
||||
let list = List::new();
|
||||
frame.set_child(Some(&list.widget));
|
||||
|
||||
let this = Rc::new(Self {
|
||||
widget,
|
||||
backend,
|
||||
title_label,
|
||||
subtitle_label,
|
||||
search_entry,
|
||||
server_check_button,
|
||||
stack,
|
||||
list,
|
||||
items: RefCell::new(Vec::new()),
|
||||
back_cb: RefCell::new(None),
|
||||
add_cb: RefCell::new(None),
|
||||
make_widget: RefCell::new(None),
|
||||
load_online: RefCell::new(None),
|
||||
load_local: RefCell::new(None),
|
||||
filter: RefCell::new(None),
|
||||
});
|
||||
|
|
@ -87,18 +76,6 @@ impl<T> Selector<T> {
|
|||
this.list.invalidate_filter();
|
||||
}));
|
||||
|
||||
this.server_check_button
|
||||
.connect_toggled(clone!(@strong this => move |_| {
|
||||
let active = this.server_check_button.is_active();
|
||||
this.backend.set_use_server(active);
|
||||
|
||||
if active {
|
||||
this.clone().load_online();
|
||||
} else {
|
||||
this.clone().load_local();
|
||||
}
|
||||
}));
|
||||
|
||||
this.list
|
||||
.set_make_widget_cb(clone!(@strong this => move |index| {
|
||||
if let Some(cb) = &*this.make_widget.borrow() {
|
||||
|
|
@ -121,16 +98,8 @@ impl<T> Selector<T> {
|
|||
}
|
||||
}));
|
||||
|
||||
try_again_button.connect_clicked(clone!(@strong this => move |_| {
|
||||
this.clone().load_online();
|
||||
}));
|
||||
|
||||
// Initialize
|
||||
if this.backend.use_server() {
|
||||
this.clone().load_online();
|
||||
} else {
|
||||
this.server_check_button.set_active(false);
|
||||
}
|
||||
this.clone().load_local();
|
||||
|
||||
this
|
||||
}
|
||||
|
|
@ -156,17 +125,6 @@ impl<T> Selector<T> {
|
|||
self.add_cb.replace(Some(Box::new(cb)));
|
||||
}
|
||||
|
||||
/// Set the async closure to be called to fetch items from the server. If that results in an
|
||||
/// error, an error screen is shown allowing to try again.
|
||||
pub fn set_load_online<F, R>(&self, cb: F)
|
||||
where
|
||||
F: (Fn() -> R) + 'static,
|
||||
R: Future<Output = Result<Vec<T>>> + 'static,
|
||||
{
|
||||
self.load_online
|
||||
.replace(Some(Box::new(move || Box::new(cb()))));
|
||||
}
|
||||
|
||||
/// Set the async closure to be called to get local items.
|
||||
pub fn set_load_local<F, R>(&self, cb: F)
|
||||
where
|
||||
|
|
@ -188,26 +146,6 @@ impl<T> Selector<T> {
|
|||
self.filter.replace(Some(Box::new(filter)));
|
||||
}
|
||||
|
||||
fn load_online(self: Rc<Self>) {
|
||||
let context = glib::MainContext::default();
|
||||
let clone = self.clone();
|
||||
context.spawn_local(async move {
|
||||
if let Some(cb) = &*self.load_online.borrow() {
|
||||
self.stack.set_visible_child_name("loading");
|
||||
|
||||
match Pin::from(cb()).await {
|
||||
Ok(items) => {
|
||||
clone.show_items(items);
|
||||
}
|
||||
Err(_) => {
|
||||
clone.show_items(Vec::new());
|
||||
clone.stack.set_visible_child_name("error");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn load_local(self: Rc<Self>) {
|
||||
let context = glib::MainContext::default();
|
||||
let clone = self.clone();
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ impl Screen<(), Work> for WorkSelector {
|
|||
fn new(_: (), handle: NavigationHandle<Work>) -> Rc<Self> {
|
||||
// Create UI
|
||||
|
||||
let selector = Selector::<Person>::new(Rc::clone(&handle.backend));
|
||||
let selector = Selector::<Person>::new();
|
||||
selector.set_title(&gettext("Select composer"));
|
||||
|
||||
let this = Rc::new(Self { handle, selector });
|
||||
|
|
@ -44,11 +44,6 @@ impl Screen<(), Work> for WorkSelector {
|
|||
});
|
||||
}));
|
||||
|
||||
this.selector
|
||||
.set_load_online(clone!(@weak this => @default-panic, move || {
|
||||
async move { Ok(this.handle.backend.cl().get_persons().await?) }
|
||||
}));
|
||||
|
||||
this.selector
|
||||
.set_load_local(clone!(@weak this => @default-panic, move || {
|
||||
async move { this.handle.backend.db().get_persons().await.unwrap() }
|
||||
|
|
@ -98,7 +93,7 @@ struct WorkSelectorWorkScreen {
|
|||
|
||||
impl Screen<Person, Work> for WorkSelectorWorkScreen {
|
||||
fn new(person: Person, handle: NavigationHandle<Work>) -> Rc<Self> {
|
||||
let selector = Selector::<Work>::new(Rc::clone(&handle.backend));
|
||||
let selector = Selector::<Work>::new();
|
||||
selector.set_title(&gettext("Select work"));
|
||||
selector.set_subtitle(&person.name_fl());
|
||||
|
||||
|
|
@ -121,11 +116,6 @@ impl Screen<Person, Work> for WorkSelectorWorkScreen {
|
|||
});
|
||||
}));
|
||||
|
||||
this.selector
|
||||
.set_load_online(clone!(@weak this => @default-panic, move || {
|
||||
async move { Ok(this.handle.backend.cl().get_works(&this.person.id).await?) }
|
||||
}));
|
||||
|
||||
this.selector
|
||||
.set_load_local(clone!(@weak this => @default-panic, move || {
|
||||
async move { this.handle.backend.db().get_works(&this.person.id).await.unwrap() }
|
||||
|
|
|
|||
|
|
@ -21,9 +21,6 @@ pub use screen::*;
|
|||
pub mod section;
|
||||
pub use section::*;
|
||||
|
||||
pub mod upload_section;
|
||||
pub use upload_section::*;
|
||||
|
||||
mod indexed_list_model;
|
||||
|
||||
/// Something that can be represented as a GTK widget.
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
use super::Section;
|
||||
use adw::prelude::*;
|
||||
use gettextrs::gettext;
|
||||
use glib::clone;
|
||||
use musicus_backend::Backend;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// A section showing a switch to enable uploading an item.
|
||||
pub struct UploadSection {
|
||||
/// The GTK widget of the wrapped section.
|
||||
pub widget: gtk::Box,
|
||||
|
||||
backend: Rc<Backend>,
|
||||
|
||||
/// The upload switch.
|
||||
switch: gtk::Switch,
|
||||
}
|
||||
|
||||
impl UploadSection {
|
||||
/// Create a new upload section which will be initially switched on.
|
||||
pub fn new(backend: Rc<Backend>) -> Rc<Self> {
|
||||
let list = gtk::ListBoxBuilder::new()
|
||||
.selection_mode(gtk::SelectionMode::None)
|
||||
.build();
|
||||
|
||||
let switch = gtk::SwitchBuilder::new()
|
||||
.active(backend.use_server())
|
||||
.valign(gtk::Align::Center)
|
||||
.build();
|
||||
|
||||
let row = adw::ActionRowBuilder::new()
|
||||
.focusable(false)
|
||||
.title("Upload changes to the server")
|
||||
.activatable_widget(&switch)
|
||||
.build();
|
||||
|
||||
row.add_suffix(&switch);
|
||||
list.append(&row);
|
||||
|
||||
let section = Section::new(&gettext("Upload"), &list);
|
||||
|
||||
let this = Rc::new(Self {
|
||||
widget: section.widget,
|
||||
backend,
|
||||
switch,
|
||||
});
|
||||
|
||||
this.switch
|
||||
.connect_state_notify(clone!(@weak this => move |_| {
|
||||
this.backend.set_use_server(this.switch.state());
|
||||
}));
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
/// Return whether the user has enabled the upload switch.
|
||||
pub fn get_active(&self) -> bool {
|
||||
self.switch.state()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue