ca9099997c
The userList code has no dependencies on anything else in loginDialog.js so move it to its own file. This is part of the greater reorganization effort to clean up the login dialog / unlock dialog situation.
252 lines
7.7 KiB
JavaScript
252 lines
7.7 KiB
JavaScript
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
|
|
const AccountsService = imports.gi.AccountsService;
|
|
const Gtk = imports.gi.Gtk;
|
|
const Meta = imports.gi.Meta;
|
|
const Lang = imports.lang;
|
|
const Signals = imports.signals;
|
|
const St = imports.gi.St;
|
|
const Gdm = imports.gi.Gdm;
|
|
|
|
const Batch = imports.misc.batch;
|
|
const Tweener = imports.ui.tweener;
|
|
const UserAvatar = imports.ui.userAvatar;
|
|
|
|
const _SCROLL_ANIMATION_TIME = 0.5;
|
|
|
|
const UserListItem = new Lang.Class({
|
|
Name: 'UserListItem',
|
|
|
|
_init: function(user) {
|
|
this.user = user;
|
|
this._userChangedId = this.user.connect('changed',
|
|
Lang.bind(this, this._onUserChanged));
|
|
|
|
let layout = new St.BoxLayout({ vertical: false });
|
|
this.actor = new St.Button({ style_class: 'login-dialog-user-list-item',
|
|
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
|
can_focus: true,
|
|
child: layout,
|
|
reactive: true,
|
|
x_align: St.Align.START,
|
|
x_fill: true });
|
|
|
|
this._userAvatar = new UserAvatar.UserAvatar(this.user,
|
|
{ styleClass: 'login-dialog-user-list-item-icon' });
|
|
layout.add(this._userAvatar.actor);
|
|
let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box',
|
|
vertical: true });
|
|
layout.add(textLayout, { expand: true });
|
|
|
|
this._nameLabel = new St.Label({ style_class: 'login-dialog-user-list-item-name' });
|
|
this.actor.label_actor = this._nameLabel;
|
|
textLayout.add(this._nameLabel,
|
|
{ y_fill: false,
|
|
y_align: St.Align.MIDDLE,
|
|
expand: true });
|
|
|
|
this._timedLoginIndicator = new St.Bin({ style_class: 'login-dialog-timed-login-indicator',
|
|
scale_x: 0 });
|
|
textLayout.add(this._timedLoginIndicator,
|
|
{ x_fill: true,
|
|
x_align: St.Align.MIDDLE,
|
|
y_fill: false,
|
|
y_align: St.Align.END });
|
|
|
|
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
|
this._onUserChanged();
|
|
},
|
|
|
|
_onUserChanged: function() {
|
|
this._nameLabel.set_text(this.user.get_real_name());
|
|
this._userAvatar.update();
|
|
this._updateLoggedIn();
|
|
},
|
|
|
|
syncStyleClasses: function() {
|
|
this._updateLoggedIn();
|
|
|
|
if (global.stage.get_key_focus() == this.actor)
|
|
this.actor.add_style_pseudo_class('focus');
|
|
else
|
|
this.actor.remove_style_pseudo_class('focus');
|
|
},
|
|
|
|
_updateLoggedIn: function() {
|
|
if (this.user.is_logged_in())
|
|
this.actor.add_style_pseudo_class('logged-in');
|
|
else
|
|
this.actor.remove_style_pseudo_class('logged-in');
|
|
},
|
|
|
|
_onClicked: function() {
|
|
this.emit('activate');
|
|
},
|
|
|
|
showTimedLoginIndicator: function(time) {
|
|
let hold = new Batch.Hold();
|
|
|
|
this.hideTimedLoginIndicator();
|
|
Tweener.addTween(this._timedLoginIndicator,
|
|
{ scale_x: 1.,
|
|
time: time,
|
|
transition: 'linear',
|
|
onComplete: function() {
|
|
hold.release();
|
|
},
|
|
onCompleteScope: this
|
|
});
|
|
return hold;
|
|
},
|
|
|
|
hideTimedLoginIndicator: function() {
|
|
Tweener.removeTweens(this._timedLoginIndicator);
|
|
this._timedLoginIndicator.scale_x = 0.;
|
|
}
|
|
});
|
|
Signals.addSignalMethods(UserListItem.prototype);
|
|
|
|
const UserList = new Lang.Class({
|
|
Name: 'UserList',
|
|
|
|
_init: function() {
|
|
this.actor = new St.ScrollView({ style_class: 'login-dialog-user-list-view'});
|
|
this.actor.set_policy(Gtk.PolicyType.NEVER,
|
|
Gtk.PolicyType.AUTOMATIC);
|
|
|
|
this._box = new St.BoxLayout({ vertical: true,
|
|
style_class: 'login-dialog-user-list',
|
|
pseudo_class: 'expanded' });
|
|
|
|
this.actor.add_actor(this._box);
|
|
this._items = {};
|
|
|
|
this.actor.connect('key-focus-in', Lang.bind(this, this._moveFocusToItems));
|
|
},
|
|
|
|
_moveFocusToItems: function() {
|
|
let hasItems = Object.keys(this._items).length > 0;
|
|
|
|
if (!hasItems)
|
|
return;
|
|
|
|
if (global.stage.get_key_focus() != this.actor)
|
|
return;
|
|
|
|
let focusSet = this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
|
if (!focusSet) {
|
|
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
|
this._moveFocusToItems();
|
|
return false;
|
|
}));
|
|
}
|
|
},
|
|
|
|
_onItemActivated: function(activatedItem) {
|
|
this.emit('activate', activatedItem);
|
|
},
|
|
|
|
updateStyle: function(isExpanded) {
|
|
let tasks = [];
|
|
|
|
if (isExpanded)
|
|
this._box.add_style_pseudo_class('expanded');
|
|
else
|
|
this._box.remove_style_pseudo_class('expanded');
|
|
|
|
for (let userName in this._items) {
|
|
let item = this._items[userName];
|
|
item.actor.sync_hover();
|
|
item.syncStyleClasses();
|
|
}
|
|
},
|
|
|
|
scrollToItem: function(item) {
|
|
let box = item.actor.get_allocation_box();
|
|
|
|
let adjustment = this.actor.get_vscroll_bar().get_adjustment();
|
|
|
|
let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0);
|
|
Tweener.removeTweens(adjustment);
|
|
Tweener.addTween (adjustment,
|
|
{ value: value,
|
|
time: _SCROLL_ANIMATION_TIME,
|
|
transition: 'easeOutQuad' });
|
|
},
|
|
|
|
jumpToItem: function(item) {
|
|
let box = item.actor.get_allocation_box();
|
|
|
|
let adjustment = this.actor.get_vscroll_bar().get_adjustment();
|
|
|
|
let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0);
|
|
|
|
adjustment.set_value(value);
|
|
},
|
|
|
|
getItemFromUserName: function(userName) {
|
|
let item = this._items[userName];
|
|
|
|
if (!item)
|
|
return null;
|
|
|
|
return item;
|
|
},
|
|
|
|
addUser: function(user) {
|
|
if (!user.is_loaded)
|
|
return;
|
|
|
|
if (user.is_system_account())
|
|
return;
|
|
|
|
if (user.locked)
|
|
return;
|
|
|
|
let userName = user.get_user_name();
|
|
|
|
if (!userName)
|
|
return;
|
|
|
|
this.removeUser(user);
|
|
|
|
let item = new UserListItem(user);
|
|
this._box.add(item.actor, { x_fill: true });
|
|
|
|
this._items[userName] = item;
|
|
|
|
item.connect('activate',
|
|
Lang.bind(this, this._onItemActivated));
|
|
|
|
// Try to keep the focused item front-and-center
|
|
item.actor.connect('key-focus-in',
|
|
Lang.bind(this,
|
|
function() {
|
|
this.scrollToItem(item);
|
|
}));
|
|
|
|
this._moveFocusToItems();
|
|
|
|
this.emit('item-added', item);
|
|
},
|
|
|
|
removeUser: function(user) {
|
|
if (!user.is_loaded)
|
|
return;
|
|
|
|
let userName = user.get_user_name();
|
|
|
|
if (!userName)
|
|
return;
|
|
|
|
let item = this._items[userName];
|
|
|
|
if (!item)
|
|
return;
|
|
|
|
item.actor.destroy();
|
|
delete this._items[userName];
|
|
}
|
|
});
|
|
Signals.addSignalMethods(UserList.prototype);
|