Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Godind/issue136 #213

Merged
merged 2 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/app/app-settings.interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface IConfig {

export interface IAppConfig {
configVersion: number;
autoNightMode: boolean;
dataSets: IDataSet[];
unitDefaults: IUnitDefaults;
notificationConfig: INotificationConfig;
Expand Down
34 changes: 31 additions & 3 deletions src/app/app-settings.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { DefaultNotificationConfig } from './config.blank.notification.const';
import { DemoAppConfig, DemoConnectionConfig, DemoWidgetConfig, DemoLayoutConfig, DemoThemeConfig, DemoZonesConfig } from './config.demo.const';

import { StorageService } from './storage.service';
import { IAuthorizationToken } from './auththetication.service';

const defaultTheme = 'modern-dark';
const configVersion = 9; // used to invalidate old configs. connectionConfig and appConfig use this same version.
Expand All @@ -29,6 +28,7 @@ export class AppSettingsService {
private unitDefaults: BehaviorSubject<IUnitDefaults> = new BehaviorSubject<IUnitDefaults>({});
private themeName: BehaviorSubject<string> = new BehaviorSubject<string>(defaultTheme);
private kipKNotificationConfig: BehaviorSubject<INotificationConfig> = new BehaviorSubject<INotificationConfig>(DefaultNotificationConfig);
private autoNightMode: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);

private useDeviceToken: boolean = false;
private loginName: string;
Expand All @@ -49,7 +49,7 @@ export class AppSettingsService {
constructor(
@Inject(APP_BASE_HREF) private baseHref: string,
private router: Router,
private storage: StorageService,
private storage: StorageService
)
{
console.log("[AppSettings Service] Service startup...");
Expand Down Expand Up @@ -143,6 +143,7 @@ export class AppSettingsService {
private upgradeAppConfig(appConfig: any): IAppConfig {
let upgradedConfig: IAppConfig = {
configVersion: 9,
autoNightMode: this.autoNightMode.getValue(),
dataSets: cloneDeep(appConfig.dataSets),
notificationConfig: cloneDeep(appConfig.notificationConfig),
unitDefaults: cloneDeep(appConfig.unitDefaults)
Expand Down Expand Up @@ -215,7 +216,12 @@ export class AppSettingsService {
this.zones.next(this.activeConfig.zones.zones);
this.splitSets = this.activeConfig.layout.splitSets;
this.rootSplits = this.activeConfig.layout.rootSplits;
}

if (this.activeConfig.app.autoNightMode === undefined) {
this.setAutoNightMode(false);
} else
this.autoNightMode.next(this.activeConfig.app.autoNightMode);
}

//UnitDefaults
public getDefaultUnitsAsO() {
Expand Down Expand Up @@ -312,10 +318,31 @@ export class AppSettingsService {
return this.themeName.getValue();;
}

// Auto night mode
public getAutoNightModeAsO() {
return this.autoNightMode.asObservable();
}

public setAutoNightMode(enabled: boolean) {
this.autoNightMode.next(enabled);
const appConf = this.buildAppStorageObject();

if (this.useSharedConfig) {
this.storage.patchConfig('IAppConfig', appConf);
} else {
this.saveAppConfigToLocalStorage();
}
}

public getAutoNightMode(): boolean {
return this.autoNightMode.getValue();
}

// Widgets
public getWidgets() {
return this.widgets;
}

public saveWidgets(widgets: Array<IWidget>) {
this.widgets = widgets;
if (this.useSharedConfig) {
Expand Down Expand Up @@ -473,6 +500,7 @@ export class AppSettingsService {

let storageObject: IAppConfig = {
configVersion: configVersion,
autoNightMode: this.autoNightMode.getValue(),
dataSets: this.dataSets,
unitDefaults: this.unitDefaults.getValue(),
notificationConfig: this.kipKNotificationConfig.getValue(),
Expand Down
6 changes: 5 additions & 1 deletion src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { AppSettingsService } from './app-settings.service';
import { DataSetService } from './data-set.service';
import { NotificationsService } from './notifications.service';
import { SignalKDeltaService, IStreamStatus } from './signalk-delta.service';
import { AppService } from './app.service';

declare var NoSleep: any; //3rd party

Expand Down Expand Up @@ -51,6 +52,7 @@ export class AppComponent implements OnInit, OnDestroy {
private notificationsService: NotificationsService, // needs AppSettingsService SignalKConnectionService
public auththeticationService: AuththeticationService,
private deltaService: SignalKDeltaService,
private appService: AppService,
// below services are needed: first service instanciation after Init Service
private signalKDeltaService: SignalKDeltaService, // needs SignalKService & NotificationsService & SignalKConnectionService
) { }
Expand All @@ -72,7 +74,8 @@ export class AppComponent implements OnInit, OnDestroy {
this.overlayContainer.getContainerElement().classList.remove(this.activeTheme);
}

if (!this.isNightMode) {
if (newTheme != 'nightMode') {
this.isNightMode = false;
if (newTheme !== this.themeName) {
this.overlayContainer.getContainerElement().classList.add(newTheme);
this.themeName = newTheme;
Expand All @@ -81,6 +84,7 @@ export class AppComponent implements OnInit, OnDestroy {
}
} else {
this.overlayContainer.getContainerElement().classList.add(newTheme);
this.isNightMode = true;
}
this.activeTheme = newTheme;
}
Expand Down
4 changes: 2 additions & 2 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ import { WidgetGaugeNgRadialComponent } from './widgets/widget-gauge-ng-radial/w
import { AlarmMenuComponent } from './alarm-menu/alarm-menu.component';
import { WidgetAutopilotComponent } from './widgets/widget-autopilot/widget-autopilot.component';
import { SvgAutopilotComponent } from './widgets/svg-autopilot/svg-autopilot.component';
import { SettingsNotificationsComponent } from './settings/notifications/notifications.component';
import { SettingsGeneralComponent } from './settings/general/general.component';
import { SvgSimpleLinearGaugeComponent } from './widgets/svg-simple-linear-gauge/svg-simple-linear-gauge.component';
import { WidgetSimpleLinearComponent } from './widgets/widget-simple-linear/widget-simple-linear.component';
import { DataBrowserComponent } from './data-browser/data-browser.component';
Expand Down Expand Up @@ -175,7 +175,7 @@ const appNetworkInitializerFn = (appNetInitSvc: AppNetworkInitService) => {
ModalPathSelectorComponent,
ModalUserCredentialComponent,
AlarmMenuComponent,
SettingsNotificationsComponent,
SettingsGeneralComponent,
DataBrowserComponent,
DataBrowserRowComponent
],
Expand Down
16 changes: 16 additions & 0 deletions src/app/app.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';

import { AppService } from './app.service';

describe('AppService', () => {
let service: AppService;

beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(AppService);
});

it('should be created', () => {
expect(service).toBeTruthy();
});
});
79 changes: 79 additions & 0 deletions src/app/app.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { IStreamStatus, SignalKDeltaService } from './signalk-delta.service';
import { NotificationsService } from './notifications.service';
import { IConnectionConfig } from './app-settings.interfaces';
import { AppSettingsService } from './app-settings.service';
import { Injectable } from '@angular/core';
import { SignalKService } from './signalk.service';
import { Observable } from 'rxjs';

const sunPath: string = 'self.environment.sun';

@Injectable({
providedIn: 'root'
})
export class AppService {
public autoNightMode: boolean; // from Config value
private sunValue: string = 'day';
private dayTheme: string;

constructor(
private settings: AppSettingsService,
private delta: SignalKDeltaService,
private sk: SignalKService,
private notification: NotificationsService
) {
this.autoNightMode = this.settings.getAutoNightMode();
this.autoNightModeObserver();
}

private autoNightModeObserver(): void {
let deltaStatus = this.delta.getDataStreamStatusAsO(); // wait for delta service to start
deltaStatus.subscribe(stat => {
stat as IStreamStatus;
if(stat.operation == 2) {

setTimeout(() => { // Wait for path data to come in on startup
const autoNightMode: Observable<boolean> = this.settings.getAutoNightModeAsO();
autoNightMode.subscribe(mode => {
this.autoNightMode = mode;
if (mode) {
if (this.sk.getPathObject(sunPath) !== null) {

// capture none nightMode theme name changes
this.settings.getThemeNameAsO().subscribe(theme => {
if (theme != 'nightMode')
this.dayTheme = theme;
});

const connConf: IConnectionConfig = this.settings.getConnectionConfig(); // get app UUUID

this.sk.subscribePath(connConf.kipUUID, sunPath, 'default').subscribe(sun => {
if (sun.value == 'night' && this.sunValue != sun.value) {
this.sunValue = sun.value;
this.settings.setThemName('nightMode');
} else if (sun.value == 'day' && this.sunValue != sun.value) {
this.sunValue = sun.value;
this.settings.setThemName(this.dayTheme);
}
});
}
}
});
}, 0);
}
});
}

public validateAutoNighModeSupported(): boolean {
if (this.sk.getPathObject(sunPath) == null) {
this.notification.sendSnackbarNotification("Dependency Error: self.environment.sun path was not found. To enable Automatic Night Mode, verify that the following Signal K requirements are meet: 1) The Derived Data plugin is installed and enabled. 2) The plugin's Sun:Sets environment.sun parameter is checked.", 0);
return false;
}
return true;
}

public set autoNightModeConfig(isEnabled : boolean) {
this.settings.setAutoNightMode(isEnabled);
}

}
1 change: 1 addition & 0 deletions src/app/config.blank.const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { DefaultUnitsConfig } from "./config.blank.units.const";

export const DefaultAppConfig: IAppConfig = {
"configVersion": 9,
"autoNightMode": false,
"dataSets": [],
"unitDefaults": DefaultUnitsConfig,
"notificationConfig": DefaultNotificationConfig,
Expand Down
1 change: 1 addition & 0 deletions src/app/config.demo.const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { IConfig, IAppConfig, IConnectionConfig, IThemeConfig, ILayoutConfig, IW
// Demo Mode config settings file
export const DemoAppConfig: IAppConfig = {
"configVersion": 9,
"autoNightMode": false,
"dataSets": [
{
"uuid": "afbe4e41-26f5-404f-a55d-9f7b9b76fbd1",
Expand Down
2 changes: 1 addition & 1 deletion src/app/settings/config/config.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ <h3>Operations</h3>
<h3>Local Configration Editor</h3>
<i>Config is in raw json and no validation on save. Make sure you double
check your changes, else you lose your configuration. A good choice is
to back up first using the Save feature above first!</i>
to back up first using the Save feature above!</i>
</div>
<div style="margin-left: 10px; margin-right: 10px; width: 100%;">
<form (ngSubmit)="rawConfigSave('IConnectionConfig')">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<div class="mat-typography">
<form name="notificationSetting">
<h1>Server Notifications</h1>
<form #general="ngForm" name="GeneraSetting">
<h2>Night Vision</h2>
<mat-checkbox [(ngModel)]="autoNightModeConfig" [ngModelOptions]="{standalone: false}" name="autoNightMode" (change)="isAutoNightPathSupported($event)">Automatically change between Day and Night display modes based on sun phases</mat-checkbox>
<br/><br/>
<h2>Notifications</h2>
<p class="mat-card-subtitle">Notifications are a special type of data sent from Signal K and displayed in the
notification menu. They are meant to alert or inform operators. Set server
notification preferences such as types of messages to display and audio prompts.</p>
Expand Down Expand Up @@ -41,7 +44,7 @@ <h1>Server Notifications</h1>
</mat-accordion>
<div class="formActionFooter">
<mat-divider class="formActionDivider"></mat-divider>
<button mat-raised-button color="accent" class="formActionButton" (click)='saveNotificationsSettings()'>Save</button>
<button mat-raised-button color="accent" class="formActionButton" (click)='saveAllSettings()'>Save</button>
</div>
</form>
</div>
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';

import { SettingsNotificationsComponent } from './notifications.component';
import { SettingsGeneralComponent } from './general.component';

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

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ SettingsNotificationsComponent ]
declarations: [ SettingsGeneralComponent ]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(SettingsNotificationsComponent);
fixture = TestBed.createComponent(SettingsGeneralComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
Expand Down
55 changes: 55 additions & 0 deletions src/app/settings/general/general.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Component, OnInit } from '@angular/core';
import { INotificationConfig } from '../../app-settings.interfaces';
import { AppService } from '../../app.service';
import { AppSettingsService } from '../../app-settings.service';
import { NotificationsService } from '../../notifications.service';


@Component({
selector: 'settings-general',
templateUrl: './general.component.html',
styleUrls: ['./general.component.css'],
})
export class SettingsGeneralComponent implements OnInit {

public notificationConfig: INotificationConfig;
public autoNightModeConfig: boolean;

constructor(
private notifications: NotificationsService,
private app: AppService,
private settings: AppSettingsService,
) { }

ngOnInit() {
this.notificationConfig = this.settings.getNotificationConfig();
this.autoNightModeConfig = this.app.autoNightMode;
}

public saveAllSettings():void {
try {
this.saveNotificationsSettings();
this.saveAutoNightMode();
this.notifications.sendSnackbarNotification("General settings saved", 5000, false);
} catch (error) {
this.notifications.sendSnackbarNotification("Error saving settings: " + error, 5000, false);
}

}

public saveNotificationsSettings(): void {
this.settings.setNotificationConfig(this.notificationConfig);
}

public saveAutoNightMode() {
this.app.autoNightModeConfig = this.autoNightModeConfig;
}

public isAutoNightPathSupported(event):void {
if (event.checked) {
if (!this.app.validateAutoNighModeSupported()) {
this.autoNightModeConfig = false;
}
}
}
}
Loading