Skip to content

Commit 6d7efb9

Browse files
authored
Merge pull request #172 from NazarUsov/fixes
Fixes
2 parents 34a378c + 47dbe04 commit 6d7efb9

81 files changed

Lines changed: 1017 additions & 758 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

html_source/.gemini/styleguide.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Professional Guide: Angular 14 | Chrome 68 | Qt Environment
2+
3+
## 1. Environment & Runtime Constraints
4+
- **Runtime:** Qt WebEngine (Embedded Chrome 68).
5+
- **CSS Constraint:** NO `@media` queries support. Do not use them for responsive design.
6+
- **Responsiveness:** Use Flexbox/Grid with percentage widths or HostListeners to calculate dimensions in JS if necessary.
7+
- **JS Engine:** Chrome 68 (ES2018). Avoid `?.`, `??`, and `array.flat()` unless polyfilled.
8+
- **Rendering:** Be cautious with `position: fixed` and `z-index` in Qt containers; prefer `flex` layouts for stable rendering.
9+
10+
## 2. Angular 14 Professional Standards
11+
- **Strictly Typed Forms:** Use `FormControl<string>`, `FormGroup<MyInterface>`.
12+
- **Forbidden:** Never use `UntypedFormControl` or `UntypedFormGroup`.
13+
- **DI Pattern:** Use constructor for clean, modern dependency injection.
14+
- **Architecture:** Follow the LIFT principle (Locate, Identify, Flat, T-Dry).
15+
- **Change Detection:** Always use `ChangeDetectionStrategy.OnPush` to minimize CPU usage in the Qt environment.
16+
17+
## 3. RxJS & State Management
18+
- **Memory:** Strict `takeUntil(this.destroy$)` pattern in `ngOnDestroy`.
19+
- **Streams:** Use `shareReplay(1)` for multicasting data from API to multiple UI elements.
20+
- **State:** Use `BehaviorSubject` in services for lightweight state management.
21+
22+
## 4. UI & Styling (Qt-Specific)
23+
- **Layout:** Since `@media` is broken, use a "Container-first" approach.
24+
- **CSS Units:** Avoid `vh` and `vw` if the Qt window is resizable (can cause jitter); prefer `%` or `flex-grow`.
25+
- **Methodology:** BEM (Block Element Modifier).
26+
- **Scrollbars:** Use simple CSS scrollbar styling, as Qt WebEngine often has issues with default OS scrollbars.
27+
28+
## 5. Coding Behavior for Gemini
29+
- **Role:** Act as a Senior Angular Architect specialized in Embedded Systems (Qt).
30+
- **Constraint Check:** Before providing any CSS, ensure it does not contain `@media` blocks.
31+
- **Code Style:** Clean, modular, and performance-oriented.
32+
33+
## 6. Security & Navigation (Qt Specific)
34+
- **File System Access:** Prevent accidental directory listings. All internal links must point to specific `.html` files or assets.
35+
- **Protocol Handling:** Use URL interceptors to block `file://` protocol access to sensitive folders like `AppData`.
36+
- **Navigation Policy:** Implement a navigation guard to ensure that any request not matching the application's internal routes is cancelled or opened in the default system browser, not inside the Qt WebView.

