malcontent-control: Add initial draft of main interface
This replicates the old interface from Endless’ gnome-control-center, with no attempt to improve or rework it. That will come later. It might not work fully. It allows a user to be selected, and their parental controls to be changed. It currently doesn’t filter the users. It supports a simple ‘Loading’ screen, before displaying the main interface. If loading fails (due to a D-Bus error with accountsservice), an error page is displayed instead. Signed-off-by: Philip Withnall <withnall@endlessm.com>
This commit is contained in:
parent
1623876fbc
commit
c7f975bb2b
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <act/act.h>
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
#include <glib/gi18n-lib.h>
|
||||
|
@ -28,6 +29,16 @@
|
|||
#include <gtk/gtk.h>
|
||||
|
||||
#include "application.h"
|
||||
#include "user-controls.h"
|
||||
#include "user-selector.h"
|
||||
|
||||
|
||||
static void user_selector_notify_user_cb (GObject *obj,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data);
|
||||
static void user_manager_notify_is_loaded_cb (GObject *obj,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -41,6 +52,14 @@
|
|||
struct _MctApplication
|
||||
{
|
||||
GtkApplication parent_instance;
|
||||
|
||||
ActUserManager *user_manager; /* (owned) */
|
||||
|
||||
MctUserSelector *user_selector;
|
||||
MctUserControls *user_controls;
|
||||
GtkStack *main_stack;
|
||||
GtkLabel *error_title;
|
||||
GtkLabel *error_message;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MctApplication, mct_application, GTK_TYPE_APPLICATION)
|
||||
|
@ -69,27 +88,77 @@ mct_application_constructed (GObject *object)
|
|||
G_OBJECT_CLASS (mct_application_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
mct_application_dispose (GObject *object)
|
||||
{
|
||||
MctApplication *self = MCT_APPLICATION (object);
|
||||
|
||||
if (self->user_manager != NULL)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (self->user_manager,
|
||||
user_manager_notify_is_loaded_cb, self);
|
||||
g_clear_object (&self->user_manager);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (mct_application_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static GtkWindow *
|
||||
mct_application_get_main_window (MctApplication *self)
|
||||
{
|
||||
return gtk_application_get_active_window (GTK_APPLICATION (self));
|
||||
}
|
||||
|
||||
static void
|
||||
mct_application_activate (GApplication *application)
|
||||
{
|
||||
GList *windows; /* (element-type GtkWindow) */
|
||||
MctApplication *self = MCT_APPLICATION (application);
|
||||
GtkWindow *window = NULL;
|
||||
|
||||
windows = gtk_application_get_windows (GTK_APPLICATION (application));
|
||||
if (windows != NULL)
|
||||
window = windows->data;
|
||||
window = mct_application_get_main_window (self);
|
||||
|
||||
if (window == NULL)
|
||||
{
|
||||
g_autoptr(GtkBuilder) builder = NULL;
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
|
||||
builder = gtk_builder_new_from_resource ("/org/freedesktop/MalcontentControl/ui/main.ui");
|
||||
/* Ensure the types used in the UI are registered. */
|
||||
g_type_ensure (MCT_TYPE_USER_CONTROLS);
|
||||
g_type_ensure (MCT_TYPE_USER_SELECTOR);
|
||||
|
||||
builder = gtk_builder_new ();
|
||||
|
||||
g_assert (self->user_manager == NULL);
|
||||
self->user_manager = g_object_ref (act_user_manager_get_default ());
|
||||
|
||||
gtk_builder_set_translation_domain (builder, "malcontent");
|
||||
gtk_builder_expose_object (builder, "user_manager", G_OBJECT (self->user_manager));
|
||||
|
||||
gtk_builder_add_from_resource (builder, "/org/freedesktop/MalcontentControl/ui/main.ui", &local_error);
|
||||
g_assert (local_error == NULL);
|
||||
|
||||
/* Set up the main window. */
|
||||
window = GTK_WINDOW (gtk_builder_get_object (builder, "main_window"));
|
||||
gtk_window_set_application (window, GTK_APPLICATION (application));
|
||||
|
||||
self->main_stack = GTK_STACK (gtk_builder_get_object (builder, "main_stack"));
|
||||
self->user_selector = MCT_USER_SELECTOR (gtk_builder_get_object (builder, "user_selector"));
|
||||
self->user_controls = MCT_USER_CONTROLS (gtk_builder_get_object (builder, "user_controls"));
|
||||
self->error_title = GTK_LABEL (gtk_builder_get_object (builder, "error_title"));
|
||||
self->error_message = GTK_LABEL (gtk_builder_get_object (builder, "error_message"));
|
||||
|
||||
/* Connect signals. */
|
||||
g_signal_connect (self->user_selector, "notify::user",
|
||||
G_CALLBACK (user_selector_notify_user_cb),
|
||||
self);
|
||||
g_signal_connect (self->user_manager, "notify::is-loaded",
|
||||
G_CALLBACK (user_manager_notify_is_loaded_cb), self);
|
||||
|
||||
/* Work out whether to show the loading page or the main page, and show
|
||||
* the controls for the initially selected user. */
|
||||
user_selector_notify_user_cb (G_OBJECT (self->user_selector), NULL, self);
|
||||
user_manager_notify_is_loaded_cb (G_OBJECT (self->user_manager), NULL, self);
|
||||
|
||||
gtk_widget_show (GTK_WIDGET (window));
|
||||
}
|
||||
|
||||
|
@ -104,9 +173,61 @@ mct_application_class_init (MctApplicationClass *klass)
|
|||
GApplicationClass *application_class = G_APPLICATION_CLASS (klass);
|
||||
|
||||
object_class->constructed = mct_application_constructed;
|
||||
object_class->dispose = mct_application_dispose;
|
||||
|
||||
application_class->activate = mct_application_activate;
|
||||
}
|
||||
|
||||
static void
|
||||
user_selector_notify_user_cb (GObject *obj,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
MctUserSelector *selector = MCT_USER_SELECTOR (obj);
|
||||
MctApplication *self = MCT_APPLICATION (user_data);
|
||||
ActUser *user;
|
||||
|
||||
user = mct_user_selector_get_user (selector);
|
||||
|
||||
mct_user_controls_set_user (self->user_controls, user);
|
||||
}
|
||||
|
||||
static void
|
||||
user_manager_notify_is_loaded_cb (GObject *obj,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
MctApplication *self = MCT_APPLICATION (user_data);
|
||||
ActUserManager *user_manager = ACT_USER_MANAGER (obj);
|
||||
gboolean is_loaded;
|
||||
const gchar *new_page_name;
|
||||
|
||||
/* The implementation of #ActUserManager guarantees that once is-loaded is
|
||||
* true, it is never reset to false. */
|
||||
g_object_get (user_manager, "is-loaded", &is_loaded, NULL);
|
||||
|
||||
/* Handle any loading errors. */
|
||||
if (is_loaded && act_user_manager_no_service (user_manager))
|
||||
{
|
||||
gtk_label_set_label (self->error_title,
|
||||
_("Failed to load user data from the system"));
|
||||
gtk_label_set_label (self->error_message,
|
||||
_("Please make sure that the AccountsService is installed and enabled."));
|
||||
|
||||
new_page_name = "error";
|
||||
}
|
||||
else if (is_loaded)
|
||||
{
|
||||
new_page_name = "controls";
|
||||
}
|
||||
else
|
||||
{
|
||||
new_page_name = "loading";
|
||||
}
|
||||
|
||||
gtk_stack_set_visible_child_name (self->main_stack, new_page_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* mct_application_new:
|
||||
*
|
||||
|
|
|
@ -1,11 +1,117 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright © 2019 Endless Mobile, Inc. -->
|
||||
<!-- Copyright © 2019, 2020 Endless Mobile, Inc. -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.12"/>
|
||||
<object class="GtkApplicationWindow" id="main_window">
|
||||
<property name="default-width">500</property>
|
||||
<property name="default-height">700</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="vbox1">
|
||||
<object class="GtkStack" id="main_stack">
|
||||
<property name="visible">True</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="border_width">0</property>
|
||||
<child>
|
||||
<object class="MctUserSelector" id="user_selector">
|
||||
<property name="visible">True</property>
|
||||
<property name="user-manager">user_manager</property>
|
||||
<accessibility>
|
||||
<relation target="user_controls" type="controller-for"/>
|
||||
</accessibility>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="fill">False</property>
|
||||
<property name="expand">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<property name="min-content-height">450</property>
|
||||
<child>
|
||||
<object class="MctUserControls" id="user_controls">
|
||||
<property name="visible">True</property>
|
||||
<property name="margin">12</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">controls</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<child type="center">
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Loading…</property>
|
||||
<attributes>
|
||||
<attribute name="scale" value="1.4"/>
|
||||
</attributes>
|
||||
<child internal-child="accessible">
|
||||
<object class="AtkObject">
|
||||
<property name="AtkObject::accessible-role">static</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">loading</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<child type="center">
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="error_title">
|
||||
<property name="visible">True</property>
|
||||
<property name="label"></property>
|
||||
<attributes>
|
||||
<attribute name="scale" value="1.4"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="error_message">
|
||||
<property name="visible">True</property>
|
||||
<property name="label"></property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child internal-child="accessible">
|
||||
<object class="AtkObject">
|
||||
<property name="AtkObject::accessible-role">alert</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">error</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
Loading…
Reference in New Issue