Commit c032b3a3 authored by Sandro Lutz's avatar Sandro Lutz Committed by Sandro Lutz
Browse files

Improve user experience with FilteredListPage

* Adds a time delay until the loading animation is shown
* Adds the option to always show some lists regardless of the state of
the page
parent 08548286
...@@ -96,20 +96,32 @@ ...@@ -96,20 +96,32 @@
} }
.loading { .loading {
position: absolute; position: relative;
top: 50%; width: 100%;
left: 50%; height: 50vh;
transform: translateX(-50%) translateY(-50%);
> * {
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
}
} }
.empty-list { .empty-list {
position: absolute; position: relative;
top: 50%; width: 100%;
left: 50%; height: 50vh;
transform: translateX(-50%) translateY(-50%);
font-size: 1.2em; > * {
text-align: center; position: absolute;
width: calc(100% - 2em); top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
font-size: 1.2em;
text-align: center;
width: calc(100% - 2em);
}
} }
.list_header { .list_header {
......
...@@ -11,6 +11,7 @@ import { i18n, currentLanguage } from '../models/language'; ...@@ -11,6 +11,7 @@ import { i18n, currentLanguage } from '../models/language';
import FilterView from '../components/FilterView'; import FilterView from '../components/FilterView';
import icons from '../images/icons'; import icons from '../images/icons';
const LIST_LOADING_DELAY = 150;
const LIST_LOADING = 'loading'; const LIST_LOADING = 'loading';
const LIST_LOADED = 'loaded'; const LIST_LOADED = 'loaded';
const LIST_ERROR = 'error'; const LIST_ERROR = 'error';
...@@ -310,12 +311,17 @@ export class FilteredListPage { ...@@ -310,12 +311,17 @@ export class FilteredListPage {
} }
reload() { reload() {
this.dataStore.listState = LIST_LOADING; const timeout = setTimeout(() => {
this.dataStore.listState = LIST_LOADING;
m.redraw();
}, LIST_LOADING_DELAY);
return this._reloadData() return this._reloadData()
.then(() => { .then(() => {
clearTimeout(timeout);
this.dataStore.listState = LIST_LOADED; this.dataStore.listState = LIST_LOADED;
}) })
.catch(err => { .catch(err => {
clearTimeout(timeout);
error(err); error(err);
this.dataStore.listState = LIST_ERROR; this.dataStore.listState = LIST_ERROR;
}) })
...@@ -434,8 +440,10 @@ export class FilteredListPage { ...@@ -434,8 +440,10 @@ export class FilteredListPage {
values: this.dataStore.filterValues, values: this.dataStore.filterValues,
...this._filterViewAttributes, ...this._filterViewAttributes,
onchange: async values => { onchange: async values => {
this.dataStore.listState = LIST_LOADING; const timeout = setTimeout(() => {
m.redraw(); this.dataStore.listState = LIST_LOADING;
m.redraw();
}, LIST_LOADING_DELAY);
try { try {
await this._filterViewAttributes.onchange(values); await this._filterViewAttributes.onchange(values);
...@@ -445,8 +453,10 @@ export class FilteredListPage { ...@@ -445,8 +453,10 @@ export class FilteredListPage {
this._handleItemDirectLink(this.itemId); this._handleItemDirectLink(this.itemId);
} }
} }
clearTimeout(timeout);
this.dataStore.listState = LIST_LOADED; this.dataStore.listState = LIST_LOADED;
} catch (_error) { } catch (_error) {
clearTimeout(timeout);
this.dataStore.listState = LIST_ERROR; this.dataStore.listState = LIST_ERROR;
if (_error) error(_error); if (_error) error(_error);
} }
...@@ -458,42 +468,53 @@ export class FilteredListPage { ...@@ -458,42 +468,53 @@ export class FilteredListPage {
} }
get _listContainerView() { get _listContainerView() {
if (this.dataStore.listState === LIST_LOADING) { const lists = this._lists;
return m('div.loading', m(Spinner, { show: true, size: '96px' })); const listLoaded = this.dataStore.listState === LIST_LOADED;
const containsPinnedList = lists.some(
list => list.name === this.constructor.pinnedListIdentifier
);
let pinnedList;
if (this.dataStore.pinnedItem && !this.dataStore.pinnedItem.loading) {
pinnedList = this._renderList({
name: this.constructor.pinnedListIdentifier,
items: [this.dataStore.pinnedItem.item],
});
} }
if (this.dataStore.listState === LIST_LOADED) {
if (this._hasItems()) {
let pinnedList;
if (this.dataStore.pinnedItem && !this.dataStore.pinnedItem.loading) {
pinnedList = this._renderList({
name: this.constructor.pinnedListIdentifier,
items: [this.dataStore.pinnedItem.item],
});
}
const lists = this._lists; let fullPageMessage;
const containsPinnedList = lists.some(
list => list.name === this.constructor.pinnedListIdentifier
);
return [ if (this.dataStore.listState === LIST_LOADING) {
!containsPinnedList ? pinnedList : null, fullPageMessage = m('div.loading', m(Spinner, { show: true, size: '96px' }));
...lists.map(list => { } else if (this.dataStore.listState === LIST_ERROR) {
if (list.name === this.constructor.pinnedListIdentifier) { fullPageMessage = this.constructor._renderFullPageMessage(i18n('loadingError'));
return pinnedList; } else if (!this._hasItems()) {
} fullPageMessage = this.constructor._renderFullPageMessage(i18n('emptyList'));
return this._renderList(list);
}),
];
}
return this.constructor._renderFullPageMessage(i18n('emptyList'));
} }
return this.constructor._renderFullPageMessage(i18n('loadingError'));
return [
listLoaded && !containsPinnedList ? pinnedList : null,
...lists.map(list => {
if (list.permanent === true) {
return this._renderList(list);
}
if (listLoaded) {
if (list.name === this.constructor.pinnedListIdentifier) {
return pinnedList;
}
if (this._hasItems()) {
return this._renderList(list);
}
}
return null;
}),
fullPageMessage,
];
} }
static _renderFullPageMessage(message) { static _renderFullPageMessage(message) {
return m('span.empty-list', message); return m('div.empty-list', m('span', message));
} }
_renderList(list) { _renderList(list) {
......
...@@ -228,10 +228,12 @@ export default class StudydocList extends FilteredListPage { ...@@ -228,10 +228,12 @@ export default class StudydocList extends FilteredListPage {
return [ return [
{ {
name: 'quickfilter', name: 'quickfilter',
permanent: true,
items: [m(StudydocQuickFilter, { controller, dataStore })], items: [m(StudydocQuickFilter, { controller, dataStore })],
}, },
{ {
name: 'notice', name: 'notice',
permanent: true,
items: [ items: [
m(Infobox, { m(Infobox, {
icon: m(Icon, { svg: { content: m.trust(icons.info) } }), icon: m(Icon, { svg: { content: m.trust(icons.info) } }),
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment