Skip to content

Commit

Permalink
Selective Import/Export of accounts (#12)
Browse files Browse the repository at this point in the history
* Selective EXPORT of accounts

* Refactor export account modal component

- Changed export account modal to be generic between import and export
- better UI of the account selection flow

* Selective Import of accounts and file integrity verification

* sort translation keys

* Fix loading presentation

* better import/export error handling
  • Loading branch information
jlcvp authored Sep 13, 2024
1 parent 7f7e897 commit f241006
Show file tree
Hide file tree
Showing 11 changed files with 331 additions and 88 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "authleu",
"version": "1.0.0",
"version": "1.0.1",
"author": "Leonardo 'Leu' Pereira <[email protected]>",
"homepage": "https://ionicframework.com/",
"homepage": "https://github.com/jlcvp/AuthLeu",
"scripts": {
"ng": "ng",
"start": "ng serve",
Expand Down
7 changes: 0 additions & 7 deletions src/app/components/account-detail/account-detail.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,10 @@ export class AccountDetailComponent {
@HostListener('window:focus', ['$event'])
onFocus(event: FocusEvent): void {
// resume timer
console.log("Window focused")
this.updateCode()
this.updateTokenCountdown()
}

@HostListener('window:blur', ['$event'])
onBlur(event: FocusEvent): void {
// stop timer, camera, etc
console.log("Window blurred")
}

get account(): Account2FA | undefined {
return this._account
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-button (click)="closeModal()">
<ion-icon *ngIf="isMD" slot="icon-only" name="close-outline"></ion-icon>
<ion-label *ngIf="!isMD">{{ "ACCOUNT_SELECT_MODAL.CANCEL" | translate }}</ion-label>
</ion-button>
</ion-buttons>
<ion-title>{{ title || ("ACCOUNT_SELECT_MODAL.DEFAULT_TITLE" | translate) }}</ion-title>
<ion-buttons slot="end">
<ion-button (click)="onConfirm()" [disabled]="selectedAccountsCount<1">
<ion-label>{{ confirmText || ("CONFIRM_SELECTION.EXPORT" | translate) }}</ion-label>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<ion-list lines="full">
<ion-item>
<ion-label>{{ "ACCOUNT_SELECT_MODAL.SELECTION_COUNTER" | translate:selectionCountParams }}</ion-label>
<ion-button (click)="onSelectAllClick()">{{ selectAllLabelKey | translate }}</ion-button>
</ion-item>
<ion-item *ngFor="let item of selection; let i = index" button (click)="onItemClick(i)" detail="false" [color]="item.selected ? 'light' : ''">
<ion-thumbnail class="thumb" slot="start">
<img class="thumb-img" [src]="item.account.getLogo()" />
</ion-thumbnail>
<ion-checkbox labelPlacement="start" [checked]="item.selected">
{{item.account.label}}
</ion-checkbox>
</ion-item>
</ion-list>
</ion-content>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.thumb-img {
object-fit: scale-down;
padding: 2px;
}

.thumb {
background-color: white;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Component, Input, OnInit } from '@angular/core';
import { Config, ModalController } from '@ionic/angular';
import { Account2FA } from 'src/app/models/account2FA.model';

@Component({
selector: 'app-account-select-modal',
templateUrl: './account-select-modal.component.html',
styleUrls: ['./account-select-modal.component.scss'],
})
export class AccountSelectModalComponent implements OnInit {
@Input() accounts: Account2FA[] = []
@Input() title: string = ''
@Input() confirmText: string = ''

selection: {account: Account2FA, selected: boolean}[] = []
isMD: boolean
constructor(private modalController: ModalController, config: Config) {
this.isMD = config.get('mode') !== 'ios'
}

ngOnInit() {
this.selection = this.accounts.map((account) => {
return { account, selected: true }
})
}

get selectedAccountsCount() {
return this.selection.reduce((count, item) => count + (item.selected ? 1 : 0), 0)
}

get selectAllLabelKey(): string {
const allSelected = this.selection.every((item) => item.selected)
return allSelected ? 'ACCOUNT_SELECT_MODAL.DESELECT_ALL' : 'ACCOUNT_SELECT_MODAL.SELECT_ALL'
}

get selectionCountParams() {
return {
total: this.selection.length,
selected: this.selectedAccountsCount
}
}

onSelectAllClick() {
const allSelected = this.selection.every((item) => item.selected)
this.selection.forEach((item) => item.selected = !allSelected)
}

onItemClick(index: number) {
this.selection[index].selected = !this.selection[index].selected
}

onConfirm() {
const selectedAccounts = this.selection.filter((item) => item.selected).map((item) => item.account)
this.modalController.dismiss(selectedAccounts)
}

closeModal() {
this.modalController.dismiss(null, 'cancel')
}

}
6 changes: 3 additions & 3 deletions src/app/home/home.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import { NgxScannerQrcodeModule } from 'ngx-scanner-qrcode';
import { AccountListComponent } from '../components/account-list/account-list.component';
import { AccountDetailComponent } from '../components/account-detail/account-detail.component';
import { CountdownTimerComponent } from '../components/countdown-timer/countdown-timer.component';
import { TranslateModule } from '@ngx-translate/core';

import { TranslateModule } from '@ngx-translate/core'
import { AccountSelectModalComponent } from '../components/account-select-modal/account-select-modal.component';

@NgModule({
imports: [
Expand All @@ -24,6 +24,6 @@ import { TranslateModule } from '@ngx-translate/core';
NgxScannerQrcodeModule,
TranslateModule.forChild()
],
declarations: [HomePage, AccountListComponent, AccountDetailComponent, CountdownTimerComponent]
declarations: [HomePage, AccountListComponent, AccountDetailComponent, CountdownTimerComponent, AccountSelectModalComponent]
})
export class HomePageModule {}
Loading

0 comments on commit f241006

Please sign in to comment.