From a9b777f52c7046017f6a21085b35143858705520 Mon Sep 17 00:00:00 2001
From: Dorian MARCO <dorian.marco@e-is.pro>
Date: Thu, 20 Mar 2025 10:42:52 +0100
Subject: [PATCH] fix(login) can connect with restaure sentence
 ehn(login-method) add get from clipboard fix(auth.form) open help modal

---
 package-lock.json                             |  6 ++--
 src/app/account/accounts.service.ts           | 10 +++---
 .../account/auth/address/address.form.html    | 13 +++++--
 src/app/account/auth/address/address.form.ts  | 15 +++++++-
 src/app/account/auth/auth.modal.ts            | 14 ++++++--
 .../account/auth/mnemonic/mnemonic.form.html  | 35 +++++++------------
 .../account/auth/mnemonic/mnemonic.form.scss  |  3 ++
 .../account/auth/mnemonic/mnemonic.form.ts    | 15 ++++++++
 src/app/account/auth/pubkey/pubkey.form.html  | 25 +++++++------
 src/app/account/auth/pubkey/pubkey.form.ts    | 15 +++++++-
 src/app/home/help/help.page.html              |  6 ++--
 src/app/home/help/help.page.ts                |  6 +++-
 12 files changed, 111 insertions(+), 52 deletions(-)
 create mode 100644 src/app/account/auth/mnemonic/mnemonic.form.scss

diff --git a/package-lock.json b/package-lock.json
index 0207bab..57beb6f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "cesium",
-  "version": "2.0.0-alpha45",
+  "version": "2.0.0-alpha46",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "cesium",
-      "version": "2.0.0-alpha45",
+      "version": "2.0.0-alpha46",
       "license": "AGPL-3.0",
       "dependencies": {
         "@angular/animations": "^18.2.13",
@@ -131,7 +131,7 @@
         "typescript": "~5.4.5"
       },
       "engines": {
-        "node": ">= 20.17.2",
+        "node": ">= 20.17.0",
         "npm": ">= 10.7.0",
         "yarn": ">= 1.22.19"
       },
diff --git a/src/app/account/accounts.service.ts b/src/app/account/accounts.service.ts
index f5feca4..c6f0aa8 100644
--- a/src/app/account/accounts.service.ts
+++ b/src/app/account/accounts.service.ts
@@ -277,11 +277,11 @@ export class AccountsService extends RxStartableService<AccountsState> {
       return true; // ok
     }
 
-    const hasPassword = this.settings.get('hasPassword') || false;
-    if (!hasPassword) {
-      console.error(`${this._logPrefix}No password defined. Cannot auth`);
-      return false; // KO
-    }
+    // const hasPassword = this.settings.get('hasPassword') || false;  //TODO: TO BE VALIDED
+    // if (!hasPassword) {
+    //   console.error(`${this._logPrefix}No password defined. Cannot auth`);
+    //   return false; // KO
+    // }
 
     console.debug(`${this._logPrefix}Not auth: opening unlock modal...`);
 
diff --git a/src/app/account/auth/address/address.form.html b/src/app/account/auth/address/address.form.html
index a73d288..c1ffb7b 100644
--- a/src/app/account/auth/address/address.form.html
+++ b/src/app/account/auth/address/address.form.html
@@ -9,9 +9,16 @@
     <!-- Address -->
     <ion-item>
       <ion-input formControlName="address" [label]="'LOGIN.ADDRESS_HELP' | translate" labelPlacement="floating" autocomplete="off" required>
-        <ion-button fill="clear" slot="end" [attr.aria-label]="'COMMON.BTN_SEARCH'" (click)="showWotModal($event)">
-          <ion-icon slot="icon-only" name="search" aria-hidden="true"></ion-icon>
-        </ion-button>
+        <ion-buttons slot="end">
+          <!-- Copy from clipboard -->
+          <ion-button fill="clear" (click)="pasteFromClipboard()">
+            <ion-icon slot="icon-only" name="clipboard" aria-hidden="true"></ion-icon>
+          </ion-button>
+
+          <ion-button fill="clear" [attr.aria-label]="'COMMON.BTN_SEARCH'" (click)="showWotModal($event)">
+            <ion-icon slot="icon-only" name="search" aria-hidden="true"></ion-icon>
+          </ion-button>
+        </ion-buttons>
       </ion-input>
     </ion-item>
   </ion-list>
