feat(menu): add context menu

Closes #3
This commit is contained in:
Sebastian Lange
2019-05-27 16:38:47 +02:00
parent 3ce3c9ba16
commit 1dbf4515fe
27 changed files with 2261 additions and 767 deletions

View File

@@ -16,10 +16,11 @@ import {CommonModule} from '@angular/common';
import {HttpClientModule} from '@angular/common/http';
import {NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {IonicModule} from '@ionic/angular';
import {Events, IonicModule} from '@ionic/angular';
import {TranslateModule} from '@ngx-translate/core';
import {MarkdownModule} from 'ngx-markdown';
import {MomentModule} from 'ngx-moment';
import {MenuModule} from '../menu/menu.module';
import {StorageModule} from '../storage/storage.module';
import {DataFacetsProvider} from './data-facets.provider';
import {DataRoutingModule} from './data-routing.module';
@@ -116,6 +117,7 @@ import {VideoListItem} from './types/video/video-list-item.component';
DataRoutingModule,
HttpClientModule,
MarkdownModule.forRoot(),
MenuModule,
MomentModule.forRoot({
relativeTimeThresholdOptions: {
'm': 59,
@@ -127,6 +129,7 @@ import {VideoListItem} from './types/video/video-list-item.component';
providers: [
DataProvider,
DataFacetsProvider,
Events,
StAppsWebHttpClient,
],
})

View File

@@ -12,92 +12,157 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Component} from '@angular/core';
import {AlertController} from '@ionic/angular';
import {SCThing} from '@openstapps/core';
import {Component, OnInit} from '@angular/core';
import {AlertController, Events} from '@ionic/angular';
import {
SCFacet,
SCSearchFilter,
SCSearchQuery,
SCSearchSort,
SCSettingValue,
SCSettingValues,
SCThing,
} from '@openstapps/core';
import {Logger} from '@openstapps/logger';
import {Subject} from 'rxjs';
import {debounceTime, distinctUntilChanged} from 'rxjs/operators';
import {MenuService} from '../../menu/menu.service';
import {DataProvider} from '../data.provider';
/**
* TODO
* DataListComponent queries things and shows list of things and context menu
*/
@Component({
selector: 'stapps-data-list',
templateUrl: 'data-list.html',
})
export class DataListComponent {
export class DataListComponent implements OnInit {
/**
* TODO
* Api query filter
*/
dataProvider: DataProvider;
filterQuery: SCSearchFilter | undefined;
/**
* TODO
* Thing counter to start query the next page from
*/
from = 0;
/**
* TODO
* Container for queried things
*/
items: SCThing[];
/**
* TODO
* Page size of queries
*/
loaded = false;
pageSize = 30;
/**
* TODO
* Search value from search bar
*/
query: string;
/**
* TODO
*/
queryChanged: Subject<string> = new Subject<string>();
queryText: string;
/**
* TODO
* Subject to handle search text changes
*/
selectedItem: any;
/**
* TODO
*/
size = 30;
queryTextChanged: Subject<string> = new Subject<string>();
/**
*
* @param alertController TODO
* @param dataProvider TODO
* Time to wait for search query if search text is changing
*/
searchQueryDueTime = 1000;
/**
* Api query sorting
*/
sortQuery: SCSearchSort | undefined;
/**
*
* @param alertController AlertController
* @param dataProvider DataProvider
* @param events Events
* @param menuService MenuService
*/
constructor(
private readonly alertController: AlertController,
dataProvider: DataProvider,
) {
this.dataProvider = dataProvider;
this.queryChanged
private dataProvider: DataProvider,
private readonly events: Events,
private readonly menuService: MenuService,
) {
this.queryTextChanged
.pipe(
debounceTime(1000),
debounceTime(this.searchQueryDueTime),
distinctUntilChanged())
.subscribe((model) => {
this.from = 0;
this.query = model;
this.fetchItems();
this.queryText = model;
this.fetchAndUpdateItems();
});
this.fetchItems();
this.menuService.filterQueryChanged$.subscribe((query) => {
this.filterQuery = query;
this.fetchAndUpdateItems();
});
this.menuService.sortQueryChanged$.subscribe((query) => {
this.sortQuery = query;
this.fetchAndUpdateItems();
});
this.fetchAndUpdateItems();
/**
* Subscribe to 'settings.changed' events
*/
this.events.subscribe('stapps.settings.changed',
(category: string, name: string, value: SCSettingValue | SCSettingValues) => {
Logger.log(`received event "settings.changed" with category:
${category}, name: ${name}, value: ${JSON.stringify(value)}`);
},
);
}
/**
* TODO
* Fetches items with set query configuration
*
* @param append If true fetched data gets appended to existing, override otherwise (default false)
*/
private async fetchItems(): Promise<any> {
return this.dataProvider.search({
private async fetchAndUpdateItems(append = false): Promise<void> {
// build query search options
const searchOptions: SCSearchQuery = {
from: this.from,
query: this.query,
size: this.size,
} as any)
size: this.pageSize,
};
if (this.queryText && this.queryText.length > 0) {
// add query string
searchOptions.query = this.queryText;
}
if (this.filterQuery) {
// add query filtering
searchOptions.filter = this.filterQuery;
}
if (this.sortQuery) {
// add query sorting
searchOptions.sort = [this.sortQuery];
}
return this.dataProvider.search(searchOptions)
.then((result) => {
if (append) {
// append results
this.items = this.items.concat(result.data);
} else {
// override items with results
this.items = result.data;
this.loaded = true;
}
// update filter options if result contains facets
if (typeof result.facets !== 'undefined') {
this.updateContextFilter(result.facets);
}
}, async (err) => {
const alert: HTMLIonAlertElement = await this.alertController.create({
buttons: ['Dismiss'],
@@ -110,18 +175,52 @@ export class DataListComponent {
}
/**
* TODO
* Loads next page of things
*/
// tslint:disable-next-line:no-any
async loadMore(event: any): Promise<void> {
this.from += this.size;
await this.fetchItems();
this.from += this.pageSize;
await this.fetchAndUpdateItems(true);
event.target.complete();
}
/**
* TODO
* Initialises the sort context of menuService
*/
search(query: string) {
this.queryChanged.next(query);
ngOnInit(): void {
// initialise sort option for context menu
this.menuService.setContextSort({
name: 'sort',
reversed: false,
value: 'relevance',
values: [
{
reversible: false,
value: 'relevance',
},
{
reversible: true,
value: 'name',
},
{
reversible: true,
value: 'type',
},
],
});
}
/**
* Search event of search bar
*/
searchStringChanged(queryValue: string) {
this.queryTextChanged.next(queryValue);
}
/**
* Updates context filter in menuService with facets
*/
updateContextFilter(facets: SCFacet[]) {
this.menuService.updateContextFilter(facets);
}
}

View File

@@ -1,11 +1,17 @@
<stapps-context></stapps-context>
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
<ion-menu-button></ion-menu-button>
</ion-buttons>
<ion-buttons slot="end">
<ion-menu-button menu="context">
<ion-icon name="options"></ion-icon>
</ion-menu-button>
</ion-buttons>
<ion-searchbar (ngModelChange)="search($event)" [(ngModel)]="query"></ion-searchbar>
<ion-searchbar (ngModelChange)="searchStringChanged($event)" [(ngModel)]="queryText"></ion-searchbar>
<!--<ion-title>List</ion-title>-->
</ion-toolbar>