This commit is contained in:
Drew Ansbacher
2021-06-30 16:54:27 -06:00
committed by Aiden McClelland
parent 8f0e0a392e
commit 834de9ab54
16 changed files with 178 additions and 217 deletions

View File

@@ -5,37 +5,11 @@
{ {
"files": ["*.ts"], "files": ["*.ts"],
"parserOptions": { "parserOptions": {
"project": ["tsconfig.json", "e2e/tsconfig.json"], "project": ["tsconfig.json"],
"createDefaultProgram": true "createDefaultProgram": true
}, },
"extends": [
"plugin:@angular-eslint/ng-cli-compat",
"plugin:@angular-eslint/ng-cli-compat--formatting-add-on",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": { "rules": {
"@angular-eslint/component-class-suffix": [ "semi": [1, "never"]
"error",
{
"suffixes": ["Page", "Component"]
}
],
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "app",
"style": "kebab-case"
}
],
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": "app",
"style": "camelCase"
}
]
} }
}, },
{ {

View File

@@ -12,6 +12,7 @@
Thumbs.db Thumbs.db
UserInterfaceState.xcuserstate UserInterfaceState.xcuserstate
$RECYCLE.BIN/ $RECYCLE.BIN/
/out-tsc
*.log *.log
log.txt log.txt

View File

@@ -10,15 +10,6 @@ const routes: Routes = [
path: 'recover', path: 'recover',
loadChildren: () => import('./pages/recover/recover.module').then( m => m.RecoverPageModule) loadChildren: () => import('./pages/recover/recover.module').then( m => m.RecoverPageModule)
}, },
{
path: 'password',
loadChildren: () => import('./pages/password/password.module').then( m => m.PasswordPageModule)
},
{
path: '',
redirectTo: 'wizard',
pathMatch: 'full'
},
]; ];
@NgModule({ @NgModule({

View File

@@ -3,9 +3,6 @@
<h2 color="light">Connecting to Embassy</h2> <h2 color="light">Connecting to Embassy</h2>
</ion-content> </ion-content>
<ng-template #loaded> <ng-template #loaded>
<ion-content *ngIf="error"> <ion-router-outlet></ion-router-outlet>
<h2 color="light">{{ error }}</h2>
</ion-content>
<ion-router-outlet *ngIf="!error"></ion-router-outlet>
</ng-template> </ng-template>
</ion-app> </ion-app>

View File

@@ -1,20 +1,20 @@
import { Component } from '@angular/core'; import { Component, OnInit } from '@angular/core'
import { NavController, ToastController } from '@ionic/angular'; import { NavController, ToastController } from '@ionic/angular'
import { ApiService } from './services/api/api.service'; import { ApiService } from './services/api/api.service'
import { StateService } from './services/state.service'; import { StateService } from './services/state.service'
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
templateUrl: 'app.component.html', templateUrl: 'app.component.html',
styleUrls: ['app.component.scss'], styleUrls: ['app.component.scss'],
}) })
export class AppComponent { export class AppComponent implements OnInit {
constructor( constructor(
private readonly apiService: ApiService, private readonly apiService: ApiService,
private readonly stateService: StateService, private readonly stateService: StateService,
private readonly navCtrl: NavController, private readonly navCtrl: NavController,
public toastController: ToastController private readonly toastController: ToastController
) { ) {
this.apiService.watchError$.subscribe(error => { this.apiService.watchError$.subscribe(error => {
if(error) { if(error) {
@@ -25,12 +25,10 @@ export class AppComponent {
async ngOnInit() { async ngOnInit() {
await this.stateService.getState() await this.stateService.getState()
if (!this.stateService.selectedDataDrive) { if (this.stateService.recoveryDrive) {
await this.navCtrl.navigateForward(`/wizard`)
} else if(this.stateService.hasPassword) {
//redirect to embassyOS
} else if (this.stateService.recoveryDrive) {
await this.navCtrl.navigateForward(`/recover`) await this.navCtrl.navigateForward(`/recover`)
} else {
await this.navCtrl.navigateForward(`/wizard`)
} }
} }
@@ -45,9 +43,9 @@ export class AppComponent {
role: 'cancel', role: 'cancel',
} }
] ]
}); })
await toast.present(); await toast.present()
await toast.onDidDismiss(); await toast.onDidDismiss()
} }
} }

View File

