Skip to content
This repository has been archived by the owner on Feb 12, 2022. It is now read-only.

Commit

Permalink
Merge pull request #93 from seokju-na/geeks-diary-39
Browse files Browse the repository at this point in the history
App Settings
  • Loading branch information
seokju-na committed Dec 12, 2018
2 parents db245e3 + 807811d commit 435783b
Show file tree
Hide file tree
Showing 63 changed files with 1,627 additions and 109 deletions.
3 changes: 3 additions & 0 deletions src/browser/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
@import "app/all-theme";
@import "note/all-theme";
@import "vcs/all-theme";
@import "settings/all-theme";

@include ui-core();

Expand All @@ -18,11 +19,13 @@
@include gd-ui-all-theme($basic-light-theme);
@include gd-note-all-theme($basic-light-theme);
@include gd-vcs-all-theme($basic-light-theme);
@include gd-settings-all-theme($basic-light-theme);
}

.BasicDarkTheme {
@include gd-app-all-theme($basic-dark-theme);
@include gd-ui-all-theme($basic-dark-theme);
@include gd-note-all-theme($basic-dark-theme);
@include gd-vcs-all-theme($basic-dark-theme);
@include gd-settings-all-theme($basic-dark-theme);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
</button>
</li>
</ul>

<button gd-icon-button aria-label="Open Settings" [bigSize]="true"
(click)="openSettingsDialog()" class="AppLayoutSidenav__settingsButton">
<gd-icon name="cog" [bigSize]="true"></gd-icon>
</button>
</nav>

<gd-resizable-content role="tabpanel" [minWidth]="200" [maxWidth]="375" class="AppLayoutSidenav__panel">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
justify-content: space-between;
width: $app-layout-sidenav-nav-size;
height: 100%;
padding-bottom: $spacing-half;
}

