better migration progress bar (#1993)

* better migration progress bar

* show different messages based on setup type and fix modal height

* type safety

Co-authored-by: Matt Hill <matthewonthemoon@gmail.com>
This commit is contained in:
Aiden McClelland
2022-11-29 11:45:46 -07:00
committed by GitHub
parent ccb85737f7
commit 837d4c1597
15 changed files with 120 additions and 90 deletions

View File

@@ -28,6 +28,7 @@ export class AttachPage {
) {}
async ngOnInit() {
this.stateService.setupType = 'attach'
await this.getDrives()
}

View File

@@ -1,5 +1,5 @@
<ion-content>
<ion-grid>
<ion-grid *ngIf="!loading">
<ion-row class="ion-align-items-center">
<ion-col class="ion-text-center">
<div style="padding-bottom: 32px">
@@ -9,7 +9,7 @@
style="max-width: 220px"
/>
</div>
<ion-card *ngIf="!loading" color="dark">
<ion-card color="dark">
<ion-card-header>
<ion-button
*ngIf="swiper?.activeIndex === 1"

View File

@@ -3,6 +3,7 @@ import { IonicSlides } from '@ionic/angular'
import { ApiService } from 'src/app/services/api/api.service'
import SwiperCore, { Swiper } from 'swiper'
import { ErrorToastService } from '@start9labs/shared'
import { StateService } from 'src/app/services/state.service'
SwiperCore.use([IonicSlides])
@@ -19,9 +20,11 @@ export class HomePage {
constructor(
private readonly api: ApiService,
private readonly errToastService: ErrorToastService,
private readonly stateService: StateService,
) {}
async ionViewDidEnter() {
this.stateService.setupType = 'fresh'
if (this.swiper) {
this.swiper.allowTouchMove = false
}

View File

@@ -2,16 +2,11 @@ import { NgModule } from '@angular/core'
import { CommonModule } from '@angular/common'
import { IonicModule } from '@ionic/angular'
import { FormsModule } from '@angular/forms'
import { LoadingPage } from './loading.page'
import { LoadingPage, ToMessagePipe } from './loading.page'
import { LoadingPageRoutingModule } from './loading-routing.module'
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
LoadingPageRoutingModule,
],
declarations: [LoadingPage],
imports: [CommonModule, FormsModule, IonicModule, LoadingPageRoutingModule],
declarations: [LoadingPage, ToMessagePipe],
})
export class LoadingPageModule { }
export class LoadingPageModule {}

View File

@@ -2,12 +2,15 @@
<ion-grid>
<ion-row class="ion-align-items-center">
<ion-col class="ion-text-center">
<ion-card color="dark">
<ion-card
*ngIf="{ decimal: progress$ | async } as progress"
color="dark"
>
<ion-card-header>
<ion-card-title>Initializing Embassy</ion-card-title>
<div class="center-wrapper">
<ion-card-subtitle *ngIf="stateService.dataProgress">
Progress: {{ (stateService.dataProgress * 100).toFixed(0)}}%
<ion-card-subtitle *ngIf="progress.decimal as decimal">
Progress: {{ (decimal * 100).toFixed(0)}}%
</ion-card-subtitle>
</div>
</ion-card-header>
@@ -21,10 +24,10 @@
padding-bottom: 20px;
margin-bottom: 40px;
"
[type]="stateService.dataProgress ? 'determinate' : 'indeterminate'"
[value]="stateService.dataProgress"
[type]="progress.decimal ? 'determinate' : 'indeterminate'"
[value]="progress.decimal || 0"
></ion-progress-bar>
<p>Setting up your Embassy. This can take a while.</p>
<p>{{ progress.decimal | toMessage }}</p>
</ion-card-content>
</ion-card>
</ion-col>

View File