@@ -3,6 +3,7 @@ import { CommonModule } from '@angular/common';
import { IonicModule } from '@ionic/angular'; import { IonicModule } from '@ionic/angular';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { HomePage } from './home.page'; import { HomePage } from './home.page';
import { PasswordPageModule } from '../password/password.module';
import { HomePageRoutingModule } from './home-routing.module'; import { HomePageRoutingModule } from './home-routing.module';
@@ -12,7 +13,8 @@ import { HomePageRoutingModule } from './home-routing.module';
CommonModule, CommonModule,
FormsModule, FormsModule,
IonicModule, IonicModule,
HomePageRoutingModule HomePageRoutingModule,
PasswordPageModule,
], ],
declarations: [HomePage] declarations: [HomePage]
}) })

View File

@@ -6,17 +6,17 @@
</ion-toolbar> </ion-toolbar>
</ion-header> </ion-header>
<ion-content> <ion-content>
<div *ngIf="!stateService.selectedDataDrive"> <div *ngIf="!stateService.dataDrive">
<h2 color="light">Select Data Drive</h2> <h2 color="light">Select Data Drive</h2>
<ion-card <ion-card
*ngFor="let drive of dataDrives" *ngFor="let drive of dataDrives"
(click)="selectDrive(drive)" (click)="selectDrive(drive)"
button="true" button="true"
[class.selected]="selectedDrive === drive['logical-name']" [class.selected]="selectedDrive?.logicalname === drive.logicalname"
color="light" color="light"
> >
<ion-card-header> <ion-card-header>
<ion-card-title>{{drive["logical-name"]}}</ion-card-title> <ion-card-title>{{drive.logicalname}}</ion-card-title>
<ion-card-subtitle>{{drive.labels}}</ion-card-subtitle> <ion-card-subtitle>{{drive.labels}}</ion-card-subtitle>
</ion-card-header> </ion-card-header>
@@ -26,7 +26,7 @@
</ion-card> </ion-card>
<ion-button (click)="warn()" color="primary" [disabled]="!selectedDrive">Next</ion-button> <ion-button (click)="warn()" color="primary" [disabled]="!selectedDrive">Next</ion-button>
</div> </div>
<div *ngIf="stateService.selectedDataDrive"> <div *ngIf="stateService.dataDrive">
<ion-card <ion-card
(click)="presentPasswordModal()" (click)="presentPasswordModal()"
button="true" button="true"

View File

