Skip to content

Commit

Permalink
Add separate classes for different versions of data.
Browse files Browse the repository at this point in the history
  • Loading branch information
gbmhunter committed Jun 18, 2024
1 parent f42b189 commit c2f54bd
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 34 deletions.
125 changes: 103 additions & 22 deletions src/model/ProfileManager/ProfileManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { makeAutoObservable } from 'mobx';

import { DisplaySettingsConfig } from '../Settings/DisplaySettings/DisplaySettings';
import { GeneralSettingsConfig } from '../Settings/GeneralSettings/GeneralSettings';
import { PortConfigurationConfigV2, PortState } from '../Settings/PortConfigurationSettings/PortConfigurationSettings';
import { PortConfigurationConfigV2, PortConfigurationConfigV3, PortState } from '../Settings/PortConfigurationSettings/PortConfigurationSettings';
import { RxSettingsConfig } from '../Settings/RxSettings/RxSettings';
import { TxSettingsConfig } from '../Settings/TxSettings/TxSettings';
import { MacroControllerConfig } from '../Terminals/RightDrawer/Macros/MacroController';
Expand All @@ -18,7 +18,7 @@ export class LastUsedSerialPort {
/**
* Everything in this class must be POD (plain old data) and serializable to JSON.
*/
export class RootConfig {
export class RootConfigV2 {
version = 2;

terminal = {
Expand All @@ -37,14 +37,46 @@ export class RootConfig {
};
}

/**
* Everything in this class must be POD (plain old data) and serializable to JSON.
*/
export class RootConfigV3 {
version = 3;

terminal = {
macroController: new MacroControllerConfig(),
rightDrawer: new RightDrawerConfig(),
};

lastUsedSerialPort: LastUsedSerialPort = new LastUsedSerialPort();

settings = {
portSettings: new PortConfigurationConfigV3(),
txSettings: new TxSettingsConfig(),
rxSettings: new RxSettingsConfig(),
displaySettings: new DisplaySettingsConfig(),
generalSettings: new GeneralSettingsConfig(),
};
}

/**
* This class represents all the data stored in a user profile. It is used to store use-specific
* settings for the application (e.g. all the settings to talk to a particular
* embedded device). The class is serializable to JSON.
*/
export class Profile {
export class ProfileV2 {
name: string = '';
rootConfig: RootConfigV2 = new RootConfigV2();

constructor(name: string) {
this.name = name;
makeAutoObservable(this);
}
}

export class ProfileV3 {
name: string = '';
rootConfig: RootConfig = new RootConfig();
rootConfig: RootConfigV3 = new RootConfigV3();

constructor(name: string) {
this.name = name;
Expand All @@ -56,29 +88,50 @@ export class Profile {
* This class represents all the data that the app needs to store/load from
* local storage (i.e. the root object). It must be serializable to JSON.
*/
export class AppData {
export class AppDataV1 {

version = 1;

profiles: Profile[] = [];
profiles: ProfileV2[] = [];

/**
* Represents the current application configuration. This is saved regularly so that when the app reloads,
* it can restore the last known configuration.
*/
currentAppConfig: RootConfig = new RootConfig();
currentAppConfig: RootConfigV2 = new RootConfigV2();

constructor() {
makeAutoObservable(this);
}
}

export class AppDataV2 {

version = 2;

profiles: ProfileV3[] = [];

/**
* Represents the current application configuration. This is saved regularly so that when the app reloads,
* it can restore the last known configuration.
*/
currentAppConfig: RootConfigV3 = new RootConfigV3();

constructor() {
this.profiles = [];
this.profiles.push(new ProfileV3('Default profile'));
makeAutoObservable(this);
}
}

type AppData = AppDataV2;

const APP_DATA_STORAGE_KEY = 'appData';

export class ProfileManager {
app: App;

appData: AppData = new AppData();
appData: AppDataV2 = new AppDataV2();

_profileChangeCallbacks: (() => void)[] = [];

Expand Down Expand Up @@ -137,24 +190,16 @@ export class ProfileManager {
if (appDataAsJson === null) {
// No config key found in users store, create one!
console.log('App data not found in local storage. Creating default app data.');
appData = new AppData();
appData.profiles = [];
appData.profiles.push(new Profile('Default profile'));
appData = new AppDataV2();
// Save just-created config back to store.
window.localStorage.setItem(APP_DATA_STORAGE_KEY, JSON.stringify(appData));
} else {
// A version of app data was found in local storage. Load it.
let appDataUnknownVersion = JSON.parse(appDataAsJson);
if (appDataUnknownVersion.version == 1) {
// Latest version, don't need to convert anything
// or save it back
appData = appDataUnknownVersion;
} else {
console.error('Unknown app data version found: ', appDataUnknownVersion.version);
appData = new AppData();
appData.profiles = [];
appData.profiles.push(new Profile('Default profile'));
// Save just-created config back to store.
let wasChanged;
({ appData, wasChanged } = this._updateAppData(appDataUnknownVersion));

if (wasChanged) {
window.localStorage.setItem(APP_DATA_STORAGE_KEY, JSON.stringify(appData));
}
}
Expand All @@ -163,6 +208,42 @@ export class ProfileManager {
this.appData = appData;
};

/**
* Use this to update an app data object read from local storage to the latest version.
* @param appData
*/
_updateAppData = (appData: any): { appData: AppData, wasChanged: boolean } => {
let wasChanged = false;
let updatedAppData = JSON.parse(JSON.stringify(appData)) as any;
if (updatedAppData.version === 1) {
console.log('Updating app data from version 1 to version 2...');
// Convert to v2
// Port settings got a new field
let appDataV1 = updatedAppData as AppDataV1;
let appDataV2 = updatedAppData as AppDataV2;
for (let i = 0; i < appDataV1.profiles.length; i++) {
appDataV2.profiles[i].rootConfig.settings.portSettings.allowSettingsChangesWhenOpen = false;
}
appDataV2.currentAppConfig.settings.portSettings.allowSettingsChangesWhenOpen = false;
appDataV2.version = 2;
wasChanged = true;
}

if (updatedAppData.version === 2) {
// Nothing to do, already latest version
// updatedAppData = appData;
console.log(`App data is at latest version (v${updatedAppData.version}).`);
}

if (updatedAppData.version !== 2) {
console.error('Unknown app data version found: ', appData.version);
updatedAppData = new AppDataV2();
wasChanged = true;
}

return { appData: updatedAppData, wasChanged };
}

/**
* Save the current app configuration to local storage.
*/
Expand All @@ -184,7 +265,7 @@ export class ProfileManager {
newProfileNameToCheck = newProfileName + ' ' + nextProfileNum;
}
// At this point newProfileNameToCheck is the name we want
const newProfile = new Profile(newProfileNameToCheck);
const newProfile = new ProfileV3(newProfileNameToCheck);
this.appData.profiles.push(newProfile);
this.saveAppData();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,33 @@ export class PortConfigurationConfigV2 {
reopenSerialPortIfUnexpectedlyClosed = true;
}

export class PortConfigurationConfigV3 {
/**
* Increment this version number if you need to update this data in this class.
* This will cause the app to ignore whatever is in local storage and use the defaults,
* updating to this new version.
*/
version = 3;

baudRate = 115200;

numDataBits = 8;

parity = Parity.NONE;

stopBits: StopBits = 1;

flowControl = FlowControl.NONE;

connectToSerialPortAsSoonAsItIsSelected = true;

resumeConnectionToLastSerialPortOnStartup = true;

reopenSerialPortIfUnexpectedlyClosed = true;

allowSettingsChangesWhenOpen = false;
}

export default class PortConfiguration {

app: App
Expand Down Expand Up @@ -178,18 +205,6 @@ export default class PortConfiguration {

_loadConfig = () => {
let configToLoad = this.profileManager.appData.currentAppConfig.settings.portSettings
//===============================================
// UPGRADE PATH
//===============================================
const latestVersion = new PortConfigurationConfigV2().version;
if (configToLoad.version === latestVersion) {
// Do nothing
} else {
console.log(`Out-of-date config version ${configToLoad.version} found.` +
` Updating to version ${latestVersion}.`);
this._saveConfig();
configToLoad = this.profileManager.appData.currentAppConfig.settings.portSettings
}

// At this point we are confident that the deserialized config matches what
// this classes config object wants, so we can go ahead and update.
Expand All @@ -201,6 +216,7 @@ export default class PortConfiguration {
this.connectToSerialPortAsSoonAsItIsSelected = configToLoad.connectToSerialPortAsSoonAsItIsSelected;
this.resumeConnectionToLastSerialPortOnStartup = configToLoad.resumeConnectionToLastSerialPortOnStartup;
this.reopenSerialPortIfUnexpectedlyClosed = configToLoad.reopenSerialPortIfUnexpectedlyClosed;
this.allowSettingsChangesWhenOpen = configToLoad.allowSettingsChangesWhenOpen;

this.setBaudRateInputValue(this.baudRate.toString());
};
Expand All @@ -216,6 +232,7 @@ export default class PortConfiguration {
config.connectToSerialPortAsSoonAsItIsSelected = this.connectToSerialPortAsSoonAsItIsSelected;
config.resumeConnectionToLastSerialPortOnStartup = this.resumeConnectionToLastSerialPortOnStartup;
config.reopenSerialPortIfUnexpectedlyClosed = this.reopenSerialPortIfUnexpectedlyClosed;
config.allowSettingsChangesWhenOpen = this.allowSettingsChangesWhenOpen;

this.profileManager.saveAppData();
};
Expand Down

0 comments on commit c2f54bd

Please sign in to comment.