html_source/AGENTS.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# AI Agent Guidelines (Zano Project)
2+
3+
This document provides architectural context, coding standards, and project-specific rules for AI agents working on the Zano GUI.
4+
5+
## 🚫 Context Exclusion Rules
6+
To minimize noise and focus on relevant code, **IGNORE** the following directories and files:
7+
- **Build/Config artifacts:** `.angular/`, `.gemini/`, `.idea/`, `.vscode/`, `node_modules/`, `dist/`.
8+
- **E2E Tests:** `e2e/` (unless explicitly asked for E2E tasks).
9+
- **External/Legacy:** `html_source/` (this contains the final build output).
10+
- **Scripts:** `index-html-transform.js`, `ngcc.config.js`, `update-build-time.js`.
11+
12+
## 🛠 Tech Stack
13+
- **Framework:** Angular 14.2.10
14+
- **Language:** TypeScript 4.8.4
15+
- **Styling:** Stylus (`.styl`), Angular Material
16+
- **State Management:** Reactive Store (RxJS-based) in `src/app/store/`
17+
- **Backend:** Qt-based backend accessed via `QWebChannel`
18+
- **Formatting:** Prettier + ESLint
19+
20+
## 🏗 Key Architectural Patterns
21+
22+
### 1. Backend Communication (`BackendService`)
23+
The application acts as a GUI for a C++/Qt core.
24+
- **Bridge:** Interaction happens through `mediator_object` exposed via `BackendService`.
25+
- **Data Integrity:** ALWAYS use `BigNumber.js` for financial values. Avoid native JS `number` for crypto values.
26+
- **Serialization:** Use `JSONBigNumber` for parsing backend responses.
27+
28+
### 2. Variables & Global State
29+
- **`VariablesService`**: Central service for current wallet state (`current_wallet`) and app settings.
30+
- **State Updates:** State is pushed from the backend and synchronized via RxJS subjects in the `Store`.
31+
32+
### 3. Template Standards
33+
- **Localization:** All UI strings must use the `| translate` pipe (`ngx-translate`).
34+
- **Custom Pipes:** Use `| intToMoney` for crypto amounts.
35+
- **Loading UI:** Use `<ng-template #skeletonTemplate>` for loading states.
36+
37+
## 📝 Coding Rules
38+
39+
### TypeScript & RxJS
40+
- **Clean Up:** Use `takeUntil(this.destroy$)` or the `async` pipe.
41+
- **Typing:** Strict typing is mandatory. Interfaces go in `src/app/api/models/`.
42+
43+
### Styling (Stylus)
44+
- Use `.styl` files.
45+
- Use utility classes (e.g., `text-ellipsis`, `border-radius-0_8-rem`).
46+
47+
## 🚀 Development Workflow
48+
- `npm run format`: Run `npx prettier --write .` before submitting changes.
49+
50+
## ⚠️ Important Considerations
51+
- **Wallet Loading:** Always verify `variablesService.current_wallet.loaded` before rendering wallet-specific data.
52+
- **Project Structure:** Focus primarily on `src/app/` for logic and `src/assets/i18n/` for translations.

html_source/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
"lodash": "^4.17.20",
4545
"ngx-pagination": "^6.0.3",
4646
"ngx-papaparse": "^5.1.0",
47-
"prettier-eslint": "^15.0.1",
4847
"qrcode": "^1.5.1",
4948
"rxjs": "~7.5.7",
5049
"tslib": "^2.4.1",

html_source/src/app/api/models/custom-asstest.model.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,3 @@ export interface EmitParams {
3131
destinations: Destinations;
3232
asset_id: string;
3333
}
34-

html_source/src/app/api/models/scale.model.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.

html_source/src/app/app.component.html

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@
33
></router-outlet>
44

55
<!-- Sync / Error / Complete States -->
6-
<section *ngIf="loadingDaemonStates.includes(variablesService.daemon_state)" aria-busy="true" aria-live="polite" class="preloader" role="status">
6+
<section
7+
*ngIf="loadingDaemonStates.includes(variablesService.daemon_state)"
8+
aria-busy="true"
9+
aria-live="polite"
10+
class="preloader"
11+
role="status"
12+
>
713
<p class="mb-2">
814
{{ loadingMessageKey | translate }}
915
</p>