diff --git a/src/app/account/auth/address/address.form.ts b/src/app/account/auth/address/address.form.ts
index 583e120..6123991 100644
--- a/src/app/account/auth/address/address.form.ts
+++ b/src/app/account/auth/address/address.form.ts
@@ -4,11 +4,12 @@ import { AppForm } from '@app/shared/form.class';
 import { SettingsService } from '@app/settings/settings.service';
 import { environment } from '@environments/environment';
 import { FormUtils } from '@app/shared/forms';
-import { isNil } from '@app/shared/functions';
+import { isNil, isNotNilOrBlank } from '@app/shared/functions';
 import { setTimeout } from '@rx-angular/cdk/zone-less/browser';
 import { AuthData } from '@app/account/auth/auth.model';
 import { SharedValidators } from '@app/shared/form/form-validators';
 import { APP_WOT_CONTROLLER, IWotController } from '@app/wot/wot.model';
+import { Clipboard } from '@capacitor/clipboard';
 
 @Component({
   selector: 'app-address-form',
@@ -82,6 +83,18 @@ export class AddressForm extends AppForm<AuthData> implements OnInit {
     };
   }
 
+  async pasteFromClipboard() {
+    try {
+      const { value } = await Clipboard.read();
+
+      if (isNotNilOrBlank(value)) {
+        this.form.patchValue({ address: value.trim() });
+      }
+    } catch (err) {
+      console.error('Can not read clipboard', err);
+    }
+  }
+
   // get address corresponding to form input
   get address(): string {
     const data = this.form.value;
diff --git a/src/app/account/auth/auth.modal.ts b/src/app/account/auth/auth.modal.ts
index 7b7eafd..70af2b4 100644
--- a/src/app/account/auth/auth.modal.ts
+++ b/src/app/account/auth/auth.modal.ts
@@ -10,6 +10,7 @@ import { SettingsService } from '@app/settings/settings.service';
 import { AppForm } from '@app/shared/form.class';
 import { toBoolean } from '@app/shared/functions';
 import { DerivationSelectionComponent } from '@app/account/auth/derivation-selection/derivation-selection.component';
+import { HelpPage } from '@app/home/help/help.page';
 
 export interface AuthModalOptions {
   auth?: boolean;
@@ -77,6 +78,7 @@ export class AuthModal implements OnInit, AuthModalOptions {
 
     try {
       data = data || this.form.value;
+      data.v2.mnemonic = data.v2.mnemonic.trim();
 
       // Disable the form
       this.form.disable();
@@ -152,8 +154,16 @@ export class AuthModal implements OnInit, AuthModalOptions {
     this.markForCheck();
   }
 
-  showHelpModal(anchor?: string) {
-    console.info('TODO Opening help modal to anchor: ' + anchor);
+  async showHelpModal(anchor?: string) {
+    const modal = await this.modalCtrl.create({
+      id: 'help-modal',
+      component: HelpPage,
+      componentProps: {
+        highlightedDefinition: anchor,
+      },
+      canDismiss: true,
+    });
+    await modal.present();
   }
 
   protected register() {
diff --git a/src/app/account/auth/mnemonic/mnemonic.form.html b/src/app/account/auth/mnemonic/mnemonic.form.html
index eede827..96b31fc 100644
--- a/src/app/account/auth/mnemonic/mnemonic.form.html
+++ b/src/app/account/auth/mnemonic/mnemonic.form.html
@@ -8,29 +8,19 @@
 
     <!-- Mnemonic -->
     <ion-item [class.invalid]="form.get('mnemonic').invalid && form.get('mnemonic').touched">
-      @if (showMnemonic) {
-        <ion-textarea
-          formControlName="mnemonic"
-          [label]="'LOGIN.MNEMONIC' | translate"
-          labelPlacement="floating"
-          autocomplete="off"
-          required
-        ></ion-textarea>
-      } @else {
-        <ion-textarea
-          formControlName="mnemonic"
-          type="password"
-          [label]="'LOGIN.MNEMONIC' | translate"
-          labelPlacement="floating"
-          autocomplete="off"
-          required
-        ></ion-textarea>
-      }
+      <ion-label position="floating" translate>LOGIN.MNEMONIC</ion-label>
+      <ion-textarea formControlName="mnemonic" [class.password-mode]="!showMnemonic" autocomplete="off" required></ion-textarea>
 
-      <!-- show/hide button -->
-      <ion-button slot="end" (click)="toggleShowMnemonic($event)" fill="clear" color="medium" [tabindex]="-1">
-        <ion-icon slot="icon-only" [name]="showMnemonic ? 'eye-off' : 'eye'"></ion-icon>
-      </ion-button>
+      <ion-buttons slot="end">
+        <!-- Copy from clipboard -->
+        <ion-button (click)="pasteFromClipboard()" fill="clear" color="medium" [tabindex]="-1">
+          <ion-icon slot="icon-only" name="clipboard-outline"></ion-icon>
+        </ion-button>
+        <!-- show/hide button -->
+        <ion-button (click)="toggleShowMnemonic($event)" fill="clear" color="medium" [tabindex]="-1">
+          <ion-icon slot="icon-only" [name]="showMnemonic ? 'eye-off' : 'eye'"></ion-icon>
+        </ion-button>
+      </ion-buttons>
     </ion-item>
 
     <!-- Address -->
@@ -38,5 +28,4 @@
       <ion-textarea [value]="generatedAddress" [label]="'COMMON.ADDRESS' | translate" labelPlacement="floating" [disabled]="true"></ion-textarea>
     </ion-item>
   </ion-list>
-
 </form>
diff --git a/src/app/account/auth/mnemonic/mnemonic.form.scss b/src/app/account/auth/mnemonic/mnemonic.form.scss
new file mode 100644
index 0000000..99e8c8f
--- /dev/null
+++ b/src/app/account/auth/mnemonic/mnemonic.form.scss
@@ -0,0 +1,3 @@
+.password-mode {
+  -webkit-text-security: disc;
+}
diff --git a/src/app/account/auth/mnemonic/mnemonic.form.ts b/src/app/account/auth/mnemonic/mnemonic.form.ts
index 5ef065b..25c5ebf 100644
--- a/src/app/account/auth/mnemonic/mnemonic.form.ts
+++ b/src/app/account/auth/mnemonic/mnemonic.form.ts
@@ -11,10 +11,13 @@ import { debounceTime } from 'rxjs/operators';
 import { AccountsService } from '@app/account/accounts.service';
 import { formatAddress } from '@app/shared/currencies';
 import { SharedValidators } from '@app/shared/form/form-validators';
+import { Clipboard } from '@capacitor/clipboard';
+import { isNotNilOrBlank } from '@app/shared/functions';
 
 @Component({
   selector: 'app-mnemonic-form',
   templateUrl: 'mnemonic.form.html',
+  styleUrls: ['mnemonic.form.scss'],
   animations: [slideUpDownAnimation],
   changeDetection: ChangeDetectionStrategy.OnPush,
 })
@@ -92,6 +95,18 @@ export class MnemonicForm extends AppForm<AuthData> implements OnInit {
     setTimeout(() => this.validate.emit(data));
   }
 
+  async pasteFromClipboard() {
+    try {
+      const { value } = await Clipboard.read();
+
+      if (isNotNilOrBlank(value)) {
+        this.form.patchValue({ mnemonic: value.trim() });
+      }
+    } catch (err) {
+      console.error('Can not read clipboard', err);
+    }
+  }
+
   get value(): AuthData {
     const data = this.form.value;
     return {
diff --git a/src/app/account/auth/pubkey/pubkey.form.html b/src/app/account/auth/pubkey/pubkey.form.html
index 1b5906f..f4358da 100644
--- a/src/app/account/auth/pubkey/pubkey.form.html
+++ b/src/app/account/auth/pubkey/pubkey.form.html
@@ -9,16 +9,21 @@
     <!-- Pubkey -->
     <ion-item>
       <ion-input type="text" formControlName="pubkey" [label]="'LOGIN.PUBKEY_HELP' | translate" labelPlacement="floating" autocomplete="off" required>
-        <!-- search button-->
-        <ion-button
-          fill="clear"
-          slot="end"
-          [attr.aria-label]="'COMMON.BTN_SEARCH'"
-          (click)="showWotModal($event)"
-          [disabled]="form | formGetValue: 'pubkey' | isNilOrBlank"
-        >
-          <ion-icon slot="icon-only" name="search" aria-hidden="true"></ion-icon>
-        </ion-button>
+        <ion-buttons slot="end">
+          <!-- Copy from clipboard -->
+          <ion-button fill="clear" (click)="pasteFromClipboard()">
+            <ion-icon slot="icon-only" name="clipboard" aria-hidden="true"></ion-icon>
+          </ion-button>
+          <!-- search button-->
+          <ion-button
+            fill="clear"
+            [attr.aria-label]="'COMMON.BTN_SEARCH'"
+            (click)="showWotModal($event)"
+            [disabled]="form | formGetValue: 'pubkey' | isNilOrBlank"
+          >
+            <ion-icon slot="icon-only" name="search" aria-hidden="true"></ion-icon>
+          </ion-button>
+        </ion-buttons>
       </ion-input>
     </ion-item>
   </ion-list>
diff --git a/src/app/account/auth/pubkey/pubkey.form.ts b/src/app/account/auth/pubkey/pubkey.form.ts
index 2fc60f8..c03aecd 100644
--- a/src/app/account/auth/pubkey/pubkey.form.ts
+++ b/src/app/account/auth/pubkey/pubkey.form.ts
@@ -4,11 +4,12 @@ import { AppForm } from '@app/shared/form.class';
 import { SettingsService } from '@app/settings/settings.service';
 import { environment } from '@environments/environment';
 import { FormUtils } from '@app/shared/forms';
-import { isNil } from '@app/shared/functions';
+import { isNil, isNotNilOrBlank } from '@app/shared/functions';
 import { setTimeout } from '@rx-angular/cdk/zone-less/browser';
 import { AuthData } from '@app/account/auth/auth.model';
 import { SharedValidators } from '@app/shared/form/form-validators';
 import { APP_WOT_CONTROLLER, IWotController } from '@app/wot/wot.model';
+import { Clipboard } from '@capacitor/clipboard';
 
 @Component({
   selector: 'app-pubkey-form',
@@ -92,6 +93,18 @@ export class PubkeyForm extends AppForm<AuthData> implements OnInit {
     return '';
   }
 
+  async pasteFromClipboard() {
+    try {
+      const { value } = await Clipboard.read();
+
+      if (isNotNilOrBlank(value)) {
+        this.form.patchValue({ pubkey: value.trim() });
+      }
+    } catch (err) {
+      console.error('Can not read clipboard', err);
+    }
+  }
+
   /* -- protected functions -- */
 
   async showWotModal(event: Event) {
diff --git a/src/app/home/help/help.page.html b/src/app/home/help/help.page.html
index 743f8d7..8f7bded 100644
--- a/src/app/home/help/help.page.html
+++ b/src/app/home/help/help.page.html
@@ -95,10 +95,10 @@
         </ion-row>
       </ion-grid>
     </ion-item>
-    <ion-item lines="none">
-      <ion-grid>
+    <ion-item id="login-method" lines="none">
+      <ion-grid [ngClass]="{ highlight: isLoginMethodHelp() }">
         <ion-row>
-          <ion-col size="4" size-lg="4" size-sm="12">
+          <ion-col size="4" size-lg="4" size-sm="12" [ngClass]="{ 'text-bold': isLoginMethodHelp() }">
             <ion-label translate>HELP.LOGIN.METHOD</ion-label>
           </ion-col>
           <ion-col size="8" size-lg="8" size-sm="12">
diff --git a/src/app/home/help/help.page.ts b/src/app/home/help/help.page.ts
index aefbcc7..c41ace4 100644
--- a/src/app/home/help/help.page.ts
+++ b/src/app/home/help/help.page.ts
@@ -12,7 +12,7 @@ import { isNotNilOrBlank } from '@app/shared/functions';
 
 export interface HelpPageState extends AppPageState, Settings {}
 
-export declare type HighlightedDefinition = 'GLOSSARY_DISTANCE_RULE' | 'DEMO_MODE_HELP' | 'READONLY_MODE_HELP' | 'UD' | '';
+export declare type HighlightedDefinition = 'GLOSSARY_DISTANCE_RULE' | 'DEMO_MODE_HELP' | 'READONLY_MODE_HELP' | 'UD' | 'login-method' | '';
 
 @Component({
   selector: 'app-help',
@@ -64,6 +64,10 @@ export class HelpPage extends AppPage<HelpPageState> implements OnInit {
     return this.highlightedDefinition === 'UD';
   }
 
+  isLoginMethodHelp() {
+    return this.highlightedDefinition === 'login-method';
+  }
+
   async scrollToDefinition(definitionId: string) {
     const targetElement = document.getElementById(definitionId);
     if (targetElement) {
-- 
GitLab