appDisplay: Remove Frequent view
The Frequent apps grid has a few problems: * On a fresh install there would be no history of app usage so the applications shown in the grid have no relevance it takes time to be useful instead of being useful from the start; * The grid has far too many items in it to be relevant; 24 apps is well beyond the average use case as most people don't frequently use that many, so it gets populated with several apps that are single use (hello xterm); * The position of items in the grid are always changing based on an unknown frequency metric (and not by user-intended input) which makes it a poor way to quickly launch apps as one would have to constantly learn the positions of the items in the grid; * Having two app grids is a bit superfluous and needlessly complicates the app launching navigation: you have to spend time checking the frequent grid and if it's not there you have to switch over to another grid and find the app you need in there it's not straightforward. Remove the Frequent tab and simplify the related code. Related: https://gitlab.gnome.org/GNOME/gnome-shell/issues/1425 https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/880
This commit is contained in:
parent
4ae04d5aa8
commit
548e19a7cd
@ -14,8 +14,6 @@ $app_icon_padding: 24px;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//.app-display { spacing: 20px; }
|
|
||||||
|
|
||||||
/* App Icons */
|
/* App Icons */
|
||||||
|
|
||||||
$app_grid_fg_color: #fff;
|
$app_grid_fg_color: #fff;
|
||||||
@ -123,15 +121,11 @@ $app_grid_fg_color: #fff;
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Some hacks I don't even know
|
// Some hacks I don't even know
|
||||||
.all-apps,
|
.all-apps {
|
||||||
.frequent-apps > StBoxLayout {
|
|
||||||
// horizontal padding to make sure scrollbars or dash don't overlap content
|
// horizontal padding to make sure scrollbars or dash don't overlap content
|
||||||
padding: 0px 88px 10px 88px;
|
padding: 0px 88px 10px 88px;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Label when no frequent apps
|
|
||||||
.no-frequent-applications-label { @extend %status_text; }
|
|
||||||
|
|
||||||
// shutdown and other actions in the grid
|
// shutdown and other actions in the grid
|
||||||
.system-action-icon {
|
.system-action-icon {
|
||||||
background-color: rgba(0,0,0,0.8);
|
background-color: rgba(0,0,0,0.8);
|
||||||
@ -139,44 +133,3 @@ $app_grid_fg_color: #fff;
|
|||||||
border-radius: 99px;
|
border-radius: 99px;
|
||||||
icon-size: $app_icon_size * 0.5;
|
icon-size: $app_icon_size * 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Frequent | All toggle */
|
|
||||||
|
|
||||||
// container
|
|
||||||
.app-view-controls {
|
|
||||||
padding-bottom: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// buttons
|
|
||||||
.app-view-control {
|
|
||||||
padding: 4px 32px;
|
|
||||||
margin: 0 4px;
|
|
||||||
|
|
||||||
&, &:hover, &:checked {
|
|
||||||
@include button(undecorated);
|
|
||||||
color: darken($osd_fg_color, 25%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: $osd_fg_color;
|
|
||||||
box-shadow: inset 0 -2px darken($osd_fg_color, 25%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
box-shadow: inset 0 -2px $osd_fg_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:checked {
|
|
||||||
color: $osd_fg_color;
|
|
||||||
box-shadow: inset 0 -2px $selected_bg_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
border-right-width: 0;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -29,8 +29,6 @@ var INACTIVE_GRID_OPACITY = 77;
|
|||||||
var INACTIVE_GRID_OPACITY_ANIMATION_TIME = 240;
|
var INACTIVE_GRID_OPACITY_ANIMATION_TIME = 240;
|
||||||
var FOLDER_SUBICON_FRACTION = .4;
|
var FOLDER_SUBICON_FRACTION = .4;
|
||||||
|
|
||||||
var MIN_FREQUENT_APPS_COUNT = 3;
|
|
||||||
|
|
||||||
var VIEWS_SWITCH_TIME = 400;
|
var VIEWS_SWITCH_TIME = 400;
|
||||||
var VIEWS_SWITCH_ANIMATION_DELAY = 100;
|
var VIEWS_SWITCH_ANIMATION_DELAY = 100;
|
||||||
|
|
||||||
@ -954,119 +952,6 @@ var AllView = GObject.registerClass({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var FrequentView = GObject.registerClass(
|
|
||||||
class FrequentView extends BaseAppView {
|
|
||||||
_init() {
|
|
||||||
super._init({
|
|
||||||
style_class: 'frequent-apps',
|
|
||||||
layout_manager: new Clutter.BinLayout(),
|
|
||||||
x_expand: true,
|
|
||||||
y_expand: true,
|
|
||||||
}, { fillParent: true });
|
|
||||||
|
|
||||||
this._noFrequentAppsLabel = new St.Label({ text: _("Frequently used applications will appear here"),
|
|
||||||
style_class: 'no-frequent-applications-label',
|
|
||||||
x_align: Clutter.ActorAlign.CENTER,
|
|
||||||
x_expand: true,
|
|
||||||
y_align: Clutter.ActorAlign.CENTER,
|
|
||||||
y_expand: true });
|
|
||||||
|
|
||||||
this._grid.y_expand = true;
|
|
||||||
|
|
||||||
this.add_actor(this._grid);
|
|
||||||
this.add_actor(this._noFrequentAppsLabel);
|
|
||||||
this._noFrequentAppsLabel.hide();
|
|
||||||
|
|
||||||
this._usage = Shell.AppUsage.get_default();
|
|
||||||
}
|
|
||||||
|
|
||||||
vfunc_map() {
|
|
||||||
this._redisplay();
|
|
||||||
super.vfunc_map();
|
|
||||||
}
|
|
||||||
|
|
||||||
hasUsefulData() {
|
|
||||||
return this._usage.get_most_used().length >= MIN_FREQUENT_APPS_COUNT;
|
|
||||||
}
|
|
||||||
|
|
||||||
_compareItems() {
|
|
||||||
// The FrequentView does not need to be sorted alphabetically
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_loadApps() {
|
|
||||||
let apps = [];
|
|
||||||
let mostUsed = this._usage.get_most_used();
|
|
||||||
let hasUsefulData = this.hasUsefulData();
|
|
||||||
this._noFrequentAppsLabel.visible = !hasUsefulData;
|
|
||||||
if (!hasUsefulData)
|
|
||||||
return [];
|
|
||||||
|
|
||||||
// Allow dragging of the icon only if the Dash would accept a drop to
|
|
||||||
// change favorite-apps. There are no other possible drop targets from
|
|
||||||
// the app picker, so there's no other need for a drag to start,
|
|
||||||
// at least on single-monitor setups.
|
|
||||||
// This also disables drag-to-launch on multi-monitor setups,
|
|
||||||
// but we hope that is not used much.
|
|
||||||
let favoritesWritable = global.settings.is_writable('favorite-apps');
|
|
||||||
|
|
||||||
for (let i = 0; i < mostUsed.length; i++) {
|
|
||||||
if (!this._parentalControlsManager.shouldShowApp(mostUsed[i].get_app_info()))
|
|
||||||
continue;
|
|
||||||
let appIcon = this._items.get(mostUsed[i].get_id());
|
|
||||||
if (!appIcon) {
|
|
||||||
appIcon = new AppIcon(mostUsed[i], {
|
|
||||||
isDraggable: favoritesWritable,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
apps.push(appIcon);
|
|
||||||
}
|
|
||||||
|
|
||||||
return apps;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called before allocation to calculate dynamic spacing
|
|
||||||
adaptToSize(width, height) {
|
|
||||||
let box = new Clutter.ActorBox();
|
|
||||||
box.x1 = box.y1 = 0;
|
|
||||||
box.x2 = width;
|
|
||||||
box.y2 = height;
|
|
||||||
box = this.get_theme_node().get_content_box(box);
|
|
||||||
box = this._grid.get_theme_node().get_content_box(box);
|
|
||||||
let availWidth = box.x2 - box.x1;
|
|
||||||
let availHeight = box.y2 - box.y1;
|
|
||||||
this._grid.adaptToSize(availWidth, availHeight);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var Views = {
|
|
||||||
FREQUENT: 0,
|
|
||||||
ALL: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
var ControlsBoxLayout = GObject.registerClass(
|
|
||||||
class ControlsBoxLayout extends Clutter.BoxLayout {
|
|
||||||
/*
|
|
||||||
* Override the BoxLayout behavior to use the maximum preferred width of all
|
|
||||||
* buttons for each child
|
|
||||||
*/
|
|
||||||
vfunc_get_preferred_width(container, forHeight) {
|
|
||||||
let maxMinWidth = 0;
|
|
||||||
let maxNaturalWidth = 0;
|
|
||||||
for (let child = container.get_first_child();
|
|
||||||
child;
|
|
||||||
child = child.get_next_sibling()) {
|
|
||||||
let [minWidth, natWidth] = child.get_preferred_width(forHeight);
|
|
||||||
maxMinWidth = Math.max(maxMinWidth, minWidth);
|
|
||||||
maxNaturalWidth = Math.max(maxNaturalWidth, natWidth);
|
|
||||||
}
|
|
||||||
let childrenCount = container.get_n_children();
|
|
||||||
let totalSpacing = this.spacing * (childrenCount - 1);
|
|
||||||
return [maxMinWidth * childrenCount + totalSpacing,
|
|
||||||
maxNaturalWidth * childrenCount + totalSpacing];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var ViewStackLayout = GObject.registerClass({
|
var ViewStackLayout = GObject.registerClass({
|
||||||
Signals: { 'allocated-size-changed': { param_types: [GObject.TYPE_INT,
|
Signals: { 'allocated-size-changed': { param_types: [GObject.TYPE_INT,
|
||||||
GObject.TYPE_INT] } },
|
GObject.TYPE_INT] } },
|
||||||
@ -1091,70 +976,14 @@ class AppDisplay extends St.BoxLayout {
|
|||||||
y_expand: true,
|
y_expand: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
this._privacySettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.privacy' });
|
this._view = new AllView();
|
||||||
this._privacySettings.connect('changed::remember-app-usage',
|
|
||||||
this._updateFrequentVisibility.bind(this));
|
|
||||||
|
|
||||||
this._views = [];
|
|
||||||
|
|
||||||
let view, button;
|
|
||||||
view = new FrequentView();
|
|
||||||
button = new St.Button({ label: _("Frequent"),
|
|
||||||
style_class: 'app-view-control button',
|
|
||||||
can_focus: true,
|
|
||||||
x_expand: true });
|
|
||||||
this._views[Views.FREQUENT] = { view, 'control': button };
|
|
||||||
|
|
||||||
view = new AllView();
|
|
||||||
button = new St.Button({ label: _("All"),
|
|
||||||
style_class: 'app-view-control button',
|
|
||||||
can_focus: true,
|
|
||||||
x_expand: true });
|
|
||||||
this._views[Views.ALL] = { view, 'control': button };
|
|
||||||
|
|
||||||
this._viewStackLayout = new ViewStackLayout();
|
this._viewStackLayout = new ViewStackLayout();
|
||||||
this._viewStack = new St.Widget({ x_expand: true, y_expand: true,
|
this._viewStack = new St.Widget({ x_expand: true, y_expand: true,
|
||||||
layout_manager: this._viewStackLayout });
|
layout_manager: this._viewStackLayout });
|
||||||
this._viewStackLayout.connect('allocated-size-changed', this._onAllocatedSizeChanged.bind(this));
|
this._viewStackLayout.connect('allocated-size-changed', this._onAllocatedSizeChanged.bind(this));
|
||||||
this.add_actor(this._viewStack);
|
this.add_actor(this._viewStack);
|
||||||
let layout = new ControlsBoxLayout({ homogeneous: true });
|
|
||||||
this._controls = new St.Widget({
|
|
||||||
style_class: 'app-view-controls',
|
|
||||||
layout_manager: layout,
|
|
||||||
x_align: Clutter.ActorAlign.CENTER,
|
|
||||||
});
|
|
||||||
this._controls.connect('notify::mapped', () => {
|
|
||||||
// controls are faded either with their parent or
|
|
||||||
// explicitly in animate(); we can't know how they'll be
|
|
||||||
// shown next, so make sure to restore their opacity
|
|
||||||
// when they are hidden
|
|
||||||
if (this._controls.mapped)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._controls.remove_all_transitions();
|
this._viewStack.add_actor(this._view);
|
||||||
this._controls.opacity = 255;
|
|
||||||
});
|
|
||||||
|
|
||||||
layout.hookup_style(this._controls);
|
|
||||||
this.add_actor(new St.Bin({ child: this._controls }));
|
|
||||||
|
|
||||||
for (let i = 0; i < this._views.length; i++) {
|
|
||||||
this._viewStack.add_actor(this._views[i].view);
|
|
||||||
this._controls.add_actor(this._views[i].control);
|
|
||||||
|
|
||||||
let viewIndex = i;
|
|
||||||
this._views[i].control.connect('clicked', () => {
|
|
||||||
this._showView(viewIndex);
|
|
||||||
global.settings.set_uint('app-picker-view', viewIndex);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let initialView = Math.min(global.settings.get_uint('app-picker-view'),
|
|
||||||
this._views.length - 1);
|
|
||||||
let frequentUseful = this._views[Views.FREQUENT].view.hasUsefulData();
|
|
||||||
if (initialView == Views.FREQUENT && !frequentUseful)
|
|
||||||
initialView = Views.ALL;
|
|
||||||
this._showView(initialView);
|
|
||||||
this._updateFrequentVisibility();
|
|
||||||
|
|
||||||
this._switcherooNotifyId = global.connect('notify::switcheroo-control',
|
this._switcherooNotifyId = global.connect('notify::switcheroo-control',
|
||||||
() => this._updateDiscreteGpuAvailable());
|
() => this._updateDiscreteGpuAvailable());
|
||||||
@ -1172,56 +1001,11 @@ class AppDisplay extends St.BoxLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
animate(animationDirection, onComplete) {
|
animate(animationDirection, onComplete) {
|
||||||
let currentView = this._views.filter(v => v.control.has_style_pseudo_class('checked')).pop().view;
|
this._view.animate(animationDirection, onComplete);
|
||||||
|
|
||||||
// Animate controls opacity using iconGrid animation time, since
|
|
||||||
// it will be the time the AllView or FrequentView takes to show
|
|
||||||
// it entirely.
|
|
||||||
let finalOpacity;
|
|
||||||
if (animationDirection == IconGrid.AnimationDirection.IN) {
|
|
||||||
this._controls.opacity = 0;
|
|
||||||
finalOpacity = 255;
|
|
||||||
} else {
|
|
||||||
finalOpacity = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._controls.ease({
|
|
||||||
opacity: finalOpacity,
|
|
||||||
duration: IconGrid.ANIMATION_TIME_IN,
|
|
||||||
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
|
|
||||||
});
|
|
||||||
|
|
||||||
currentView.animate(animationDirection, onComplete);
|
|
||||||
}
|
|
||||||
|
|
||||||
_showView(activeIndex) {
|
|
||||||
for (let i = 0; i < this._views.length; i++) {
|
|
||||||
if (i == activeIndex)
|
|
||||||
this._views[i].control.add_style_pseudo_class('checked');
|
|
||||||
else
|
|
||||||
this._views[i].control.remove_style_pseudo_class('checked');
|
|
||||||
|
|
||||||
let animationDirection = i == activeIndex
|
|
||||||
? IconGrid.AnimationDirection.IN
|
|
||||||
: IconGrid.AnimationDirection.OUT;
|
|
||||||
this._views[i].view.animateSwitch(animationDirection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_updateFrequentVisibility() {
|
|
||||||
let enabled = this._privacySettings.get_boolean('remember-app-usage');
|
|
||||||
this._views[Views.FREQUENT].control.visible = enabled;
|
|
||||||
|
|
||||||
let visibleViews = this._views.filter(v => v.control.visible);
|
|
||||||
this._controls.visible = visibleViews.length > 1;
|
|
||||||
|
|
||||||
if (!enabled && this._views[Views.FREQUENT].view.visible)
|
|
||||||
this._showView(Views.ALL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
selectApp(id) {
|
selectApp(id) {
|
||||||
this._showView(Views.ALL);
|
this._view.selectApp(id);
|
||||||
this._views[Views.ALL].view.selectApp(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_onAllocatedSizeChanged(actor, width, height) {
|
_onAllocatedSizeChanged(actor, width, height) {
|
||||||
@ -1232,8 +1016,7 @@ class AppDisplay extends St.BoxLayout {
|
|||||||
box = this._viewStack.get_theme_node().get_content_box(box);
|
box = this._viewStack.get_theme_node().get_content_box(box);
|
||||||
let availWidth = box.x2 - box.x1;
|
let availWidth = box.x2 - box.x1;
|
||||||
let availHeight = box.y2 - box.y1;
|
let availHeight = box.y2 - box.y1;
|
||||||
for (let i = 0; i < this._views.length; i++)
|
this._view.adaptToSize(availWidth, availHeight);
|
||||||
this._views[i].view.adaptToSize(availWidth, availHeight);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user