html_source/src/app/pages/assign-alias/assign-alias.component.html

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<main class="page-container" aria-describedby="assign-alias-description">
1+
<main appAutofocus tabindex="0" class="page-container" aria-describedby="assign-alias-description">
22
<p class="sr-only" id="assign-alias-description">
33
{{ 'ACCESSIBILITY.ASSIGN_ALIAS.DESCRIPTIONS.DESCRIPTION1' | translate }}
44
</p>
@@ -28,8 +28,6 @@ <h1 class="ml-2" aria-live="assertive">{{ 'BREADCRUMBS.ASSIGN_ALIAS' | translate
2828
[attr.aria-describedby]="'alias-name-error1 alias-name-error2 alias-name-error3'"
2929
[attr.aria-invalid]="form.controls.name.invalid || null"
3030
[placeholder]="'ASSIGN_ALIAS.NAME.PLACEHOLDER' | translate"
31-
appAutofocus
32-
autofocus
3331
autocomplete="off"
3432
class="form__field--input"
3533
formControlName="name"
@@ -39,19 +37,19 @@ <h1 class="ml-2" aria-live="assertive">{{ 'BREADCRUMBS.ASSIGN_ALIAS' | translate
3937
</div>
4038
<ng-container *ngIf="form.controls.name | isVisibleControlError">
4139
<div class="error" [attr.aria-live]="'assertive'" id="alias-name-error1">
42-
<ng-container *ngIf="form.controls.name.hasError('pattern'); else nameMinLengthErrorTemplate">
43-
{{ 'ASSIGN_ALIAS.FORM_ERRORS.NAME_WRONG' | translate }}
40+
<ng-container *ngIf="form.controls.name.hasError('minlength'); else nameMaxLengthErrorTemplate">
41+
{{ 'ASSIGN_ALIAS.FORM_ERRORS.NAME_LENGTH' | translate }}
4442
</ng-container>
4543

46-
<ng-template #nameMinLengthErrorTemplate>
47-
<ng-container *ngIf="form.controls.name.hasError('minlength'); else nameMaxLengthErrorTemplate">
44+
<ng-template #nameMaxLengthErrorTemplate>
45+
<ng-container *ngIf="form.controls.name.hasError('maxlength'); else nameWrongErrorTemplate">
4846
{{ 'ASSIGN_ALIAS.FORM_ERRORS.NAME_LENGTH' | translate }}
4947
</ng-container>
5048
</ng-template>
5149

52-
<ng-template #nameMaxLengthErrorTemplate>
53-
<ng-container *ngIf="form.controls.name.hasError('maxlength'); else nameRequiredErrorTemplate">
54-
{{ 'ASSIGN_ALIAS.FORM_ERRORS.NAME_LENGTH' | translate }}
50+
<ng-template #nameWrongErrorTemplate>
51+
<ng-container *ngIf="form.controls.name.hasError('pattern'); else nameRequiredErrorTemplate">
52+
{{ 'ASSIGN_ALIAS.FORM_ERRORS.NAME_WRONG' | translate }}
5553
</ng-container>
5654
</ng-template>
5755

html_source/src/app/pages/auth/login/login.component.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ <h1 class="sr-only" aria-live="assertive">
5050
class="error"
5151
id="master-pass-error"
5252
>
53-
<div *ngIf="regMasterPassForm.controls.password.hasError('pattern')">
53+
<ng-container *ngIf="regMasterPassForm.controls.password.hasError('pattern')">
5454
{{ 'ERRORS.REGEXP_INVALID_PASSWORD' | translate }}
55-
</div>
55+
</ng-container>
5656
</div>
5757
</div>
5858

@@ -80,9 +80,9 @@ <h1 class="sr-only" aria-live="assertive">
8080
class="error"
8181
id="confirm-pass-error"
8282
>
83-
<div *ngIf="regMasterPassForm.errors['mismatch']">
83+
<ng-container *ngIf="regMasterPassForm.errors['mismatch']">
8484
{{ 'LOGIN.FORM_ERRORS.MISMATCH' | translate }}
85-
</div>
85+
</ng-container>
8686
</div>
8787
</div>
8888
</fieldset>

html_source/src/app/pages/create-wallet/create-wallet.component.html

Lines changed: 45 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
<main class="page-container" aria-describedby="create-wallet-description">
1+
<main tabindex="0" appAutofocus aria-describedby="create-wallet-description" class="page-container">
22
<p class="sr-only" id="create-wallet-description">
33
{{ 'ACCESSIBILITY.CREATE_WALLET.DESCRIPTIONS.DESCRIPTION1' | translate }}
44
</p>
55

66
<section class="toolbar mb-2">
77
<div class="left">
88
<app-back-button></app-back-button>
9-
<h1 class="ml-2" aria-live="assertive">{{ 'BREADCRUMBS.ADD_WALLET' | translate }}</h1>
9+
<h1 aria-live="assertive" class="ml-2">{{ 'BREADCRUMBS.ADD_WALLET' | translate }}</h1>
1010
</div>
1111
<div class="right"></div>
1212
</section>
@@ -15,115 +15,117 @@ <h1 class="ml-2" aria-live="assertive">{{ 'BREADCRUMBS.ADD_WALLET' | translate }
1515
<app-breadcrumbs [items]="breadcrumbItems" class="mb-2"></app-breadcrumbs>
1616

1717
<section class="scrolled-content">
18-
<form role="form" [formGroup]="createForm" class="form" [attr.aria-busy]="loading ? 'true' : null">
18+
<form (ngSubmit)="createWallet()" [attr.aria-busy]="loading ? 'true' : null" [formGroup]="form" class="form">
19+
<!--Name-->
1920
<fieldset class="form__field">
2021
<label for="wallet-name">{{ 'CREATE_WALLET.NAME' | translate }}</label>
2122
<input
2223
(contextmenu)="variablesService.onContextMenu($event)"
23-
[placeholder]="'PLACEHOLDERS.WALLET_NAME_PLACEHOLDER' | translate"
24-
[readonly]="createForm.controls.path.valid"
2524
[attr.aria-describedby]="'wallet-name-error'"
26-
autofocus
27-
appAutofocus
25+
[placeholder]="'PLACEHOLDERS.WALLET_NAME_PLACEHOLDER' | translate"
26+
[readonly]="form.controls.path.valid"
2827
class="form__field--input"
2928
formControlName="name"
3029
id="wallet-name"
31-
maxlength="{{ variablesService.maxWalletNameLength }}"
3230
type="text"
3331
/>
3432
<div
35-
*ngIf="createForm.controls.name.invalid && (createForm.controls.name.dirty || createForm.controls.name.touched)"
33+
*ngIf="form.controls.name | isVisibleControlError"
34+
[attr.aria-live]="'assertive'"
3635
class="error"
3736
id="wallet-name-error"
38-
[attr.aria-live]="'assertive'"
3937
>
40-
<div *ngIf="createForm.controls.name.hasError('duplicate')">
38+
<ng-container *ngIf="form.controls.name.hasError('duplicate'); else nameRequiredErrorTemplate">
4139
{{ 'CREATE_WALLET.FORM_ERRORS.NAME_DUPLICATE' | translate }}
42-
</div>
43-
<div *ngIf="createForm.controls.name.hasError('required')">
44-
{{ 'CREATE_WALLET.FORM_ERRORS.NAME_REQUIRED' | translate }}
45-
</div>
46-
</div>
47-
<div *ngIf="createForm.controls.name.value.length > variablesService.maxWalletNameLength" class="error">
48-
{{ 'CREATE_WALLET.FORM_ERRORS.MAX_LENGTH' | translate }}
40+
</ng-container>
41+
42+
<ng-template #nameRequiredErrorTemplate>
43+
<ng-container *ngIf="form.controls.name.hasError('required'); else nameMaxLengthErrorTemplate">
44+
{{ 'CREATE_WALLET.FORM_ERRORS.NAME_REQUIRED' | translate }}
45+
</ng-container>
46+
</ng-template>
47+
48+
<ng-template #nameMaxLengthErrorTemplate>
49+
<ng-container *ngIf="form.controls.name.hasError('maxlength')">
50+
{{ 'CREATE_WALLET.FORM_ERRORS.MAX_LENGTH' | translate }}
51+
</ng-container>
52+
</ng-template>
4953
</div>
5054
</fieldset>
5155

56+
<!--Password-->
5257
<fieldset class="form__field">
5358
<label for="wallet-password">{{ 'CREATE_WALLET.PASS' | translate }}</label>
5459
<input
5560
(contextmenu)="variablesService.onContextMenuPasteSelect($event)"
56-
[readonly]="createForm.controls.path.valid"
5761
[attr.aria-describedby]="'wallet-password-error'"
62+
[readonly]="form.controls.path.valid"
5863
class="form__field--input"
5964
formControlName="password"
6065
id="wallet-password"
6166
placeholder="{{ 'PLACEHOLDERS.PLACEHOLDER_NEW' | translate }}"
6267
type="password"
6368
/>
6469
<div
65-
*ngIf="createForm.controls.password.dirty && createForm.controls.password.invalid"
70+
*ngIf="form.controls.password | isVisibleControlError"
71+
[attr.aria-live]="'assertive'"
6672
class="error"
6773
id="wallet-password-error"
68-
[attr.aria-live]="'assertive'"
6974
>
70-
<div *ngIf="createForm.controls.password.hasError('pattern')">
75+
<ng-container *ngIf="form.controls.password.hasError('pattern')">
7176
{{ 'ERRORS.REGEXP_INVALID_PASSWORD' | translate }}
72-
</div>
77+
</ng-container>
7378
</div>
7479
</fieldset>
7580

81+
<!--Confirm-->
7682
<fieldset class="form__field">
7783
<label for="confirm-wallet-password">{{ 'CREATE_WALLET.CONFIRM' | translate }}</label>
7884
<input
7985
(contextmenu)="variablesService.onContextMenuPasteSelect($event)"
80-
[class.invalid]="createForm.hasError('mismatch') && createForm.controls.confirm.value.length > 0"
81-
[readonly]="createForm.controls.path.valid"
8286
[attr.aria-describedby]="'confirm-wallet-password-error'"
87+
[readonly]="form.controls.path.valid"
8388
class="form__field--input"
8489
formControlName="confirm"
8590
id="confirm-wallet-password"
8691
placeholder="{{ 'PLACEHOLDERS.PLACEHOLDER_CONFIRM' | translate }}"
8792
type="password"
8893
/>
8994
<div
90-
*ngIf="
91-
createForm.controls.confirm.dirty &&
92-
createForm.hasError('mismatch') &&
93-
createForm.controls.confirm.value.length > 0
94-
"
95-
id="confirm-wallet-password-error"
95+
*ngIf="form.controls.confirm | isVisibleControlError"
9696
[attr.aria-live]="'assertive'"
9797
class="error"
98+
id="confirm-wallet-password-error"
9899
>
99-
{{ 'CREATE_WALLET.FORM_ERRORS.CONFIRM_NOT_MATCH' | translate }}
100+
<ng-container *ngIf="form.controls.confirm.hasError('mismatch')">
101+
{{ 'CREATE_WALLET.FORM_ERRORS.CONFIRM_NOT_MATCH' | translate }}
102+
</ng-container>
100103
</div>
101104
</fieldset>
102105

103-
<button *ngIf="createForm.controls.path.valid" class="outline big w-100 mb-2" disabled type="button">
106+
<button *ngIf="form.controls.path.valid" class="outline big w-100 mb-2" disabled type="button">
104107
<mat-icon class="mr-1" svgIcon="zano-check-circle"></mat-icon>
105108
{{ savedWalletName }}
106109
</button>
107110

108111
<button
109-
(click)="selectWalletLocation()"
110-
*ngIf="createForm.controls.path.invalid"
111-
[disabled]="createForm.controls.name.invalid || createForm.controls.password.invalid || createForm.hasError('mismatch')"
112+
*ngIf="form.controls.path.invalid"
113+
(click)="selectLocation()"
114+
[disabled]="form.controls.name.invalid || form.controls.password.invalid || form.controls.confirm.invalid"
112115
class="outline big w-100 mb-2"
113116
type="button"
114117
>
115118
{{ 'CREATE_WALLET.BUTTON_SELECT' | translate }}
116119
</button>
117120

118-
<button (click)="createWallet()" [disabled]="createForm.invalid" class="primary big w-100" type="button">
119-
{{ 'CREATE_WALLET.BUTTON_CREATE' | translate }}
120-
<span *ngIf="loading" [ngTemplateOutlet]="loaderTemp" class="ml-1"></span>
121+
<button [disabled]="form.invalid || loading" class="primary big w-100" type="submit">
122+
<ng-container *ngIf="!loading">
123+
{{ 'CREATE_WALLET.BUTTON_CREATE' | translate }}
124+
</ng-container>
125+
126+
<zano-loader *ngIf="loading"></zano-loader>
121127
</button>
122128
</form>
123129
</section>
124130
</div>
125131
</main>
126-
127-
<ng-template #loaderTemp>
128-
<zano-loader></zano-loader>
129-
</ng-template>

0 commit comments

Comments
 (0)