@@ -1,6 +1,6 @@
import { Component } from '@angular/core' import { Component } from '@angular/core'
import { AlertController, ModalController } from '@ionic/angular' import { AlertController, ModalController, LoadingController } from '@ionic/angular'
import { ApiService } from 'src/app/services/api/api.service' import { ApiService, DataDrive } from 'src/app/services/api/api.service'
import { StateService } from 'src/app/services/state.service' import { StateService } from 'src/app/services/state.service'
import { PasswordPage } from '../password/password.page' import { PasswordPage } from '../password/password.page'
@@ -11,26 +11,27 @@ import { PasswordPage } from '../password/password.page'
}) })
export class HomePage { export class HomePage {
dataDrives = [] dataDrives = []
selectedDrive = null selectedDrive: DataDrive = null
constructor( constructor(
private readonly apiService: ApiService, private readonly apiService: ApiService,
private readonly stateService: StateService, private readonly stateService: StateService,
private readonly alertController: AlertController, private readonly alertController: AlertController,
private modalController: ModalController, private readonly modalController: ModalController,
private readonly loadingCtrl: LoadingController,
) {} ) {}
async ngOnInit() { async ngOnInit() {
if(!this.stateService.selectedDataDrive) { if(!this.stateService.dataDrive) {
this.dataDrives = await this.apiService.getStorageDisks() this.dataDrives = await this.apiService.getDataDrives()
} }
} }
selectDrive(name: string) { selectDrive(drive: DataDrive) {
if (name === this.selectedDrive) { if (drive.logicalname === this.selectedDrive?.logicalname) {
this.selectedDrive = null this.selectedDrive = null
} else { } else {
this.selectedDrive = name this.selectedDrive = drive
} }
} }
@@ -38,7 +39,7 @@ export class HomePage {
const alert = await this.alertController.create({ const alert = await this.alertController.create({
cssClass: 'my-custom-class', cssClass: 'my-custom-class',
header: 'Warning!', header: 'Warning!',
message: 'This disk will be entirely wiped of all memory.', message: 'This drive will be entirely wiped of all memory.',
buttons: [ buttons: [
{ {
text: 'Cancel', text: 'Cancel',
@@ -50,7 +51,7 @@ export class HomePage {
}, { }, {
text: 'Okay', text: 'Okay',
handler: async () => { handler: async () => {
await this.chooseDisk() await this.chooseDrive()
} }
} }
] ]
@@ -59,30 +60,38 @@ export class HomePage {
await alert.present(); await alert.present();
} }
async chooseDisk() { async chooseDrive() {
await this.apiService.selectStorageDisk({logicalName: this.selectedDrive}) await this.apiService.selectDataDrive(this.selectedDrive.logicalname)
this.stateService.selectedDataDrive = this.selectedDrive this.stateService.dataDrive = this.selectedDrive
} }
async presentPasswordModal() { async presentPasswordModal() {
const modal = await this.modalController.create({ const modal = await this.modalController.create({
component: PasswordPage, component: PasswordPage,
backdropDismiss: false, backdropDismiss: false
componentProps: {
'version': null,
}
}) })
modal.onDidDismiss().then(ret => { modal.onDidDismiss().then(ret => {
if(ret.data.pwValid) { const pass = ret.data.password
this.submitPassword(ret.data.password) if (pass) {
this.submitPassword(pass)
} }
}) })
await modal.present(); await modal.present();
} }
async submitPassword (pw: string) { async submitPassword (pw: string) {
await this.apiService.submitPassword(pw) const loader = await this.loadingCtrl.create({
// @TODO navigate to embassyOS message: 'Setting up your Embassy'
})
await loader.present()
try {
await this.apiService.submitPassword(pw)
location.reload()
} catch (e) {
} finally {
loader.dismiss()
}
} }
} }

View File

@@ -6,12 +6,12 @@
</ion-toolbar> </ion-toolbar>
</ion-header> </ion-header>
<ion-content> <ion-content>
<div *ngIf="!needsVer"> <div *ngIf="needsVer">
<h2>Enter Password</h2> <h2>Enter Password</h2>
<ion-input type="password" [(ngModel)]="password">Password:</ion-input> <ion-input type="password" [(ngModel)]="password">Password:</ion-input>
</div> </div>
<div *ngIf="needsVer"> <div *ngIf="!needsVer">
<h2>Create Password</h2> <h2>Create Password</h2>
<ion-input type="password" [(ngModel)]="password">Password:</ion-input> <ion-input type="password" [(ngModel)]="password">Password:</ion-input>
<ion-input type="password" [(ngModel)]="passwordVer">Verify Password:</ion-input> <ion-input type="password" [(ngModel)]="passwordVer">Verify Password:</ion-input>

View File

@@ -1,5 +1,6 @@
import { Component, Input } from '@angular/core' import { Component, Input } from '@angular/core'
import { ModalController } from '@ionic/angular' import { ModalController } from '@ionic/angular'
import { RecoveryDrive } from 'src/app/services/api/api.service'
@Component({ @Component({
selector: 'password', selector: 'password',
@@ -7,9 +8,9 @@ import { ModalController } from '@ionic/angular'
styleUrls: ['password.page.scss'], styleUrls: ['password.page.scss'],
}) })
export class PasswordPage { export class PasswordPage {
@Input() version: string | null @Input() recoveryDrive: RecoveryDrive
needsVer = true needsVer: boolean
error = '' error = ''
password = '' password = ''
@@ -20,27 +21,20 @@ export class PasswordPage {
) {} ) {}
ngOnInit() { ngOnInit() {
this.needsVer = !this.version?.startsWith('0.3') this.needsVer = !!this.recoveryDrive && !this.recoveryDrive.version.startsWith('0.2')
console.log('needs', this.needsVer)
} }
async submitPassword () { async submitPassword () {
if (this.needsVer && this.password !== this.passwordVer) { if (!this.needsVer && this.password !== this.passwordVer) {
this.error="*passwords dont match" this.error="*passwords dont match"
} else { } else {
this.dismiss(true) this.modalController.dismiss({
password: this.password,
})
} }
} }
cancel () { cancel () {
this.dismiss(false) this.modalController.dismiss()
} }
dismiss(submitted: boolean) {
this.modalController.dismiss({
pwValid: submitted,
pw: this.password
});
}
} }

View File

@@ -3,6 +3,7 @@ import { CommonModule } from '@angular/common';
import { IonicModule } from '@ionic/angular'; import { IonicModule } from '@ionic/angular';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { RecoverPage } from './recover.page'; import { RecoverPage } from './recover.page';
import { PasswordPageModule } from '../password/password.module';
import { RecoverPageRoutingModule } from './recover-routing.module'; import { RecoverPageRoutingModule } from './recover-routing.module';
@@ -12,7 +13,8 @@ import { RecoverPageRoutingModule } from './recover-routing.module';
CommonModule, CommonModule,
FormsModule, FormsModule,
IonicModule, IonicModule,
RecoverPageRoutingModule RecoverPageRoutingModule,
PasswordPageModule,
], ],
declarations: [RecoverPage] declarations: [RecoverPage]
}) })

