timeLimitsManager: Add new state machine for screen time limits

This implements wellbeing screen time limits in gnome-shell. It depends
on a few changes in other modules:
 - New settings schemas in gsettings-desktop-schemas
 - A settings UI in gnome-control-center
 - User documentation in gnome-user-docs

It implements the design from
https://gitlab.gnome.org/Teams/Design/settings-mockups/-/blob/master/wellbeing/wellbeing.png.

The core of the implementation is `TimeLimitsManager`, which is a state
machine which uses the user’s session state from logind to track how long
the user has been in an active session, in aggregate, during the day. If
this total exceeds their limit for the day, the state machine changes
state.

The user’s session activity history (basically, when they logged in and
out for the past 14 weeks) is kept in a state file in their home
directory. This is used by gnome-shell to count usage across reboots in
a single day, and in the future it will also be used to provide usage
history in gnome-control-center, so the user can visualise their
historic computer usage at a high level, for the past several weeks.

The `TimeLimitsDispatcher` is based on top of this, and controls showing
notifications and screen fades to make the user aware of whether they’ve
used the computer for too long today, as per their preferences.

Unit tests are included to check that `TimeLimitsManager` works, in
particular with its loading and storing of the history file. The unit
tests provide mock implementations of basic GLib clock functions, the
logind D-Bus proxy and `Gio.Settings` in order to test the state machine in
faster-than-real-time.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>

See: https://gitlab.gnome.org/Teams/Design/initiatives/-/issues/130
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3397>
This commit is contained in:
Philip Withnall 2024-06-28 16:46:17 +01:00 committed by Marge Bot
parent 1ceb803686
commit 212e098da1
8 changed files with 2064 additions and 2 deletions

View File

@ -44,7 +44,7 @@ default:
- 'api_failure'
variables:
MUTTER_CI_IMAGE: registry.gitlab.gnome.org/gnome/mutter/fedora/41:x86_64-2024-10-15.0
MUTTER_CI_IMAGE: registry.gitlab.gnome.org/gnome/mutter/fedora/41:x86_64-2024-12-18.0
FDO_UPSTREAM_REPO: GNOME/gnome-shell
BUNDLE: "extensions-git.flatpak"
LINT_LOG: "eslint-report.xml"

View File

@ -41,6 +41,7 @@
<file>misc/signalTracker.js</file>
<file>misc/smartcardManager.js</file>
<file>misc/systemActions.js</file>
<file>misc/timeLimitsManager.js</file>
<file>misc/util.js</file>
<file>misc/weather.js</file>

1020
js/misc/timeLimitsManager.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -37,6 +37,7 @@ import * as ScreenShield from './screenShield.js';
import * as SessionMode from './sessionMode.js';
import * as ShellDBus from './shellDBus.js';
import * as ShellMountOperation from './shellMountOperation.js';
import * as TimeLimitsManager from '../misc/timeLimitsManager.js';
import * as WindowManager from './windowManager.js';
import * as Magnifier from './magnifier.js';
import * as XdndHandler from './xdndHandler.js';
@ -93,6 +94,8 @@ export let endSessionDialog = null;
export let breakManager = null;
export let screenTimeDBus = null;
export let breakManagerDispatcher = null;
export let timeLimitsManager = null;
export let timeLimitsDispatcher = null;
let _startDate;
let _defaultCssStylesheet = null;
@ -250,8 +253,24 @@ async function _initializeUI() {
// Set up the global default break reminder manager and its D-Bus interface
breakManager = new BreakManager.BreakManager();
timeLimitsManager = new TimeLimitsManager.TimeLimitsManager();
screenTimeDBus = new ShellDBus.ScreenTimeDBus(breakManager);
breakManagerDispatcher = new BreakManager.BreakDispatcher(breakManager);
timeLimitsDispatcher = new TimeLimitsManager.TimeLimitsDispatcher(timeLimitsManager);
global.connect('shutdown', () => {
// Block shutdown until the session history file has been written
const loop = new GLib.MainLoop(null, false);
const source = GLib.idle_source_new();
source.set_callback(() => {
timeLimitsManager.shutdown()
.catch(e => console.warn(`Failed to stop time limits manager: ${e.message}`))
.finally(() => loop.quit());
return GLib.SOURCE_REMOVE;
});
source.attach(loop.get_context());
loop.run();
});
layoutManager.init();
overview.init();

View File

@ -27,7 +27,7 @@ gjs_req = '>= 1.73.1'
gtk_req = '>= 4.0'
mutter_req = '>= 47.0'
polkit_req = '>= 0.100'
schemas_req = '>= 47.beta'
schemas_req = '>= 48.alpha'
systemd_req = '>= 246'
gnome_desktop_req = '>= 40'
pipewire_req = '>= 0.3.49'

View File

@ -14,6 +14,7 @@ js/gdm/loginDialog.js
js/gdm/util.js
js/misc/breakManager.js
js/misc/systemActions.js
js/misc/timeLimitsManager.js
js/misc/util.js
js/misc/dateUtils.js
js/portalHelper/main.js

View File

@ -29,6 +29,7 @@ unit_tests = [
'markup',
'params',
'signalTracker',
'timeLimitsManager',
'url',
'versionCompare',
]

File diff suppressed because it is too large Load Diff