Skip to content

Commit

Permalink
Added actions and reducers for repositioning windows.
Browse files Browse the repository at this point in the history
  • Loading branch information
imolorhe committed Jan 21, 2018
1 parent ef14db3 commit 2ed6422
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 36 deletions.
16 changes: 15 additions & 1 deletion src/app/actions/windows-meta/windows-meta.ts
@@ -1,11 +1,25 @@
import { Action } from '@ngrx/store';

export const SET_ACTIVE_WINDOW_ID = 'SET_ACTIVE_WINDOW_ID';
export const SET_WINDOW_IDS = 'SET_WINDOW_IDS';
export const REPOSITION_WINDOW = 'REPOSITION_WINDOW';

export class SetActiveWindowIdAction implements Action {
readonly type = SET_ACTIVE_WINDOW_ID;

constructor(public payload: { windowId: string }) {}
}

export type Action = SetActiveWindowIdAction;
export class SetWindowIdsAction implements Action {
readonly type = SET_WINDOW_IDS;

constructor(public payload: { ids: string[]}) {}
}

export class RepositionWindowAction implements Action {
readonly type = REPOSITION_WINDOW;

constructor(public payload: { currentPosition: number, newPosition: number }) { }
}

export type Action = SetActiveWindowIdAction | SetWindowIdsAction | RepositionWindowAction;
3 changes: 2 additions & 1 deletion src/app/app.module.ts
Expand Up @@ -22,6 +22,7 @@ import { SharedModule } from './shared/shared.module';
import { reducer, metaReducers, reducerToken, reducerProvider } from './reducers';

import { QueryEffects } from './effects/query';
import { WindowsEffects } from './effects/windows';

