app-display: Implement filtering applications by category
Add a list of filters to the application view of the view selector, as in the latest mockups https://bugzilla.gnome.org/show_bug.cgi?id=631537
This commit is contained in:
parent
bdfc516715
commit
4fd24da4e4
@ -27,6 +27,7 @@ dist_theme_DATA = \
|
||||
theme/corner-ripple.png \
|
||||
theme/dash-placeholder.svg \
|
||||
theme/dialog-error.svg \
|
||||
theme/filter-selected.svg \
|
||||
theme/gnome-shell.css \
|
||||
theme/mosaic-view-active.svg \
|
||||
theme/mosaic-view.svg \
|
||||
|
@ -1,12 +1,30 @@
|
||||
<Menu>
|
||||
<DefaultLayout>
|
||||
<Menuname>Apps</Menuname>
|
||||
<Menuname>Accessories</Menuname>
|
||||
<Menuname>Games</Menuname>
|
||||
<Menuname>Tools</Menuname>
|
||||
<Menuname>Graphics</Menuname>
|
||||
<Menuname>Internet</Menuname>
|
||||
<Menuname>Multimedia</Menuname>
|
||||
<Menuname>Office</Menuname>
|
||||
<Menuname>Other</Menuname>
|
||||
</DefaultLayout>
|
||||
|
||||
<Name>Applications</Name>
|
||||
<AppDir>/usr/local/share/applications</AppDir>
|
||||
<DefaultAppDirs/>
|
||||
|
||||
<Menu>
|
||||
<Name>Accessories</Name>
|
||||
<Include>
|
||||
<And>
|
||||
<Category>Utility</Category>
|
||||
<Not>
|
||||
<Category>System</Category>
|
||||
</Not>
|
||||
</And>
|
||||
</Include>
|
||||
</Menu>
|
||||
|
||||
<Menu>
|
||||
<Name>Games</Name>
|
||||
<Include>
|
||||
@ -15,21 +33,47 @@
|
||||
</And>
|
||||
</Include>
|
||||
</Menu>
|
||||
|
||||
<Menu>
|
||||
<Name>Tools</Name>
|
||||
<Name>Graphics</Name>
|
||||
<Include>
|
||||
<Category>Development</Category>
|
||||
<And>
|
||||
<Category>System</Category>
|
||||
<Not>
|
||||
<Category>Settings</Category>
|
||||
</Not>
|
||||
<Category>Graphics</Category>
|
||||
</And>
|
||||
<Category>Utility</Category>
|
||||
</Include>
|
||||
</Menu>
|
||||
|
||||
<Menu>
|
||||
<Name>Apps</Name>
|
||||
<Name>Internet</Name>
|
||||
<Include>
|
||||
<And>
|
||||
<Category>Network</Category>
|
||||
<Not><Category>Settings</Category></Not>
|
||||
</And>
|
||||
</Include>
|
||||
</Menu>
|
||||
|
||||
<Menu>
|
||||
<Name>Multimedia</Name>
|
||||
<Include>
|
||||
<And>
|
||||
<Category>AudioVideo</Category>
|
||||
<Not><Category>Settings</Category></Not>
|
||||
</And>
|
||||
</Include>
|
||||
</Menu>
|
||||
|
||||
<Menu>
|
||||
<Name>Office</Name>
|
||||
<Include>
|
||||
<And>
|
||||
<Category>Office</Category>
|
||||
</And>
|
||||
</Include>
|
||||
</Menu>
|
||||
|
||||
<Menu>
|
||||
<Name>Other</Name>
|
||||
<OnlyUnallocated/>
|
||||
<Include>
|
||||
<And>
|
||||
|
81
data/theme/filter-selected.svg
Normal file
81
data/theme/filter-selected.svg
Normal file
@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="10"
|
||||
height="20"
|
||||
id="svg10003"
|
||||
version="1.1"
|
||||
inkscape:version="0.47 r22583"
|
||||
sodipodi:docname="filter-selected.svg">
|
||||
<defs
|
||||
id="defs10005">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 32 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="64 : 32 : 1"
|
||||
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||
id="perspective10011" />
|
||||
<inkscape:perspective
|
||||
id="perspective9998"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="5.5"
|
||||
inkscape:cx="32"
|
||||
inkscape:cy="10.181818"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:window-height="994"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata10008">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
transform="translate(0,-44)">
|
||||
<path
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-shell-design/mockups/app-picker.png"
|
||||
sodipodi:nodetypes="cccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="rect34320"
|
||||
d="m -0.18726572,54.181804 10.55634072,10.55636 10e-6,-21.11269 z"
|
||||
style="opacity:0.21000001;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.99999988;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
@ -470,26 +470,28 @@ StTooltip StLabel {
|
||||
|
||||
/* Apps */
|
||||
|
||||
.overview-pane {
|
||||
width: 440px;
|
||||
}
|
||||
|
||||
.icon-grid {
|
||||
spacing: 36px;
|
||||
-shell-grid-item-size: 70px;
|
||||
}
|
||||
|
||||
.all-app {
|
||||
padding: 16px 250px 10px 16px;
|
||||
padding: 16px 25px 16px 16px;
|
||||
spacing: 20px;
|
||||
}
|
||||
|
||||
.app-section-divider-container {
|
||||
padding-top: 36px;
|
||||
padding-bottom: 36px;
|
||||
.app-filter {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
height: 40px;
|
||||
color: #aaa;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.app-section-divider {
|
||||
height: 2px;
|
||||
.app-filter:selected {
|
||||
color: #ffffff;
|
||||
background-image: url("filter-selected.svg");
|
||||
background-position: 190px 10px;
|
||||
}
|
||||
|
||||
#dash > .app-well-app {
|
||||
|
@ -29,10 +29,20 @@ function AlphabeticalView() {
|
||||
|
||||
AlphabeticalView.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new St.BoxLayout({ vertical: true });
|
||||
this._grid = new IconGrid.IconGrid({ xAlign: St.Align.START });
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
this.actor.add(this._grid.actor, { y_align: St.Align.START, expand: true });
|
||||
|
||||
this._filterApp = null;
|
||||
|
||||
let box = new St.BoxLayout({ vertical: true });
|
||||
box.add(this._grid.actor, { y_align: St.Align.START, expand: true });
|
||||
|
||||
this.actor = new St.ScrollView({ x_fill: true,
|
||||
y_fill: false,
|
||||
y_align: St.Align.START,
|
||||
vshadows: true });
|
||||
this.actor.add_actor(box);
|
||||
this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
|
||||
},
|
||||
|
||||
_removeAll: function() {
|
||||
@ -40,20 +50,24 @@ AlphabeticalView.prototype = {
|
||||
this._apps = [];
|
||||
},
|
||||
|
||||
_addApp: function(app) {
|
||||
let appIcon = new AppWellIcon(this._appSystem.get_app(app.get_id()));
|
||||
appIcon.connect('launching', Lang.bind(this, function() {
|
||||
this.emit('launching');
|
||||
}));
|
||||
appIcon._draggable.connect('drag-begin', Lang.bind(this, function() {
|
||||
this.emit('drag-begin');
|
||||
}));
|
||||
_addApp: function(appInfo) {
|
||||
let appIcon = new AppWellIcon(this._appSystem.get_app(appInfo.get_id()));
|
||||
|
||||
this._grid.addItem(appIcon.actor);
|
||||
|
||||
appIcon._appInfo = appInfo;
|
||||
if (this._filterApp && !this._filterApp(appInfo))
|
||||
appIcon.actor.hide();
|
||||
|
||||
this._apps.push(appIcon);
|
||||
},
|
||||
|
||||
setFilter: function(filter) {
|
||||
this._filterApp = filter;
|
||||
for (let i = 0; i < this._apps.length; i++)
|
||||
this._apps[i].actor.visible = filter(this._apps[i]._appInfo);
|
||||
},
|
||||
|
||||
refresh: function(apps) {
|
||||
let ids = [];
|
||||
for (let i in apps)
|
||||
@ -70,8 +84,6 @@ AlphabeticalView.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(AlphabeticalView.prototype);
|
||||
|
||||
function ViewByCategories() {
|
||||
this._init();
|
||||
}
|
||||
@ -79,59 +91,78 @@ function ViewByCategories() {
|
||||
ViewByCategories.prototype = {
|
||||
_init: function() {
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
this.actor = new St.BoxLayout({ vertical: true });
|
||||
this.actor = new St.BoxLayout({ style_class: 'all-app' });
|
||||
this.actor._delegate = this;
|
||||
|
||||
this._view = new AlphabeticalView();
|
||||
|
||||
this._filters = new St.BoxLayout({ vertical: true });
|
||||
this.actor.add(this._view.actor, { expand: true, x_fill: true, y_fill: true });
|
||||
this.actor.add(this._filters, { expand: false, y_fill: false, y_align: St.Align.START });
|
||||
|
||||
this._sections = [];
|
||||
},
|
||||
|
||||
_updateSections: function(apps) {
|
||||
this._removeAll();
|
||||
_selectCategory: function(num) {
|
||||
if (num != -1)
|
||||
this._allFilter.remove_style_pseudo_class('selected');
|
||||
else
|
||||
this._allFilter.add_style_pseudo_class('selected');
|
||||
|
||||
let sections = this._appSystem.get_sections();
|
||||
if (!sections)
|
||||
return;
|
||||
for (let i = 0; i < sections.length; i++) {
|
||||
if (i) {
|
||||
let actor = new St.Bin({ style_class: 'app-section-divider' });
|
||||
let divider = new St.Bin({ style_class: 'app-section-divider-container',
|
||||
child: actor,
|
||||
x_fill: true });
|
||||
this._view.setFilter(Lang.bind(this, function(app) {
|
||||
if (num == -1)
|
||||
return true;
|
||||
return this._sections[num].name == app.get_section();
|
||||
}));
|
||||
|
||||
this.actor.add(divider, { y_fill: false, expand: true });
|
||||
for (let i = 0; i < this._sections.length; i++) {
|
||||
if (i == num)
|
||||
this._sections[i].filterActor.add_style_pseudo_class('selected');
|
||||
else
|
||||
this._sections[i].filterActor.remove_style_pseudo_class('selected');
|
||||
}
|
||||
let _apps = apps.filter(function(app) {
|
||||
return app.get_section() == sections[i];
|
||||
});
|
||||
this._sections[i] = { view: new AlphabeticalView(),
|
||||
apps: _apps,
|
||||
name: sections[i] };
|
||||
this._sections[i].view.connect('launching', Lang.bind(this, function() {
|
||||
this.emit('launching');
|
||||
},
|
||||
|
||||
_addFilter: function(name, num) {
|
||||
let button = new St.Button({ label: name,
|
||||
style_class: 'app-filter',
|
||||
x_align: St.Align.START });
|
||||
this._filters.add(button, { expand: true, x_fill: true, y_fill: false });
|
||||
button.connect('clicked', Lang.bind(this, function() {
|
||||
this._selectCategory(num);
|
||||
}));
|
||||
this._sections[i].view.connect('drag-begin', Lang.bind(this, function() {
|
||||
this.emit('drag-begin');
|
||||
}));
|
||||
this.actor.add(this._sections[i].view.actor, { y_align: St.Align.START, expand: true });
|
||||
}
|
||||
|
||||
if (num != -1)
|
||||
this._sections[num] = { filterActor: button,
|
||||
name: name };
|
||||
else
|
||||
this._allFilter = button;
|
||||
},
|
||||
|
||||
_removeAll: function() {
|
||||
this.actor.destroy_children();
|
||||
this._sections.forEach(function (section) { section.view.disconnectAll(); });
|
||||
|
||||
this._sections = [];
|
||||
this._filters.destroy_children();
|
||||
},
|
||||
|
||||
refresh: function(apps) {
|
||||
this._updateSections(apps);
|
||||
for (let i = 0; i < this._sections.length; i++) {
|
||||
this._sections[i].view.refresh(this._sections[i].apps);
|
||||
}
|
||||
this._removeAll();
|
||||
|
||||
let sections = this._appSystem.get_sections();
|
||||
this._apps = apps;
|
||||
this._view.refresh(apps);
|
||||
|
||||
this._addFilter(_("All"), -1);
|
||||
|
||||
if (!sections)
|
||||
return;
|
||||
|
||||
for (let i = 0; i < sections.length; i++)
|
||||
this._addFilter(sections[i], i);
|
||||
|
||||
this._selectCategory(-1);
|
||||
}
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(ViewByCategories.prototype);
|
||||
|
||||
/* This class represents a display containing a collection of application items.
|
||||
* The applications are sorted based on their name.
|
||||
*/
|
||||
@ -146,17 +177,8 @@ AllAppDisplay.prototype = {
|
||||
Main.queueDeferredWork(this._workId);
|
||||
}));
|
||||
|
||||
this._scrollView = new St.ScrollView({ x_fill: true,
|
||||
y_fill: false,
|
||||
vshadows: true });
|
||||
this.actor = new St.Bin({ style_class: 'all-app',
|
||||
y_align: St.Align.START,
|
||||
child: this._scrollView });
|
||||
|
||||
this._appView = new ViewByCategories();
|
||||
this._scrollView.add_actor(this._appView.actor);
|
||||
|
||||
this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
|
||||
this.actor = new St.Bin({ child: this._appView.actor, x_fill: true, y_fill: true });
|
||||
|
||||
this._workId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplay));
|
||||
},
|
||||
@ -169,8 +191,6 @@ AllAppDisplay.prototype = {
|
||||
this._appView.refresh(apps);
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(AllAppDisplay.prototype);
|
||||
|
||||
|
||||
function BaseAppSearchProvider() {
|
||||
this._init();
|
||||
|
Loading…
Reference in New Issue
Block a user