Skip to content

Commit

Permalink
[Issue #220] Add the library navigation tree
Browse files Browse the repository at this point in the history
* [Issue #220] Add the LibraryNavigationTree component and tests.

* [Issue #220] Integrate the library navigation tree into the interface.
  • Loading branch information
mcpierce committed Jun 21, 2020
1 parent 90b4026 commit 7fbbdd4
Show file tree
Hide file tree
Showing 16 changed files with 394 additions and 22 deletions.
@@ -1,3 +1,7 @@
<p-sidebar [visible]='showNavigationTree'
(onHide)='showNavigationTree = false'>
<app-library-navigation-tree></app-library-navigation-tree>
</p-sidebar>
<p-sidebar *ngIf='!!imageUrl && !!description'
[visible]='showDetails'
(onHide)='showDetails = false'
Expand All @@ -24,6 +28,13 @@
<p-toolbar styleClass='cx-library-toolbar'>
<div class='ui-toolbar-group-left'>
<button pButton
type='button'
icon='fa fa-fw fa-arrow-right'
class='ui-button-info'
[pTooltip]='"comic-list-toolbar.tooltip.show-navigation-tree"|translate'
(click)='showNavigationTree = true'></button>
<button pButton
type='button'
[icon]='gridLayout?"fa fa-fw fa-th":"fa fa-fw fa-list"'
(click)='setGridLayout(!gridLayout)'
[pTooltip]='"comic-list-toolbar.tooltip."+(gridLayout?"grid":"list")+"-layout"|translate'></button>
Expand Down
Expand Up @@ -44,12 +44,16 @@ import {
ConfirmationService,
DropdownModule,
MessageService,
ScrollPanelModule,
SidebarModule,
SliderModule,
ToolbarModule,
TooltipModule
TooltipModule,
TreeModule
} from 'primeng/primeng';
import { ComicListToolbarComponent } from './comic-list-toolbar.component';
import { LibraryNavigationTreeComponent } from 'app/library/components/library-navigation-tree/library-navigation-tree.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

describe('ComicListToolbarComponent', () => {
const COMICS = [COMIC_1, COMIC_3, COMIC_5];
Expand All @@ -66,6 +70,7 @@ describe('ComicListToolbarComponent', () => {
TestBed.configureTestingModule({
imports: [
ComicsModule,
BrowserAnimationsModule,
HttpClientTestingModule,
FormsModule,
RouterTestingModule,
Expand All @@ -88,9 +93,11 @@ describe('ComicListToolbarComponent', () => {
DropdownModule,
SliderModule,
CheckboxModule,
SidebarModule
SidebarModule,
TreeModule,
ScrollPanelModule
],
declarations: [ComicListToolbarComponent],
declarations: [ComicListToolbarComponent, LibraryNavigationTreeComponent],
providers: [
AuthenticationAdaptor,
SelectionAdaptor,
Expand Down
Expand Up @@ -66,6 +66,7 @@ export class ComicListToolbarComponent implements OnInit, OnDestroy {
enableDetails = false;
private _description: string = null;
private _imageUrl: string = null;
showNavigationTree = false;

constructor(
private translateService: TranslateService,
Expand Down
Expand Up @@ -64,7 +64,8 @@ import {
ProgressSpinnerModule,
SidebarModule,
ToolbarModule,
TooltipModule
TooltipModule,
TreeModule
} from 'primeng/primeng';
import { ScrollPanelModule } from 'primeng/scrollpanel';
import { SliderModule } from 'primeng/slider';
Expand All @@ -76,6 +77,7 @@ import {
ComicListComponent
} from './comic-list.component';
import { ConvertComicsSettingsComponent } from 'app/library/components/convert-comics-settings/convert-comics-settings.component';
import { LibraryNavigationTreeComponent } from 'app/library/components/library-navigation-tree/library-navigation-tree.component';

describe('ComicListComponent', () => {
const COMICS = [COMIC_1, COMIC_3, COMIC_5];
Expand Down Expand Up @@ -126,14 +128,16 @@ describe('ComicListComponent', () => {
ProgressSpinnerModule,
CheckboxModule,
DialogModule,
SidebarModule
SidebarModule,
TreeModule
],
declarations: [
ComicListComponent,
ComicListItemComponent,
ComicGridItemComponent,
ComicListToolbarComponent,
ConvertComicsSettingsComponent
ConvertComicsSettingsComponent,
LibraryNavigationTreeComponent
],
providers: [
AuthenticationAdaptor,
Expand Down
@@ -0,0 +1,4 @@
<p-scrollPanel>
<h3>{{'library-navigation-tree.title'|translate}}</h3>
<p-tree [value]='nodes'></p-tree>
</p-scrollPanel>
@@ -0,0 +1,9 @@
:host ::ng-deep .ui-scrollpanel {
width: 100%;
height: 100%;
}

:host ::ng-deep .ui-tree {
width: 100%;
border: none;
}
@@ -0,0 +1,68 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { LibraryNavigationTreeComponent } from './library-navigation-tree.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MessageService, ScrollPanelModule, TreeModule } from 'primeng/primeng';
import { LoggerModule } from '@angular-ru/logger';
import { TranslateModule } from '@ngx-translate/core';
import { LibraryAdaptor } from 'app/library';
import {
LIBRARY_FEATURE_KEY,
reducer
} from 'app/library/reducers/library.reducer';
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { LibraryEffects } from 'app/library/effects/library.effects';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ComicsModule } from 'app/comics/comics.module';

describe('LibraryNavigationTreeComponent', () => {
let component: LibraryNavigationTreeComponent;
let fixture: ComponentFixture<LibraryNavigationTreeComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
ComicsModule,
HttpClientTestingModule,
BrowserAnimationsModule,
LoggerModule.forRoot(),
TranslateModule.forRoot(),
StoreModule.forRoot({}),
StoreModule.forFeature(LIBRARY_FEATURE_KEY, reducer),
EffectsModule.forRoot([]),
EffectsModule.forFeature([LibraryEffects]),
TreeModule,
ScrollPanelModule
],
declarations: [LibraryNavigationTreeComponent],
providers: [LibraryAdaptor, MessageService]
}).compileComponents();

fixture = TestBed.createComponent(LibraryNavigationTreeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));

it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,195 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

import { Component, OnDestroy, OnInit } from '@angular/core';
import { LoggerService } from '@angular-ru/logger';
import { LibraryAdaptor } from 'app/library';
import { TreeNode } from 'primeng/api';
import { Subscription } from 'rxjs';
import { TranslateService } from '@ngx-translate/core';
import { ComicCollectionEntry } from 'app/library/models/comic-collection-entry';
import { NavigationDataPayload } from 'app/library/models/navigation-data-payload';

const PUBLISHER_NODE = 0;
const SERIES_NODE = 1;
const CHARACTER_NODE = 2;
const TEAM_NODE = 3;
const LOCATION_NODE = 4;
const STORY_NODE = 5;
const READING_LISTS = 6;

const LABEL_KEYS = [
'publishers',
'series',
'characters',
'teams',
'locations',
'stories',
'reading-lists'
];

@Component({
selector: 'app-library-navigation-tree',
templateUrl: './library-navigation-tree.component.html',
styleUrls: ['./library-navigation-tree.component.scss']
})
export class LibraryNavigationTreeComponent implements OnInit, OnDestroy {
private comicSubscription: Subscription;
private publisherSubscription: Subscription;
private seriesSubscription: Subscription;
private characterSubscription: Subscription;
private teamSubscription: Subscription;
private locationSubscription: Subscription;
private storiesSubscription: Subscription;

nodes: TreeNode[];

constructor(
private logger: LoggerService,
private translateService: TranslateService,
private libraryAdaptor: LibraryAdaptor
) {
this.nodes = [
{
// all comics
label: '',
icon: 'pi pi-folder',
children: [
{
// publishers
label: '',
icon: 'pi pi-folder'
} as TreeNode,
{
// series
label: '',
icon: 'pi pi-folder'
} as TreeNode,
{
// characters
label: '',
icon: 'pi pi-folder'
} as TreeNode,
{
// teams
label: '',
icon: 'pi pi-folder'
} as TreeNode,
{
// locations
label: '',
icon: 'pi pi-folder'
} as TreeNode,
{
// stories
label: '',
icon: 'pi pi-folder'
} as TreeNode,
{
// reading lists
label: this.translateService.instant(
'library-navigation-tree.label.reading-lists',
{ count: 0 }
),
icon: 'pi pi-folder'
} as TreeNode
]
} as TreeNode
];
this.comicSubscription = this.libraryAdaptor.comic$.subscribe(
comics =>
(this.nodes[0] = {
...this.nodes[0],
label: this.translateService.instant(
'library-navigation-tree.label.all-comics',
{ count: comics.length }
),
data: comics,
children: this.nodes[0].children
})
);
this.publisherSubscription = this.libraryAdaptor.publishers$.subscribe(
publishers => this.createChildNodes(PUBLISHER_NODE, publishers)
);
this.seriesSubscription = this.libraryAdaptor.series$.subscribe(series =>
this.createChildNodes(SERIES_NODE, series)
);
this.characterSubscription = this.libraryAdaptor.characters$.subscribe(
characters => this.createChildNodes(CHARACTER_NODE, characters)
);
this.teamSubscription = this.libraryAdaptor.teams$.subscribe(teams =>
this.createChildNodes(TEAM_NODE, teams)
);
this.locationSubscription = this.libraryAdaptor.locations$.subscribe(
locations => this.createChildNodes(LOCATION_NODE, locations)
);
this.storiesSubscription = this.libraryAdaptor.stories$.subscribe(stories =>
this.createChildNodes(STORY_NODE, stories)
);
}

ngOnInit() {}

ngOnDestroy(): void {
this.publisherSubscription.unsubscribe();
this.seriesSubscription.unsubscribe();
this.characterSubscription.unsubscribe();
this.teamSubscription.unsubscribe();
this.locationSubscription.unsubscribe();
this.storiesSubscription.unsubscribe();
}

private createChildNodes(
index: number,
collection: ComicCollectionEntry[]
): void {
this.nodes[0].children[index] = {
...this.nodes[0].children[index],
label: this.translateService.instant(
`library-navigation-tree.label.${LABEL_KEYS[index]}`,
{
count: collection.length
}
),
children: collection.map(entry => {
let entryName = entry.name;
if (!entryName || entryName.length === 0) {
entryName = this.translateService.instant(
'library-navigation-tree.label.unnamed-entry'
);
}
const title = this.translateService.instant(
'library-navigation-tree.label.leaf-entry',
{
name: entryName,
count: entry.count
}
);
return {
label: title,
data: {
title: title,
comics: entry.comics
} as NavigationDataPayload,
icon: 'pi pi-list',
expanded: this.nodes[0].children[index].expanded
} as TreeNode;
})
} as TreeNode;
}
}

0 comments on commit 7fbbdd4

Please sign in to comment.