View File

@@ -7,16 +7,16 @@
</ion-header> </ion-header>
<ion-content> <ion-content>
<div *ngIf="!stateService.recoveryDrive"> <div *ngIf="!stateService.recoveryDrive">
<h2 color="light">Select Data Drive</h2> <h2 color="light">Select Recovery Drive</h2>
<ion-card <ion-card
*ngFor="let drive of dataDrives" *ngFor="let drive of dataDrives"
(click)="selectDrive(drive)" (click)="selectDrive(drive)"
button="true" button="true"
[class.selected]="selectedDrive === drive['logical-name']" [class.selected]="selectedDrive?.logicalname === drive.logicalname"
color="light" color="light"
> >
<ion-card-header> <ion-card-header>
<ion-card-title>{{drive["logical-name"]}}</ion-card-title> <ion-card-title>{{drive.logicalname}}</ion-card-title>
<ion-card-subtitle>{{drive.name}}</ion-card-subtitle> <ion-card-subtitle>{{drive.name}}</ion-card-subtitle>
</ion-card-header> </ion-card-header>
@@ -24,15 +24,15 @@
Currently running {{drive.version}} Currently running {{drive.version}}
</ion-card-content> </ion-card-content>
</ion-card> </ion-card>
<ion-button (click)="warn()" color="primary" [disabled]="!selectedDrive">Next</ion-button> <ion-button (click)="chooseDrive()" color="primary" [disabled]="!selectedDrive">Next</ion-button>
</div> </div>
<div *ngIf="stateService.recoveryDrive"> <div *ngIf="stateService.recoveryDrive">
<h2>Progress: {{ 100 * stateService.dataProgress }}% <ion-spinner *ngIf="stateService.dataProgress != 1"></ion-spinner> </h2> <h2>Progress: {{ 100 * stateService.dataProgress }}% <ion-spinner *ngIf="stateService.dataProgress !== 1"></ion-spinner> </h2>
<ion-progress-bar value="{{stateService.dataProgress}}"></ion-progress-bar> <ion-progress-bar value="{{stateService.dataProgress}}"></ion-progress-bar>
<ion-button <ion-button
(click)="navToEmbassy()" (click)="navToEmbassy()"
color="primary" color="primary"
[disabled]="stateService.dataProgress != 1" [disabled]="stateService.dataProgress !== 1"
> >
Go To Embassy Go To Embassy
</ion-button> </ion-button>

View File