&__tabList {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { Component, NgModule } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { combineReducers, StoreModule } from '@ngrx/store';
import { Subject } from 'rxjs';
import { fastTestSetup } from '../../../../../test/helpers';
import { SettingsDialog } from '../../../settings';
import { MenuEvent, MenuService } from '../../../shared';
import { AppLayoutModule } from '../app-layout.module';
import { appLayoutReducer } from '../app-layout.reducer';
import { AppLayoutSidenavOutlet } from '../app-layout.state';
Expand Down Expand Up @@ -53,6 +57,11 @@ describe('browser.app.appLayout.AppLayoutSidenavComponent', () => {
let fixture: ComponentFixture<AppLayoutSidenavComponent>;
let component: AppLayoutSidenavComponent;

let settingsDialog: SettingsDialog;
let menu: MenuService;

let menuMessages: Subject<MenuEvent>;

const outlets: AppLayoutSidenavOutlet[] = [
{
id: 'outlet-1',
Expand All @@ -75,17 +84,51 @@ describe('browser.app.appLayout.AppLayoutSidenavComponent', () => {
fastTestSetup();

beforeAll(async () => {
settingsDialog = jasmine.createSpyObj('settingsDialog', [
'open',
]);
menu = jasmine.createSpyObj('menu', [
'onMessage',
]);

await TestBed
.configureTestingModule({
imports: [TestAppLayoutSidenavModule],
providers: [
{ provide: SettingsDialog, useValue: settingsDialog },
{ provide: MenuService, useValue: menu },
],
})
.compileComponents();
});

beforeEach(() => {
menuMessages = new Subject();
(menu.onMessage as jasmine.Spy).and.callFake(() => menuMessages.asObservable());

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

describe('toggle panel', () => {
});

describe('settings', () => {
it('should open settings dialog when click settings button.', () => {
const settingsButtonEl = fixture.debugElement.query(
By.css('.AppLayoutSidenav__settingsButton'),
).nativeElement as HTMLButtonElement;

settingsButtonEl.click();

expect(settingsDialog.open).toHaveBeenCalled();
});

it('should open settings dialog when menu event called.', () => {
menuMessages.next(MenuEvent.OPEN_SETTINGS);
expect(settingsDialog.open).toHaveBeenCalled();
});
});
});
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Component, Injector, Input } from '@angular/core';
import { Component, Injector, Input, OnInit } from '@angular/core';
import { select, Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { share } from 'rxjs/operators';
import { filter, share } from 'rxjs/operators';
import { SettingsDialog } from '../../../settings';
import { MenuEvent, MenuService } from '../../../shared';
import { AppState } from '../../app.state';
import { ToggleSidenavPanelAction } from '../app-layout.actions';
import { AppLayoutSidenavOutlet } from '../app-layout.state';
Expand All @@ -12,7 +14,7 @@ import { AppLayoutSidenavOutlet } from '../app-layout.state';
templateUrl: './app-layout-sidenav.component.html',
styleUrls: ['./app-layout-sidenav.component.scss'],
})
export class AppLayoutSidenavComponent {
export class AppLayoutSidenavComponent implements OnInit {
@Input() outlets: AppLayoutSidenavOutlet[];

readonly showPanel: Observable<boolean> = this.store.pipe(
Expand All @@ -28,10 +30,22 @@ export class AppLayoutSidenavComponent {
constructor(
private store: Store<AppState>,
public _injector: Injector,
private settingsDialog: SettingsDialog,
private menu: MenuService,
) {
}

ngOnInit(): void {
this.menu.onMessage().pipe(
filter(event => event === MenuEvent.OPEN_SETTINGS),
).subscribe(() => this.openSettingsDialog());
}

toggleServicePanel(outletId: string): void {
this.store.dispatch(new ToggleSidenavPanelAction({ outletId }));
}

openSettingsDialog(): void {
this.settingsDialog.open();
}
}
39 changes: 39 additions & 0 deletions src/browser/app/app-settings/app-settings.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { NgModule } from '@angular/core';
import { SETTINGS_REGISTRATION, SettingsContext } from '../../settings';
import { UiModule } from '../../ui/ui.module';
import { vcsSettingsContext } from '../../vcs/vcs-settings';
import { GeneralSettingsComponent } from './general-settings/general-settings.component';


const generalSettingsContext: SettingsContext<GeneralSettingsComponent> = {
id: 'settings.general',
tabName: 'General',
component: GeneralSettingsComponent,
};


@NgModule({
imports: [
UiModule,
],
declarations: [
GeneralSettingsComponent,
],
entryComponents: [
GeneralSettingsComponent,
],
providers: [
{
provide: SETTINGS_REGISTRATION,
useValue: [
generalSettingsContext,
vcsSettingsContext,
] as SettingsContext<any>[],
},
],
exports: [
GeneralSettingsComponent,
],
})
export class AppSettingsModule {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<div gdArea gdColumns="2fr 5fr" gdRows="1fr" gdGap="5px" class="GeneralSettings">
<label gdColumn="1" gdRow="1" for="general-setting-theme" gdFormFieldLabel>Theme:</label>
<div gdColumn="2" gdRow="1" fxLayout fxLayoutAlign="start center"
class="GeneralSettings__formFieldSizedBox">
<gd-button-toggle-group gdColumn="2" gdRow="1" id="general-setting-theme" [formControl]="themeFormControl">
<gd-button-toggle *ngFor="let option of themeOptions" [value]="option.value">
{{ option.name }}
</gd-button-toggle>
</gd-button-toggle-group>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@import "../../../ui/form-field/form-field-sizes";

.GeneralSettings {
&__formFieldSizedBox {
height: $form-control-size;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { Subject } from 'rxjs';
import { fastTestSetup } from '../../../../../test/helpers';
import { SharedModule, ThemeService } from '../../../shared';
import { ButtonToggleComponent } from '../../../ui/button-toggle';
import { Themes } from '../../../ui/style';
import { UiModule } from '../../../ui/ui.module';
import { GeneralSettingsComponent } from './general-settings.component';


describe('browser.app.appSettings.GeneralSettingsComponent', () => {
let fixture: ComponentFixture<GeneralSettingsComponent>;
let component: GeneralSettingsComponent;

let theme: ThemeService;

const getThemeButtonToggles = (): ButtonToggleComponent[] =>
fixture.debugElement
.queryAll(By.directive(ButtonToggleComponent))
.map(toggle => toggle.componentInstance as ButtonToggleComponent);

fastTestSetup();

beforeAll(async () => {
await TestBed
.configureTestingModule({
imports: [
SharedModule,
UiModule,
],
declarations: [
GeneralSettingsComponent,
],
})
.compileComponents();
});

beforeEach(() => {
theme = TestBed.get(ThemeService);

fixture = TestBed.createComponent(GeneralSettingsComponent);
component = fixture.componentInstance;
});

describe('theme', () => {
it('should set theme form control with current theme.', () => {
spyOnProperty(theme, 'currentTheme', 'get').and.returnValue(Themes.BASIC_DARK_THEME);
fixture.detectChanges();

expect(component.themeFormControl.value).toEqual(Themes.BASIC_DARK_THEME);
});

it('should render theme options as button toggles.', () => {
fixture.detectChanges();

const allThemes = Object.values(Themes);

getThemeButtonToggles().forEach((toggle) => {
expect(allThemes.includes(toggle.value)).toBe(true);
});
});

it('should call set theme update when form control value changes.', () => {
const setTheme = new Subject<any>();
const callback = jasmine.createSpy('callback');
const subscription = setTheme.asObservable().subscribe(callback);

(theme as any).setTheme = setTheme;

fixture.detectChanges();

const buttonToggle = getThemeButtonToggles().find(toggle => toggle.value === Themes.BASIC_LIGHT_THEME);
buttonToggle._onButtonClick();

expect(callback).toHaveBeenCalledWith(Themes.BASIC_LIGHT_THEME);
subscription.unsubscribe();
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { Subscription } from 'rxjs';
import { ThemeService } from '../../../shared';
import { Themes } from '../../../ui/style';


@Component({
selector: 'gd-general-settings',
templateUrl: './general-settings.component.html',
styleUrls: ['./general-settings.component.scss'],
})
export class GeneralSettingsComponent implements OnInit, OnDestroy {
readonly themeFormControl = new FormControl();
readonly themeOptions = [
{ name: 'Light Theme', value: Themes.BASIC_LIGHT_THEME },
{ name: 'Dark Theme', value: Themes.BASIC_DARK_THEME },
];

private themeUpdateSubscription = Subscription.EMPTY;

constructor(private theme: ThemeService) {
}

ngOnInit(): void {
this.themeFormControl.setValue(this.theme.currentTheme);
this.themeUpdateSubscription = this.themeFormControl.valueChanges.subscribe(this.theme.setTheme);
}

ngOnDestroy(): void {
this.themeUpdateSubscription.unsubscribe();
}
}
2 changes: 2 additions & 0 deletions src/browser/app/app-settings/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './app-settings.module';
export * from './general-settings/general-settings.component';
8 changes: 4 additions & 4 deletions src/browser/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { filter, map } from 'rxjs/operators';
import { NoteFinderComponent } from '../note/note-collection';
import { NoteCollectionService } from '../note/note-collection/note-collection.service';
import { ChangeViewModeAction, NoteEditorViewModes } from '../note/note-editor';
import { MenuEvent, MenuService, WORKSPACE_DATABASE, WorkspaceDatabase } from '../shared';
import { Themes, ThemeService } from '../ui/style';
import { MenuEvent, MenuService, ThemeService, WORKSPACE_DATABASE, WorkspaceDatabase } from '../shared';
import { defaultTheme, Themes } from '../ui/style';
import { VcsManagerComponent, VcsService } from '../vcs';
import { AppLayoutSidenavOutlet, ToggleSidenavPanelAction } from './app-layout';
import { AppStateWithFeatures } from './app.state';
Expand Down Expand Up @@ -65,9 +65,9 @@ export class AppComponent implements OnInit {
) {
const _theme = workspaceDB.cachedInfo
? workspaceDB.cachedInfo.theme as Themes
: ThemeService.defaultTheme;
: defaultTheme;

theme.setTheme(_theme);
theme.applyThemeToHtml(_theme);
workspaceDB.update({ theme: _theme });
}

Expand Down
4 changes: 4 additions & 0 deletions src/browser/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { EffectsModule } from '@ngrx/effects';
import { StoreModule } from '@ngrx/store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { NoteModule } from '../note';
import { SettingsModule } from '../settings';
import { UiModule } from '../ui/ui.module';
import { VcsModule } from '../vcs';
import {
Expand All @@ -15,6 +16,7 @@ import {
AppVcsItemFactoriesProvider,
} from './app-configs';
import { AppLayoutModule } from './app-layout';
import { AppSettingsModule } from './app-settings';
import { AppComponent } from './app.component';
import { appReducer } from './app.reducer';

Expand All @@ -28,8 +30,10 @@ import { appReducer } from './app.reducer';
StoreDevtoolsModule.instrument(),
EffectsModule.forRoot([]),
AppLayoutModule,
AppSettingsModule,
NoteModule,
VcsModule,
SettingsModule,
],
providers: [
AppVcsItemFactoriesProvider,
Expand Down
Loading

0 comments on commit 435783b

Please sign in to comment.