@@ -8,14 +8,16 @@ import { StateService } from 'src/app/services/state.service'
styleUrls: ['loading.page.scss'],
})
export class LoadingPage {
readonly progress$ = this.stateService.dataProgress$
constructor(
public stateService: StateService,
private navCtrl: NavController,
private readonly stateService: StateService,
private readonly navCtrl: NavController,
) {}
ngOnInit() {
this.stateService.pollDataTransferProgress()
const progSub = this.stateService.dataCompletionSubject.subscribe(
const progSub = this.stateService.dataCompletionSubject$.subscribe(
async complete => {
if (complete) {
progSub.unsubscribe()
@@ -25,3 +27,30 @@ export class LoadingPage {
)
}
}
import { Pipe, PipeTransform } from '@angular/core'
@Pipe({
name: 'toMessage',
})
export class ToMessagePipe implements PipeTransform {
constructor(private readonly stateService: StateService) {}
transform(progress: number | null): string {
switch (this.stateService.setupType) {
case 'fresh':
case 'attach':
return 'Setting up your Embassy'
case 'restore':
return 'Restoring data. This can take a while.'
case 'transfer':
if (!progress) {
return 'Preparing data. Depending on how much data you have, this could take up to 1 hour'
} else {
return 'Transferring data'
}
default:
return ''
}
}
}

View File

@@ -25,6 +25,7 @@ export class RecoverPage {
) {}
async ngOnInit() {
this.stateService.setupType = 'restore'
await this.getDrives()
}

View File

@@ -22,6 +22,7 @@ export class TransferPage {
) {}
async ngOnInit() {
this.stateService.setupType = 'transfer'
await this.getDrives()
}

View File

@@ -29,7 +29,7 @@ type Encrypted = {
export type StatusRes = {
'bytes-transferred': number
'total-bytes': number
'total-bytes': number | null
complete: boolean
} | null

View File

@@ -31,7 +31,7 @@ export class MockApiService extends ApiService {
return {
'bytes-transferred': restoreOrMigrate ? progress : 0,
'total-bytes': restoreOrMigrate ? total : 0,
'total-bytes': restoreOrMigrate ? total : null,
complete: progress === total,
}
}

View File

@@ -7,16 +7,18 @@ import { pauseFor, ErrorToastService } from '@start9labs/shared'
providedIn: 'root',
})
export class StateService {
setupType?: 'fresh' | 'restore' | 'attach' | 'transfer'
recoverySource?: RecoverySource
recoveryPassword?: string
dataTransferProgress?: {
bytesTransferred: number
totalBytes: number
totalBytes: number | null
complete: boolean
}
dataProgress = 0
dataCompletionSubject = new BehaviorSubject(false)
dataProgress$ = new BehaviorSubject<number>(0)
dataCompletionSubject$ = new BehaviorSubject(false)
constructor(
private readonly api: ApiService,
@@ -27,7 +29,7 @@ export class StateService {
await pauseFor(500)
if (this.dataTransferProgress?.complete) {
this.dataCompletionSubject.next(true)
this.dataCompletionSubject$.next(true)
return
}
@@ -41,9 +43,10 @@ export class StateService {
complete: progress.complete,
}
if (this.dataTransferProgress.totalBytes) {
this.dataProgress =
this.dataProgress$.next(
this.dataTransferProgress.bytesTransferred /
this.dataTransferProgress.totalBytes
this.dataTransferProgress.totalBytes,
)
}
} catch (e: any) {
this.errorToastService.present({

View File

@@ -1,5 +1,4 @@
$wide-modal: 900px;
$medium-modal: 600px;
body {
-webkit-user-select: text;
@@ -24,17 +23,16 @@ ion-alert {
}
}
ion-modal::part(content) {
position: absolute;
height: 90% !important;
top: 5%;
width: 90% !important;
left: 5%;
display: block;
border-radius: 6px;
border: 2px solid rgba(255, 255, 255, 0.03);
box-shadow: 0 32px 64px rgba(0, 0, 0, 0.2);
ion-modal {
--max-height: 600px;
&::part(content) {
width: 90% !important;
left: 5%;
border-radius: 6px;
border: 2px solid rgba(255, 255, 255, 0.03);
box-shadow: 0 32px 64px rgba(0, 0, 0, 0.2);
}
}
.alertlike-modal {
@@ -47,33 +45,8 @@ ion-modal::part(content) {
}
}
.medium-modal {
&::part(content) {
position: absolute;
height: 80% !important;
top: 10%;
width: 90% !important;
left: 5% !important;
}
}
@media (min-width: 1000px) {
.medium-modal {
&::part(content) {
position: absolute;
height: 80% !important;
top: 10%;
width: $medium-modal !important;
left: calc((100vw - $medium-modal) / 2) !important;
}
}
}
@media (min-width: 1000px) {
ion-modal::part(content) {
position: absolute;
height: 80% !important;
top: 10%;
width: $wide-modal !important;
left: calc((100vw - $wide-modal) / 2) !important;
}