@@ -1,6 +1,6 @@
import { Component } from '@angular/core' import { Component } from '@angular/core'
import { AlertController, ModalController } from '@ionic/angular' import { AlertController, ModalController, LoadingController } from '@ionic/angular'
import { ApiService, EmbassyDrive } from 'src/app/services/api/api.service' import { ApiService, RecoveryDrive } from 'src/app/services/api/api.service'
import { StateService } from 'src/app/services/state.service' import { StateService } from 'src/app/services/state.service'
import { PasswordPage } from '../password/password.page' import { PasswordPage } from '../password/password.page'
@@ -11,62 +11,33 @@ import { PasswordPage } from '../password/password.page'
}) })
export class RecoverPage { export class RecoverPage {
dataDrives = [] dataDrives = []
selectedDrive = null selectedDrive: RecoveryDrive = null
selectedVersion = null
constructor( constructor(
private readonly apiService: ApiService, private readonly apiService: ApiService,
private readonly stateService: StateService, private readonly stateService: StateService,
public alertController: AlertController, public alertController: AlertController,
private modalController: ModalController, private modalController: ModalController,
private readonly loadingCtrl: LoadingController,
) {} ) {}
async ngOnInit() { async ngOnInit() {
if(!this.stateService.recoveryDrive) { if(!this.stateService.recoveryDrive) {
this.dataDrives = await this.apiService.getEmbassyDrives() this.dataDrives = await this.apiService.getRecoveryDrives()
} else { } else {
this.stateService.pollDataTransferProgress() this.stateService.pollDataTransferProgress()
} }
} }
selectDrive(disk: EmbassyDrive) { selectDrive(drive: RecoveryDrive) {
const name = disk['logical-name'] if (drive.logicalname === this.selectedDrive?.logicalname) {
const version = disk.version
if (name === this.selectedDrive) {
this.selectedDrive = null this.selectedDrive = null
this.selectedVersion = null
} else { } else {
this.selectedDrive = name this.selectedDrive = drive
this.selectedVersion = version
} }
} }
async warn() { async chooseDrive() {
const alert = await this.alertController.create({
cssClass: 'my-custom-class',
header: 'Warning!',
message: 'Once you select this the recovery process will begin.',
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary',
handler: () => {
this.selectedDrive = null
}
}, {
text: 'Okay',
handler: async () => {
await this.chooseDisk()
}
}
]
});
await alert.present();
}
async chooseDisk() {
this.presentPasswordModal() this.presentPasswordModal()
} }
@@ -75,25 +46,38 @@ export class RecoverPage {
component: PasswordPage, component: PasswordPage,
backdropDismiss: false, backdropDismiss: false,
componentProps: { componentProps: {
'version': this.selectedVersion, recoveryDrive: this.selectedDrive,
} }
}) })
modal.onDidDismiss().then(ret => { modal.onDidDismiss().then(ret => {
if(ret.data.pwValid) { const pass = ret.data.password
this.submitPWAndDisk(ret.data.password) if(pass) {
this.submitPWAndDrive(pass)
} }
}) })
await modal.present(); await modal.present();
} }
async submitPWAndDisk(pw: string) { async submitPWAndDrive(pw: string) {
await this.apiService.selectEmbassyDrive({logicalName: this.selectedDrive}, pw) const loader = await this.loadingCtrl.create({
this.stateService.recoveryDrive = this.selectedDrive message: 'Validating password'
this.stateService.pollDataTransferProgress() })
await loader.present()
try {
await this.apiService.selectRecoveryDrive(this.selectedDrive.logicalname, pw)
this.stateService.recoveryDrive = this.selectedDrive
this.stateService.pollDataTransferProgress()
} catch (e) {
} finally {
loader.dismiss()
}
} }
async navToEmbassy() { async navToEmbassy() {
// @TODO nav to embassy location.reload()
} }
} }

View File

@@ -1,37 +1,36 @@
import { Subject } from "rxjs"; import { Subject } from 'rxjs'
export abstract class ApiService { export abstract class ApiService {
protected error$: Subject<string> = new Subject() protected error$: Subject<string> = new Subject();
watchError$ = this.error$.asObservable() watchError$ = this.error$.asObservable();
abstract getState (): Promise<State> abstract getState (): Promise<State>;
abstract getStorageDisks (): Promise<StorageDisk[]> abstract getDataDrives (): Promise<DataDrive[]>;
abstract selectStorageDisk (disk: { logicalName: string }): Promise<void> abstract selectDataDrive (logicalName: string): Promise<void>;
abstract getEmbassyDrives (): Promise<EmbassyDrive[]> abstract getRecoveryDrives (): Promise<RecoveryDrive[]>;
abstract selectEmbassyDrive (disk: { logicalName: string }, password: string): Promise<void> abstract selectRecoveryDrive (logicalName: string, password: string): Promise<void>;
abstract getDataTransferProgress () : Promise<TransferProgress> abstract getDataTransferProgress (): Promise<TransferProgress>;
abstract submitPassword (password: string) : Promise<void> abstract submitPassword (password: string): Promise<void>;
} }
export interface State { export interface State {
'selected-data-drive': string | null, 'data-drive': DataDrive | null;
'recovery-drive': string | null, 'recovery-drive': RecoveryDrive | null;
'has-password': boolean,
} }
export interface TransferProgress { export interface TransferProgress {
'bytes-transfered': number 'bytes-transfered': number;
'total-bytes': number 'total-bytes': number;
} }
export interface StorageDisk { export interface DataDrive {
"logical-name": string logicalname: string;
labels: string[] labels: string[];
capacity: number capacity: number;
used: number used: number;
} }
export interface EmbassyDrive { export interface RecoveryDrive {
"logical-name": string logicalname: string;
version: string version: string;
name: string name: string;
} }

View File

