refactor state handling to make application available independent of the state

This commit is contained in:
undergroundwires
2021-02-07 12:24:15 +01:00
parent 67b2d1c11c
commit df273f7f63
28 changed files with 275 additions and 198 deletions

View File

@@ -80,29 +80,26 @@
</template>
<script lang="ts">
import { Component, Prop } from 'vue-property-decorator';
import { StatefulVue } from '@/presentation/StatefulVue';
import { Component, Prop, Vue } from 'vue-property-decorator';
import Code from './Code.vue';
import { IApplication } from '@/domain/IApplication';
import { OperatingSystem } from '@/domain/OperatingSystem';
import { ApplicationFactory } from '@/application/ApplicationFactory';
@Component({
components: {
Code,
},
})
export default class MacOsInstructions extends StatefulVue {
export default class MacOsInstructions extends Vue {
@Prop() public fileName: string;
public appName = '';
public macOsDownloadUrl = '';
protected initialize(app: IApplication): void {
public async created() {
const app = await ApplicationFactory.Current.getAppAsync();
this.appName = app.info.name;
this.macOsDownloadUrl = app.info.getDownloadUrl(OperatingSystem.macOS);
}
protected handleCollectionState(): void {
return;
}
}
</script>

View File

@@ -65,9 +65,6 @@ export default class TheCodeButtons extends StatefulVue {
}
}
protected initialize(): void {
return;
}
protected handleCollectionState(newState: ICategoryCollectionState): void {
this.isMacOsCollection = newState.collection.os === OperatingSystem.macOS;
this.fileName = buildFileName(newState.collection.scripting);

View File

@@ -22,7 +22,6 @@ import { StatefulVue } from '@/presentation/StatefulVue';
import { ICategory } from '@/domain/ICategory';
import { hasDirective } from './NonCollapsingDirective';
import { ICategoryCollectionState } from '@/application/Context/State/ICategoryCollectionState';
import { IApplication } from '@/domain/IApplication';
@Component({
components: {
@@ -45,9 +44,6 @@ export default class CardList extends StatefulVue {
this.activeCategoryId = isExpanded ? categoryId : undefined;
}
protected initialize(app: IApplication): void {
return;
}
protected handleCollectionState(newState: ICategoryCollectionState, oldState: ICategoryCollectionState): void {
this.setCategories(newState.collection.actions);
this.activeCategoryId = undefined;

View File

@@ -78,9 +78,7 @@ export default class CardListItem extends StatefulVue {
this.cardTitle = category ? category.name : undefined;
await this.updateSelectionIndicatorsAsync(value);
}
protected initialize(): void {
return;
}
protected handleCollectionState(): void {
return;
}

View File

@@ -73,9 +73,6 @@ export default class ScriptsTree extends StatefulVue {
(category: ICategory) => node.id === getCategoryNodeId(category));
}
protected initialize(): void {
return;
}
protected async handleCollectionState(newState: ICategoryCollectionState) {
this.setCurrentFilter(newState.filter.currentFilter);
if (!this.categoryId) {

View File

@@ -37,9 +37,6 @@ export default class RevertToggle extends StatefulVue {
this.handler.selectWithRevertState(this.isReverted, context.state.selection);
}
protected initialize(): void {
return;
}
protected handleCollectionState(newState: ICategoryCollectionState): void {
this.updateStatus(newState.selection.selectedScripts);
this.events.unsubscribeAll();

View File

@@ -56,7 +56,6 @@ import { IScript } from '@/domain/IScript';
import { SelectedScript } from '@/application/Context/State/Selection/SelectedScript';
import { RecommendationLevel } from '@/domain/RecommendationLevel';
import { ICategoryCollectionState } from '@/application/Context/State/ICategoryCollectionState';
import { IApplication } from '@/domain/IApplication';
enum SelectionState {
Standard,
@@ -82,9 +81,6 @@ export default class TheSelector extends StatefulVue {
selectType(context.state, type);
}
protected initialize(app: IApplication): void {
return;
}
protected handleCollectionState(newState: ICategoryCollectionState, oldState: ICategoryCollectionState): void {
this.updateSelections(newState);
newState.selection.changed.on(() => this.updateSelections(newState));

View File

@@ -16,23 +16,24 @@ import { Component } from 'vue-property-decorator';
import { OperatingSystem } from '@/domain/OperatingSystem';
import { StatefulVue } from '@/presentation/StatefulVue';
import { ICategoryCollectionState } from '@/application/Context/State/ICategoryCollectionState';
import { IApplication } from '@/domain/IApplication';
import { ApplicationFactory } from '@/application/ApplicationFactory';
@Component
export default class TheOsChanger extends StatefulVue {
public allOses: Array<{ name: string, os: OperatingSystem }> = [];
public currentOs: OperatingSystem = undefined;
public currentOs: OperatingSystem = OperatingSystem.Unknown;
public async created() {
const app = await ApplicationFactory.Current.getAppAsync();
this.allOses = app.getSupportedOsList()
.map((os) => ({ os, name: renderOsName(os) }));
}
public async changeOsAsync(newOs: OperatingSystem) {
const context = await this.getCurrentContextAsync();
context.changeContext(newOs);
}
protected initialize(app: IApplication): void {
this.allOses = app.getSupportedOsList()
.map((os) => ({ os, name: renderOsName(os) }));
}
protected handleCollectionState(newState: ICategoryCollectionState, oldState: ICategoryCollectionState): void {
protected handleCollectionState(newState: ICategoryCollectionState): void {
this.currentOs = newState.os;
this.$forceUpdate(); // v-bind:class is not updated otherwise
}

View File

@@ -49,7 +49,7 @@ import { StatefulVue } from '@/presentation/StatefulVue';
import { Grouping } from './Grouping/Grouping';
import { IFilterResult } from '@/application/Context/State/Filter/IFilterResult';
import { ICategoryCollectionState } from '@/application/Context/State/ICategoryCollectionState';
import { IApplication } from '@/domain/IApplication';
import { ApplicationFactory } from '@/application/ApplicationFactory';
/** Shows content of single category or many categories */
@Component({
@@ -78,6 +78,10 @@ export default class TheScripts extends StatefulVue {
public isSearching = false;
public searchHasMatches = false;
public async created() {
const app = await ApplicationFactory.Current.getAppAsync();
this.repositoryUrl = app.info.repositoryWebUrl;
}
public async clearSearchQueryAsync() {
const context = await this.getCurrentContextAsync();
const filter = context.state.filter;
@@ -87,9 +91,6 @@ export default class TheScripts extends StatefulVue {
this.currentGrouping = group;
}
protected initialize(app: IApplication): void {
this.repositoryUrl = app.info.repositoryWebUrl;
}
protected handleCollectionState(newState: ICategoryCollectionState): void {
this.events.unsubscribeAll();
this.subscribeState(newState);

View File

@@ -1,17 +1,15 @@
import { Component, Vue } from 'vue-property-decorator';
import { AsyncLazy } from '@/infrastructure/Threading/AsyncLazy';
import { IApplicationContext } from '@/application/Context/IApplicationContext';
import { buildContext } from '@/application/Context/ApplicationContextProvider';
import { buildContextAsync } from '@/application/Context/ApplicationContextFactory';
import { IApplicationContextChangedEvent } from '@/application/Context/IApplicationContext';
import { IApplication } from '@/domain/IApplication';
import { ICategoryCollectionState } from '@/application/Context/State/ICategoryCollectionState';
import { EventSubscriptionCollection } from '../infrastructure/Events/EventSubscriptionCollection';
// @ts-ignore because https://github.com/vuejs/vue-class-component/issues/91
@Component
export abstract class StatefulVue extends Vue {
public static instance = new AsyncLazy<IApplicationContext>(
() => Promise.resolve(buildContext()));
private static readonly instance = new AsyncLazy<IApplicationContext>(() => buildContextAsync());
protected readonly events = new EventSubscriptionCollection();
@@ -20,7 +18,6 @@ export abstract class StatefulVue extends Vue {
public async mounted() {
const context = await this.getCurrentContextAsync();
this.ownEvents.register(context.contextChanged.on((event) => this.handleStateChangedEvent(event)));
this.initialize(context.app);
this.handleCollectionState(context.state, undefined);
}
public destroyed() {
@@ -28,7 +25,6 @@ export abstract class StatefulVue extends Vue {
this.events.unsubscribeAll();
}
protected abstract initialize(app: IApplication): void;
protected abstract handleCollectionState(
newState: ICategoryCollectionState, oldState: ICategoryCollectionState | undefined): void;
protected getCurrentContextAsync(): Promise<IApplicationContext> {

View File

@@ -26,9 +26,6 @@ export default class TheCodeArea extends StatefulVue {
this.destroyEditor();
}
protected initialize(): void {
return;
}
protected handleCollectionState(newState: ICategoryCollectionState): void {
this.destroyEditor();
this.editor = initializeEditor(this.theme, this.editorId, newState.collection.scripting.language);

View File

@@ -9,15 +9,13 @@
</template>
<script lang="ts">
import { Component, Prop, Watch } from 'vue-property-decorator';
import { StatefulVue } from '@/presentation/StatefulVue';
import { Component, Prop, Watch, Vue } from 'vue-property-decorator';
import { Environment } from '@/application/Environment/Environment';
import { OperatingSystem } from '@/domain/OperatingSystem';
import { ICategoryCollectionState } from '@/application/Context/State/ICategoryCollectionState';
import { IApplication } from '@/domain/IApplication';
import { ApplicationFactory } from '@/application/ApplicationFactory';
@Component
export default class DownloadUrlListItem extends StatefulVue {
export default class DownloadUrlListItem extends Vue {
@Prop() public operatingSystem!: OperatingSystem;
public downloadUrl: string = '';
@@ -38,16 +36,9 @@ export default class DownloadUrlListItem extends StatefulVue {
this.hasCurrentOsDesktopVersion = hasDesktopVersion(currentOs);
}
protected initialize(app: IApplication): void {
return;
}
protected handleCollectionState(newState: ICategoryCollectionState, oldState: ICategoryCollectionState): void {
return;
}
private async getDownloadUrlAsync(os: OperatingSystem): Promise<string> {
const context = await this.getCurrentContextAsync();
return context.app.info.getDownloadUrl(os);
const context = await ApplicationFactory.Current.getAppAsync();
return context.info.getDownloadUrl(os);
}
}

View File

@@ -31,25 +31,27 @@
</template>
<script lang="ts">
import { Component } from 'vue-property-decorator';
import { StatefulVue } from '@/presentation/StatefulVue';
import { Component, Vue } from 'vue-property-decorator';
import { Environment } from '@/application/Environment/Environment';
import { ApplicationFactory } from '@/application/ApplicationFactory';
import { IApplication } from '@/domain/IApplication';
@Component
export default class PrivacyPolicy extends StatefulVue {
export default class PrivacyPolicy extends Vue {
public repositoryUrl: string = '';
public feedbackUrl: string = '';
public isDesktop = Environment.CurrentEnvironment.isDesktop;
protected initialize(app: IApplication): void {
public async created() {
const app = await ApplicationFactory.Current.getAppAsync();
this.initialize(app);
}
private initialize(app: IApplication) {
const info = app.info;
this.repositoryUrl = info.repositoryWebUrl;
this.feedbackUrl = info.feedbackUrl;
}
protected handleCollectionState(): void {
return;
}
}
</script>

View File

@@ -47,22 +47,21 @@
</template>
<script lang="ts">
import { Component } from 'vue-property-decorator';
import { StatefulVue } from '@/presentation/StatefulVue';
import { Component, Vue } from 'vue-property-decorator';
import { Environment } from '@/application/Environment/Environment';
import PrivacyPolicy from './PrivacyPolicy.vue';
import DownloadUrlList from './DownloadUrlList.vue';
import { ICategoryCollectionState } from '@/application/Context/State/ICategoryCollectionState';
import { IApplication } from '@/domain/IApplication';
import { ApplicationFactory } from '@/application/ApplicationFactory';
@Component({
components: {
PrivacyPolicy, DownloadUrlList,
},
})
export default class TheFooter extends StatefulVue {
export default class TheFooter extends Vue {
public readonly modalName = 'privacy-policy';
public readonly isDesktop: boolean;
public readonly isDesktop = Environment.CurrentEnvironment.isDesktop;
public version: string = '';
public repositoryUrl: string = '';
@@ -70,12 +69,12 @@ export default class TheFooter extends StatefulVue {
public feedbackUrl: string = '';
public homepageUrl: string = '';
constructor() {
super();
this.isDesktop = Environment.CurrentEnvironment.isDesktop;
public async created() {
const app = await ApplicationFactory.Current.getAppAsync();
this.initialize(app);
}
protected initialize(app: IApplication): void {
private initialize(app: IApplication) {
const info = app.info;
this.version = info.version;
this.homepageUrl = info.homepage;
@@ -83,10 +82,6 @@ export default class TheFooter extends StatefulVue {
this.releaseUrl = info.releaseUrl;
this.feedbackUrl = info.feedbackUrl;
}
protected handleCollectionState(newState: ICategoryCollectionState, oldState: ICategoryCollectionState): void {
return;
}
}
</script>

View File

@@ -1,27 +1,23 @@
<template>
<div id="container">
<h1 class="child title" >{{ title }}</h1>
<h2 class="child subtitle">Enforce privacy & security on Windows and macOS</h2>
<h2 class="child subtitle">Enforce privacy &amp; security on Windows and macOS</h2>
</div>
</template>
<script lang="ts">
import { ICategoryCollectionState } from '@/application/Context/State/ICategoryCollectionState';
import { IApplication } from '@/domain/IApplication';
import { Component } from 'vue-property-decorator';
import { StatefulVue } from './StatefulVue';
import { ApplicationFactory } from '@/application/ApplicationFactory';
import { Component, Vue } from 'vue-property-decorator';
@Component
export default class TheHeader extends StatefulVue {
export default class TheHeader extends Vue {
public title = '';
public subtitle = '';
protected initialize(app: IApplication): void {
public async created() {
const app = await ApplicationFactory.Current.getAppAsync();
this.title = app.info.name;
}
protected handleCollectionState(newState: ICategoryCollectionState, oldState: ICategoryCollectionState): void {
return;
}
}
</script>

View File

@@ -36,9 +36,6 @@ export default class TheSearchBar extends StatefulVue {
}
}
protected initialize(): void {
return;
}
protected handleCollectionState(newState: ICategoryCollectionState, oldState: ICategoryCollectionState | undefined) {
const totalScripts = newState.collection.totalScripts;
this.searchPlaceHolder = `Search in ${totalScripts} scripts`;