import { ComponentModule } from './components';
import { DocViewerModule } from './components/doc-viewer/doc-viewer.module';
Expand Down Expand Up @@ -73,7 +74,7 @@ const providers = [
ComponentModule,
DocViewerModule,
StoreModule.forRoot(reducerToken, { metaReducers }),
EffectsModule.forRoot([ QueryEffects ]),
EffectsModule.forRoot([ QueryEffects, WindowsEffects ]),
StoreDevtoolsModule.instrument(),
ToastModule.forRoot(),
TranslateModule.forRoot({
Expand Down
20 changes: 10 additions & 10 deletions src/app/components/window-switcher/window-switcher.component.html
@@ -1,23 +1,23 @@
<div class="header-nav window-switcher__container">
<div
class="nav-link nav-text window-switcher _track_me"
*ngFor="let window of windows"
[class.active]="window.windowId === activeWindowId"
(click)="activeWindowChange.next(window.windowId)"
(dblclick)="editWindowNameInput(window.windowId, wTitle)"
*ngFor="let windowId of windowIds; let index = index;"
[class.active]="windowId === activeWindowId"
(click)="activeWindowChange.next(windowId)"
(dblclick)="editWindowNameInput(windowId, wTitle)"
>
<div
#wTitle class="window-switcher__input"
[attr.contenteditable]="window.windowId === windowNameEditing"
(blur)="saveWindowName(window.windowId, wTitle.innerText)"
(keydown.enter)="saveWindowName(window.windowId, wTitle.innerText)"
>{{ window.layout.title }}</div>
<div class="window-switcher__close" *ngIf="windows.length > 1" (click)="removeWindowChange.next(window.windowId)">&#x00D7;</div>
[attr.contenteditable]="windowId === windowNameEditing"
(blur)="saveWindowName(windowId, wTitle.innerText)"
(keydown.enter)="saveWindowName(windowId, wTitle.innerText)"
>{{ windows[windowId].layout.title }}</div>
<div class="window-switcher__close" *ngIf="windowIds.length > 1" (click)="removeWindowChange.next(windowId)">&#x00D7;</div>
</div>
<div
class="nav-link nav-text window-switcher window-switcher--new-window _track_me"
(click)="newWindowChange.next($event)"
*ngIf="windows.length < maxWindowCount">
*ngIf="windowIds.length < maxWindowCount">
{{ 'ADD_NEW_WINDOW_TEXT' | translate }}
</div>
</div>
Expand Up @@ -15,13 +15,15 @@ import config from '../../config';
})
export class WindowSwitcherComponent implements OnInit {

@Input() windows = [];
@Input() windows = {};
@Input() windowIds = [];
@Input() activeWindowId = '';
@Input() isElectron = false;
@Output() activeWindowChange = new EventEmitter();
@Output() newWindowChange = new EventEmitter();
@Output() removeWindowChange = new EventEmitter();
@Output() windowNameChange = new EventEmitter();
@Output() repositionWindowChange = new EventEmitter();

windowNameEditing = null;
maxWindowCount = config.max_windows;
Expand All @@ -42,4 +44,8 @@ export class WindowSwitcherComponent implements OnInit {
this.windowNameEditing = null;
}

moveWindow(currentPosition, newPosition) {
this.repositionWindowChange.next(({ currentPosition, newPosition }));
}

}
31 changes: 17 additions & 14 deletions src/app/containers/app/app.component.html
Expand Up @@ -17,25 +17,28 @@
<img src="assets/img/logo.svg" alt="logo" class="header-logo">
</div>
<app-window-switcher
[windows]="windowsArr"
[windows]="windows"
[windowIds] = "windowIds"
[activeWindowId]="activeWindowId"
[isElectron]="isElectron"
(newWindowChange)="newWindow()"
(activeWindowChange)="setActiveWindow($event)"
(removeWindowChange)="removeWindow($event)"
(windowNameChange)="setWindowName($event)"></app-window-switcher>
<div class="header-actions">
<clr-dropdown>
<button class="nav-icon" type="button" clrDropdownTrigger>
<clr-icon shape="cog"></clr-icon>
<clr-icon shape="caret down"></clr-icon>
</button>
<clr-dropdown-menu clrPosition="bottom-right" *clrIfOpen>
<button type="button" clrDropdownItem (click)="showSettingsDialog()">{{ 'SETTINGS_TEXT' | translate }}</button>
<button type="button" (click)="externalLink($event, 'https://github.com/imolorhe/altair')" clrDropdownItem>{{ 'VIEW_ON_GITHUB_TEXT' | translate }}</button>
</clr-dropdown-menu>
</clr-dropdown>
</div>
(windowNameChange)="setWindowName($event)"
(repositionWindowChange)="repositionWindow($event)"
></app-window-switcher>
<div class="header-actions">
<clr-dropdown>
<button class="nav-icon" type="button" clrDropdownTrigger>
<clr-icon shape="cog"></clr-icon>
<clr-icon shape="caret down"></clr-icon>
</button>
<clr-dropdown-menu clrPosition="bottom-right" *clrIfOpen>
<button type="button" clrDropdownItem (click)="showSettingsDialog()">{{ 'SETTINGS_TEXT' | translate }}</button>
<button type="button" (click)="externalLink($event, 'https://github.com/imolorhe/altair')" clrDropdownItem>{{ 'VIEW_ON_GITHUB_TEXT' | translate }}</button>
</clr-dropdown-menu>
</clr-dropdown>
</div>
</header>
<ng-container *ngFor="let windowId of windowIds">
<app-window [windowId]="windowId" [class.hide]="windowId !== activeWindowId"></app-window>
Expand Down
25 changes: 19 additions & 6 deletions src/app/containers/app/app.component.ts
Expand Up @@ -36,14 +36,14 @@ export class AppComponent {
settings$: Observable<fromSettings.State>;

windowIds = [];
windowsArr = [];
windows = {};
activeWindowId = '';
isElectron = isElectron;
isReady = false; // determines if the app is fully loaded. Assets, translations, etc.

constructor(
private windowService: WindowService,
private store: Store<any>,
private store: Store<fromRoot.State>,
private translate: TranslateService,
private electron: ElectronService
) {
Expand Down Expand Up @@ -83,18 +83,26 @@ export class AppComponent {
});
this.store
.subscribe(data => {
this.windows = data.windows;
this.windowIds = Object.keys(data.windows);
console.log(data.windows, this.windowIds);
this.windowsArr = this.windowIds.map(id => data.windows[id]);

// Set the window IDs in the meta state if it does not already exist
if (data.windowsMeta.windowIds) {
this.windowIds = data.windowsMeta.windowIds;
} else {
this.store.dispatch(new windowsMetaActions.SetWindowIdsAction( { ids: this.windowIds }));
}

this.activeWindowId = data.windowsMeta.activeWindowId;
console.log(data.windows, this.windowIds);

// If the active window has not been set, default it
if (this.windowsArr.length && (!this.activeWindowId || !data.windows[this.activeWindowId])) {
if (this.windowIds.length && (!this.activeWindowId || !data.windows[this.activeWindowId])) {
this.store.dispatch(new windowsMetaActions.SetActiveWindowIdAction({ windowId: this.windowIds[0] }));
}
});

if (!this.windowsArr.length) {
if (!this.windowIds.length) {
this.windowService.newWindow();
}
}
Expand Down Expand Up @@ -151,6 +159,11 @@ export class AppComponent {
this.store.dispatch(new layoutActions.SetWindowNameAction(windowId, windowName));
}

repositionWindow(data) {
const { currentPosition, newPosition } = data;
this.store.dispatch(new windowsMetaActions.RepositionWindowAction({ currentPosition, newPosition }));
}

showSettingsDialog() {
this.store.dispatch(new settingsActions.ShowSettingsAction());
}
Expand Down
2 changes: 1 addition & 1 deletion src/app/containers/window/window.component.ts
Expand Up @@ -43,7 +43,7 @@ export class WindowComponent implements OnInit {
responseTime$: Observable<number>;
responseStatusText$: Observable<string>;
isSubscribed$: Observable<boolean>;
subscriptionResponses$: Observable<Array<string>>;
subscriptionResponses$: Observable<string[]>;

@Input() windowId: string;

Expand Down
28 changes: 28 additions & 0 deletions src/app/effects/windows.ts
@@ -0,0 +1,28 @@
import { Injectable } from '@angular/core';
import { Store, Action } from '@ngrx/store';
import { Effect, Actions, toPayload } from '@ngrx/effects';
import { Observable } from 'rxjs/Observable';

import * as fromRoot from '../reducers';

import * as windowActions from '../actions/windows/windows';
import * as windowsMetaActions from '../actions/windows-meta/windows-meta';

@Injectable()
export class WindowsEffects {

@Effect() // remove, add, reposition
setWindowIDs$: Observable<Action> = this.actions$
.ofType(windowActions.ADD_WINDOW, windowActions.REMOVE_WINDOW)
.withLatestFrom(this.store, (action: windowActions.Action, state) => {
return { windows: state.windows, action };
}).switchMap(data => {
const windowIds = Object.keys(data.windows);
return Observable.of(new windowsMetaActions.SetWindowIdsAction({ ids: windowIds }));
});

constructor(
private actions$: Actions,
private store: Store<fromRoot.State>
) {}
}
19 changes: 17 additions & 2 deletions src/app/reducers/windows-meta/windows-meta.ts
Expand Up @@ -4,16 +4,31 @@ import * as windowsMeta from '../../actions/windows-meta/windows-meta';

export interface State {
activeWindowId: string;
windowIds: Array<string>;
}

const initialState: State = {
activeWindowId: ''
activeWindowId: '',
windowIds: []
};

export function windowsMetaReducer(state = initialState, action: windowsMeta.Action): State {
switch (action.type) {
case windowsMeta.SET_ACTIVE_WINDOW_ID:
return Object.assign({}, state, { activeWindowId: action.payload.windowId });
return { ...state, activeWindowId: action.payload.windowId };
case windowsMeta.SET_WINDOW_IDS:
return { ...state, windowIds: action.payload.ids };
case windowsMeta.REPOSITION_WINDOW:
const curPos = action.payload.currentPosition;
const newPos = action.payload.newPosition;

if (curPos > -1 && curPos < state.windowIds.length && newPos > -1 && newPos < state.windowIds.length) {
const arr = [ ...state.windowIds ];
arr.splice(newPos, 0, arr.splice(curPos, 1)[0]);

return { ...state, windowIds: [ ...arr ] };
}
return state;
default:
return state;
}
Expand Down

0 comments on commit 2ed6422

Please sign in to comment.