@@ -1,26 +1,36 @@
import { Injectable } from "@angular/core"; import { Injectable } from '@angular/core'
import { pauseFor } from "../state.service"; import { pauseFor } from '../state.service'
import { ApiService } from "./api.service" import { ApiService } from './api.service'
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class MockApiService extends ApiService { export class MockApiService extends ApiService {
constructor () { constructor() {
super() super()
} }
async getState () { async getState() {
await pauseFor(2000)
return { return {
'selected-data-drive': 'page1', 'data-drive': null,
// {
// logicalname: 'name1',
// labels: ['label 1', 'label 2'],
// capacity: 1600,
// used: 200,
// },
'recovery-drive': null, 'recovery-drive': null,
'has-password': false, // {
'data-transfer-progress': null // logicalname: 'name1',
// version: '0.3.3',
// name: 'My Embassy'
// }
} }
} }
async getDataTransferProgress () { async getDataTransferProgress() {
tries = Math.min(tries + 1, 4) tries = Math.min(tries + 1, 4)
return { return {
'bytes-transfered': tries, 'bytes-transfered': tries,
@@ -28,17 +38,17 @@ export class MockApiService extends ApiService {
} }
} }
async getStorageDisks () { async getDataDrives() {
await pauseFor(2000) await pauseFor(2000)
return [ return [
{ {
"logical-name": 'name1', logicalname: 'name1',
labels: ['label 1', 'label 2'], labels: ['label 1', 'label 2'],
capacity: 1600, capacity: 1600,
used: 200, used: 200,
}, },
{ {
"logical-name": 'name2', logicalname: 'name2',
labels: [], labels: [],
capacity: 1600, capacity: 1600,
used: 0, used: 0,
@@ -46,31 +56,31 @@ export class MockApiService extends ApiService {
] ]
} }
async selectStorageDisk(disk) { async selectDataDrive(drive) {
await pauseFor(200) await pauseFor(2000)
return return
} }
async getEmbassyDrives () { async getRecoveryDrives() {
await pauseFor(2000) await pauseFor(2000)
return [ return [
{ {
"logical-name": 'name1', logicalname: 'name1',
version: '0.2.3', version: '0.3.3',
name: 'Embassy 0.2.3' name: 'My Embassy'
} }
] ]
} }
async selectEmbassyDrive(disk) { async selectRecoveryDrive(logicalName, password) {
await pauseFor(200) await pauseFor(2000)
return return
} }
async submitPassword(password) { async submitPassword(password) {
await pauseFor(200) await pauseFor(2000)
return return
} }
} }
let tries = 2 let tries = 0

View File

@@ -1,38 +1,37 @@
import { Injectable } from "@angular/core"; import { Injectable } from '@angular/core'
import { ApiService } from "./api/api.service" import { ApiService, DataDrive, RecoveryDrive } from './api/api.service'
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class StateService { export class StateService {
loading = true loading = true;
selectedDataDrive: string dataDrive: DataDrive;
recoveryDrive: string recoveryDrive: RecoveryDrive;
hasPassword: Boolean dataTransferProgress: { bytesTransfered: number; totalBytes: number } | null;
dataTransferProgress: { bytesTransfered: number, totalBytes: number } | null dataProgress = 0;
dataProgress = 0
constructor ( constructor(
private readonly apiService: ApiService private readonly apiService: ApiService
) {} ) {}
async getState () { async getState() {
const state = await this.apiService.getState() const state = await this.apiService.getState()
if(state) { if(state) {
this.selectedDataDrive = state['selected-data-drive'] this.dataDrive = state['data-drive']
this.recoveryDrive = state['recovery-drive'] this.recoveryDrive = state['recovery-drive']
this.hasPassword = state['has-password']
this.loading = false this.loading = false
} }
} }
async pollDataTransferProgress () { async pollDataTransferProgress() {
if ( if (
this.dataTransferProgress?.totalBytes && this.dataTransferProgress?.totalBytes &&
this.dataTransferProgress.bytesTransfered === this.dataTransferProgress.totalBytes this.dataTransferProgress.bytesTransfered === this.dataTransferProgress.totalBytes
) {return } ) {return }
const progress = await this.apiService.getDataTransferProgress() const progress = await this.apiService.getDataTransferProgress()
this.dataTransferProgress = { this.dataTransferProgress = {
bytesTransfered: progress['bytes-transfered'], bytesTransfered: progress['bytes-transfered'],
@@ -46,6 +45,7 @@ export class StateService {
} }
} }
export function pauseFor (ms: number): Promise<void> { export const pauseFor = (ms: number) => {
return new Promise(resolve => setTimeout(resolve, ms)) const promise = new Promise(resolve => setTimeout(resolve, ms))
} return promise
};