From b251d424ed653e506ccbc7c23ece1a13172850f9 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Wed, 4 Oct 2023 08:04:25 +0800 Subject: [PATCH 01/28] feat(action.page): match new UI design --- .../home/details/actions/actions.page.html | 19 ++----- .../home/details/actions/actions.page.scss | 52 ++++++++++++++++++- 2 files changed, 55 insertions(+), 16 deletions(-) diff --git a/src/app/features/home/details/actions/actions.page.html b/src/app/features/home/details/actions/actions.page.html index 4ae594f09..3e6f9dfff 100644 --- a/src/app/features/home/details/actions/actions.page.html +++ b/src/app/features/home/details/actions/actions.page.html @@ -7,24 +7,13 @@ -
-
- {{ action.title_text }} -
-
- - x - {{ action.action_cost_number }} -
+
+
{{ action.title_text }}
+
{{ action.description_text }}
+
{{ action.action_cost_number }} NUM
- - {{ action.description_text }} - diff --git a/src/app/features/home/details/actions/actions.page.scss b/src/app/features/home/details/actions/actions.page.scss index de89df980..24f1cb43e 100644 --- a/src/app/features/home/details/actions/actions.page.scss +++ b/src/app/features/home/details/actions/actions.page.scss @@ -1,6 +1,12 @@ mat-toolbar { span { padding-right: 40px; + font-style: normal; + font-weight: 500; + font-size: 16px; + line-height: 21px; + text-align: center; + color: white; } } @@ -11,7 +17,51 @@ mat-toolbar { } ion-card { - margin: 20px 10px; + border-radius: 8px; + margin: 24px 16px; + } + + ion-card-header { + display: flex; + justify-content: space-between; + + .header-text { + flex: 1; + margin-right: 8px; + + .header-title { + color: white; + font-size: 16px; + font-style: normal; + font-weight: 500; + } + + .header-subtitle { + margin-top: 4px; + margin-bottom: 16px; + color: #9e9e9e; + font-size: 14px; + font-style: normal; + font-weight: 500; + } + } + + .header-price { + max-width: 120px; + color: white; + font-size: 16px; + font-style: normal; + font-weight: 500; + } + } + + ion-card-subtitle { + color: white; + font-size: 16px; + } + + ion-img { + aspect-ratio: 2/1; } ion-icon.numbers-token { From c61da6659b641db039332a97acd11b58803159f9 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Wed, 4 Oct 2023 08:05:40 +0800 Subject: [PATCH 02/28] feat(order-details-dialog): match new UI design --- .../order-detail-dialog.component.html | 81 +++++++++++-------- .../order-detail-dialog.component.scss | 42 ++++++++++ .../order-detail-dialog.component.ts | 2 +- src/global.scss | 7 ++ 4 files changed, 96 insertions(+), 36 deletions(-) diff --git a/src/app/shared/order-detail-dialog/order-detail-dialog.component.html b/src/app/shared/order-detail-dialog/order-detail-dialog.component.html index cce68d4f0..a96b0629e 100644 --- a/src/app/shared/order-detail-dialog/order-detail-dialog.component.html +++ b/src/app/shared/order-detail-dialog/order-detail-dialog.component.html @@ -3,34 +3,31 @@ *ngrxLet=" asset_wallet_mainnet_num_balance$ as asset_wallet_mainnet_num_balance " + class="card-container" > -

{{ t('payment.confirmPayment') }}

- - +

{{ t('payment.confirmPayment') }}

+ + + {{ t('payment.price') }} -
- - {{ orderStatus.price | number: '1.4-4' }} NUM - -
- - + + {{ orderStatus.price | number: '1.4-4' }} NUM + + + {{ t('payment.estimatedFee') }} - - - {{ orderStatus.fee | number: '1.4-4' }} NUM - - - - + + {{ orderStatus.fee | number: '1.4-4' }} NUM + + + {{ t('payment.totalCost') }} - - - {{ orderStatus.total_cost | number: '1.4-4' }} NUM - - + + {{ orderStatus.total_cost | number: '1.4-4' }} NUM + + + + {{ @@ -38,16 +35,30 @@

{{ t('payment.confirmPayment') }}

}}
- - - - + +
+ + + + {{ t('cancel') }} + + + + + {{ t('ok') }} + + + +
diff --git a/src/app/shared/order-detail-dialog/order-detail-dialog.component.scss b/src/app/shared/order-detail-dialog/order-detail-dialog.component.scss index e69de29bb..627482fcd 100644 --- a/src/app/shared/order-detail-dialog/order-detail-dialog.component.scss +++ b/src/app/shared/order-detail-dialog/order-detail-dialog.component.scss @@ -0,0 +1,42 @@ +.card-container { + h1 { + margin: 16px auto 24px; + color: white; + text-align: center; + } + + ion-list { + background-color: #212121; + + ion-item { + --border-color: #333; + --background: #212121; + --padding-start: 0; + --inner-padding-end: 0px; + } + } + + .card-action-buttons { + margin: 8px auto; + + ion-col { + padding: 0; + } + + ion-button[fill='outline'] { + margin-right: 8px; + + --color: white; + --border-color: #6f6f6f; + --border-width: 1px; + } + + ion-button { + --box-shadow: none; + } + } +} + +.no-right-margin { + margin-right: 0; +} diff --git a/src/app/shared/order-detail-dialog/order-detail-dialog.component.ts b/src/app/shared/order-detail-dialog/order-detail-dialog.component.ts index 9e0f06a2b..b604961e6 100644 --- a/src/app/shared/order-detail-dialog/order-detail-dialog.component.ts +++ b/src/app/shared/order-detail-dialog/order-detail-dialog.component.ts @@ -1,5 +1,5 @@ import { Component, Inject } from '@angular/core'; -import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { NetworkAppOrder } from '../dia-backend/store/dia-backend-store.service'; import { DiaBackendWalletService } from '../dia-backend/wallet/dia-backend-wallet.service'; diff --git a/src/global.scss b/src/global.scss index ba53ebfe0..ac544d137 100644 --- a/src/global.scss +++ b/src/global.scss @@ -141,6 +141,13 @@ body.dark .onboarding-pop-up-dialog mat-dialog-container { // max-height: 438px; } +body.dark .order-detail-dialog mat-dialog-container { + background-color: #212121; + border-radius: 8px; + max-width: 420px; + margin: auto; +} + body.dark .mat-card { background-color: var(--ion-color-light-shade); } From 21f0429d333e7588f8b0798e43b45a82c76a36d1 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Wed, 4 Oct 2023 08:09:25 +0800 Subject: [PATCH 03/28] feat: add action-details page Previous UI show modal with form to perform newtork actions. New UI will show form in a full screen page instead. Most of the logic from action.page.ts was copied over to action-details.page.ts. --- .../action-details-routing.module.ts | 17 + .../action-details/action-details.module.ts | 19 + .../action-details/action-details.page.html | 49 +++ .../action-details/action-details.page.scss | 78 ++++ .../action-details.page.spec.ts | 26 ++ .../action-details/action-details.page.ts | 407 ++++++++++++++++++ .../details/actions/actions-routing.module.ts | 7 + .../home/details/actions/actions.page.html | 2 +- .../home/details/actions/actions.page.ts | 9 +- 9 files changed, 612 insertions(+), 2 deletions(-) create mode 100644 src/app/features/home/details/actions/action-details/action-details-routing.module.ts create mode 100644 src/app/features/home/details/actions/action-details/action-details.module.ts create mode 100644 src/app/features/home/details/actions/action-details/action-details.page.html create mode 100644 src/app/features/home/details/actions/action-details/action-details.page.scss create mode 100644 src/app/features/home/details/actions/action-details/action-details.page.spec.ts create mode 100644 src/app/features/home/details/actions/action-details/action-details.page.ts diff --git a/src/app/features/home/details/actions/action-details/action-details-routing.module.ts b/src/app/features/home/details/actions/action-details/action-details-routing.module.ts new file mode 100644 index 000000000..46c04c9c1 --- /dev/null +++ b/src/app/features/home/details/actions/action-details/action-details-routing.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; + +import { ActionDetailsPage } from './action-details.page'; + +const routes: Routes = [ + { + path: '', + component: ActionDetailsPage, + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class ActionDetailsPageRoutingModule {} diff --git a/src/app/features/home/details/actions/action-details/action-details.module.ts b/src/app/features/home/details/actions/action-details/action-details.module.ts new file mode 100644 index 000000000..b87bd2226 --- /dev/null +++ b/src/app/features/home/details/actions/action-details/action-details.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; + +import { ActionDetailsPageRoutingModule } from './action-details-routing.module'; + +import { FormlyModule } from '@ngx-formly/core'; +import { FormlyMaterialModule } from '@ngx-formly/material'; +import { SharedModule } from '../../../../../shared/shared.module'; +import { ActionDetailsPage } from './action-details.page'; + +@NgModule({ + imports: [ + SharedModule, + ActionDetailsPageRoutingModule, + FormlyModule, + FormlyMaterialModule, + ], + declarations: [ActionDetailsPage], +}) +export class ActionDetailsPageModule {} diff --git a/src/app/features/home/details/actions/action-details/action-details.page.html b/src/app/features/home/details/actions/action-details/action-details.page.html new file mode 100644 index 000000000..a1b9365a2 --- /dev/null +++ b/src/app/features/home/details/actions/action-details/action-details.page.html @@ -0,0 +1,49 @@ + + + {{ title$ | async | transloco }} + + + + +

+ {{ description$ | async }} +

+ +
+ + + + +
+
+
+ +
+ +
+
+ + +
+
Price (NUM):
+
{{ price$ | async }} NUM
+
+ + + {{ title$ | async | uppercase }} + +
+
+ + + + diff --git a/src/app/features/home/details/actions/action-details/action-details.page.scss b/src/app/features/home/details/actions/action-details/action-details.page.scss new file mode 100644 index 000000000..b54869ba5 --- /dev/null +++ b/src/app/features/home/details/actions/action-details/action-details.page.scss @@ -0,0 +1,78 @@ +mat-toolbar { + span { + padding-right: 40px; + font-style: normal; + font-weight: 500; + font-size: 16px; + line-height: 21px; + text-align: center; + color: white; + } +} + +ion-content { + --padding-start: 16px; + --padding-end: 16px; + + .description { + margin: 24px 24px 48px; + color: #fff; + text-align: center; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: normal; + opacity: 0.75; + } + + .image { + margin: 0 auto 56px; + aspect-ratio: 179 / 216; + border-radius: 16px; + overflow: hidden; + border-radius: 16px; + height: 25vh; + + ion-img { + aspect-ratio: 179 / 216; + object-fit: cover; + object-position: center; + height: 100%; + } + + img-placeholder { + background-color: #212121; + } + } +} + +ion-footer { + display: flex; + padding: 16px; + flex-direction: row; + justify-content: space-between; + align-items: center; + + .price-in-num { + font-size: 14px; + font-style: normal; + font-weight: 500; + line-height: 100%; + opacity: 0.5; + } + + .price-number { + color: #fff; + font-size: 20px; + font-style: normal; + font-weight: 700; + } +} + +ion-spinner { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + scale: 1.5; +} diff --git a/src/app/features/home/details/actions/action-details/action-details.page.spec.ts b/src/app/features/home/details/actions/action-details/action-details.page.spec.ts new file mode 100644 index 000000000..ef3d28a65 --- /dev/null +++ b/src/app/features/home/details/actions/action-details/action-details.page.spec.ts @@ -0,0 +1,26 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { SharedTestingModule } from '../../../../../shared/shared-testing.module'; +import { ActionDetailsPage } from './action-details.page'; + +describe('ActionDetailsPage', () => { + let component: ActionDetailsPage; + let fixture: ComponentFixture; + + beforeEach( + waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [ActionDetailsPage], + imports: [SharedTestingModule], + }).compileComponents(); + + fixture = TestBed.createComponent(ActionDetailsPage); + component = fixture.componentInstance; + fixture.detectChanges(); + }) + ); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/home/details/actions/action-details/action-details.page.ts b/src/app/features/home/details/actions/action-details/action-details.page.ts new file mode 100644 index 000000000..a2f5fcf78 --- /dev/null +++ b/src/app/features/home/details/actions/action-details/action-details.page.ts @@ -0,0 +1,407 @@ +import { Component } from '@angular/core'; +import { UntypedFormGroup } from '@angular/forms'; +import { MatDialog } from '@angular/material/dialog'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Browser } from '@capacitor/browser'; +import { NavController } from '@ionic/angular'; +import { TranslocoService } from '@ngneat/transloco'; +import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; +import { FormlyFieldConfig } from '@ngx-formly/core'; +import { ReplaySubject, combineLatest, forkJoin, iif, of } from 'rxjs'; +import { + catchError, + concatMap, + first, + map, + switchMap, + take, + tap, +} from 'rxjs/operators'; +import { + Action, + ActionsService, + Param, +} from '../../../../../shared/actions/service/actions.service'; +import { OrderHistoryService } from '../../../../../shared/actions/service/order-history.service'; +import { BlockingActionService } from '../../../../../shared/blocking-action/blocking-action.service'; +import { DiaBackendAssetRepository } from '../../../../../shared/dia-backend/asset/dia-backend-asset-repository.service'; +import { DiaBackendAuthService } from '../../../../../shared/dia-backend/auth/dia-backend-auth.service'; +import { DiaBackendSeriesRepository } from '../../../../../shared/dia-backend/series/dia-backend-series-repository.service'; +import { + DiaBackendStoreService, + NetworkAppOrder, +} from '../../../../../shared/dia-backend/store/dia-backend-store.service'; +import { DiaBackendWalletService } from '../../../../../shared/dia-backend/wallet/dia-backend-wallet.service'; +import { ErrorService } from '../../../../../shared/error/error.service'; +import { OrderDetailDialogComponent } from '../../../../../shared/order-detail-dialog/order-detail-dialog.component'; +import { ProofRepository } from '../../../../../shared/repositories/proof/proof-repository.service'; +import { + VOID$, + isNonNullable, +} from '../../../../../utils/rx-operators/rx-operators'; +import { InformationSessionService } from '../../information/session/information-session.service'; + +@UntilDestroy() +@Component({ + selector: 'app-action-details', + templateUrl: './action-details.page.html', + styleUrls: ['./action-details.page.scss'], +}) +export class ActionDetailsPage { + readonly id$ = this.route.paramMap.pipe( + map(params => params.get('id')), + isNonNullable() + ); + + readonly networkAction$ = new ReplaySubject(1); + + readonly newtorkActionParams$ = this.networkAction$.pipe( + map(action => action.params_list_custom_param1 ?? []), + switchMap(params => this.actionsService.getParams$(params)) + ); + + readonly title$ = this.networkAction$.pipe(map(action => action.title_text)); + + readonly description$ = this.networkAction$.pipe( + map(action => action.description_text) + ); + + readonly thumbnail$ = this.id$.pipe( + switchMap(id => this.diaBackendAssetRepository.fetchById$(id)), + map(response => response.asset_file_thumbnail) + ); + + readonly form$ = this.newtorkActionParams$.pipe( + map(params => ({ + form: new UntypedFormGroup({}), + fields: this.createFormFields(params), + model: this.createFormModel(params), + })) + ); + + readonly price$ = this.networkAction$.pipe( + map(action => action.action_cost_number) + ); + + constructor( + private readonly route: ActivatedRoute, + private readonly router: Router, + private readonly navController: NavController, + private readonly actionsService: ActionsService, + private readonly diaBackendAssetRepository: DiaBackendAssetRepository, + private readonly authService: DiaBackendAuthService, + private readonly dialog: MatDialog, + private readonly storeService: DiaBackendStoreService, + private readonly errorService: ErrorService, + private readonly translocoService: TranslocoService, + private readonly blockingActionService: BlockingActionService, + private readonly diaBackendStoreService: DiaBackendStoreService, + private readonly diaBackendSeriesRepository: DiaBackendSeriesRepository, + private readonly diaBackendWalletService: DiaBackendWalletService, + private readonly informationSessionService: InformationSessionService, + private readonly proofRepository: ProofRepository, + private readonly orderHistoryService: OrderHistoryService, + private readonly snackBar: MatSnackBar + ) { + this.getActionFromRouterState(); + } + + private getActionFromRouterState() { + const routerState = this.router.getCurrentNavigation()?.extras.state; + + if (routerState) { + this.networkAction$.next(routerState as Action); + } else { + this.navController.back(); + } + } + + // eslint-disable-next-line class-methods-use-this + private createFormModel(params: Param[]) { + const formModel: any = {}; + + for (const param of params) + formModel[param.name_text] = param.default_values_list_text[0] || ''; + + return formModel; + } + + // eslint-disable-next-line class-methods-use-this + private createFormFields(params: Param[]) { + const formFields: FormlyFieldConfig[] = []; + + for (const param of params) { + const isOptional = param.optional_boolean ?? false; + + if (param.type_text === 'dropdown') + formFields.push({ + key: param.name_text, + type: 'select', + templateOptions: { + options: param.default_values_list_text.map(value => ({ + label: value, + value: value, + })), + placeholder: param.placeholder_text, + disabled: !param.user_input_boolean, + required: !isOptional, + appearance: 'outline', + }, + }); + else if (param.type_text === 'number') + formFields.push({ + key: param.name_text, + type: 'input', + templateOptions: { + type: 'number', + label: param.display_text_text, + placeholder: param.placeholder_text, + disabled: !param.user_input_boolean, + max: param.max_number, + min: param.min_number, + required: !isOptional, + appearance: 'outline', + }, + }); + else + formFields.push({ + key: param.name_text, + type: 'input', + templateOptions: { + type: 'text', + label: param.display_text_text, + placeholder: param.placeholder_text, + disabled: !param.user_input_boolean, + required: !isOptional, + appearance: 'outline', + }, + }); + } + + return formFields; + } + + canPerfomrAction$(action: Action) { + if (action.title_text === 'List in CaptureClub') { + /* + Workaround: + Currently there isn't a simple way to check whether an asset is listed in + CaptureClub or not. So I first query List all Products API with + associated_id parameter set to the assets cid. And then use list series + API and check through all nested collections. See discussion here + https://app.asana.com/0/0/1201558520076805/1201995911008176/f + */ + return this.id$.pipe( + concatMap(cid => + forkJoin([ + this.diaBackendStoreService.listAllProducts$({ + associated_id: cid, + service_name: 'CaptureClub', + }), + of(cid), + ]) + ), + concatMap(([response, cid]) => { + if (response.count > 0) { + throw new Error( + this.translocoService.translate('message.hasListedInCaptureApp') + ); + } + return of(cid); + }), + concatMap(async cid => { + let currentOffset = 0; + const limit = 100; + while (true) { + const response = await this.diaBackendSeriesRepository + .fetchAll$({ offset: currentOffset, limit }) + .toPromise(); + const listedAsSeries = response.results.some(serie => + serie.collections.some(collection => + collection.assets.some(asset => asset.cid === cid) + ) + ); + if (listedAsSeries) { + throw new Error( + this.translocoService.translate('message.hasListedInCaptureApp') + ); + } + if (response.next == null) { + break; + } + currentOffset += response.results.length; + } + return VOID$; + }), + take(1) + ); + } + return VOID$; + } + + async performAction(data: any) { + const createOrderInput$ = combineLatest([ + this.networkAction$, + this.authService.token$, + this.id$, + ]).pipe( + first(), + map(([action, token, id]) => { + return { + networkApp: action.network_app_id_text, + actionArgs: { ...data, token, cid: id }, + }; + }) + ); + + this.networkAction$ + .pipe( + first(), + concatMap(action => { + return this.blockingActionService + .run$(this.canPerfomrAction$(action)) + .pipe( + catchError((err: unknown) => this.errorService.toastError$(err)), + concatMap(() => createOrderInput$), + concatMap(createOrderInput => + this.blockingActionService.run$( + forkJoin([ + this.createOrder$( + createOrderInput.networkApp, + createOrderInput.actionArgs + ), + // To display "Insufficient NUM" in order confirmation dialog, + // we need to sync asset wallet balance if the action cost NUM. + iif( + () => action.action_cost_number > 0, + this.diaBackendWalletService.syncAssetWalletBalance$(), + VOID$ + ), + ]) + ) + ), + concatMap(([orderStatus, _]) => + this.openOrderDialog$(orderStatus) + ), + concatMap(orderId => + this.blockingActionService.run$(this.confirmOrder$(orderId)) + ), + tap(networkAppOrder => { + /* + Workaround: + Create a order history record only if the total cost is > 0 to prevent race + condition between app creating the order history record v.s. bubble workflow + checking whether a record already exists and if not create a new one, + especially for network actions that don't require any cost (and hence backend + calls the webhook immediately). + See https://dt42-numbers.slack.com/archives/C0323488MEJ/p1648006014291339 + */ + if (Number(networkAppOrder.total_cost) !== 0) { + this.createOrderHistory$(networkAppOrder).subscribe(); + } + }), + tap(() => { + this.snackBar.open( + this.translocoService.translate('message.sentSuccessfully') + ); + this.navController.back(); + }), + tap(networkAppOrder => { + if (action.ext_action_destination_text) { + this.redirectToExternalUrl( + action.ext_action_destination_text, + networkAppOrder.id + ); + } + }), + tap(() => { + if (action.hide_capture_after_execution_boolean ?? false) + this.removeCapture(); + }), + untilDestroyed(this) + ); + }) + ) + .subscribe(); + } + + createOrder$(appName: string, actionArgs: any) { + return this.storeService.createNetworkAppOrder(appName, actionArgs).pipe( + catchError((err: unknown) => + this.errorService.toastDiaBackendError$(err) + ), + isNonNullable() + ); + } + + confirmOrder$(id: string) { + return this.storeService.confirmNetworkAppOrder(id).pipe( + catchError((err: unknown) => + this.errorService.toastDiaBackendError$(err) + ), + isNonNullable() + ); + } + + createOrderHistory$(networkAppOrder: NetworkAppOrder) { + return this.id$.pipe( + first(), + isNonNullable(), + concatMap(cid => + this.orderHistoryService.createOrderHistory$(networkAppOrder, cid) + ), + catchError((err: unknown) => { + return this.errorService.toastError$(err); + }) + ); + } + + redirectToExternalUrl(url: string, orderId: string) { + this.id$ + .pipe( + first(), + isNonNullable(), + tap(cid => + Browser.open({ + url: `${url}?cid=${cid}&order_id=${orderId}`, + toolbarColor: '#564dfc', + }) + ), + catchError((err: unknown) => { + return this.errorService.toastError$(err); + }), + untilDestroyed(this) + ) + .subscribe(); + } + + removeCapture() { + if (this.informationSessionService.activatedDetailedCapture) { + this.informationSessionService.activatedDetailedCapture.proof$.subscribe( + proof => { + if (proof) { + this.proofRepository.remove(proof); + this.router.navigate(['/home']); + } + } + ); + } + } + + openOrderDialog$(orderStatus: NetworkAppOrder) { + const dialogRef = this.dialog.open( + OrderDetailDialogComponent, + { + disableClose: true, + data: orderStatus, + width: '100%', + panelClass: 'order-detail-dialog', + } + ); + return dialogRef.afterClosed().pipe( + isNonNullable(), + concatMap((orderId: string) => of(orderId)) + ); + } +} diff --git a/src/app/features/home/details/actions/actions-routing.module.ts b/src/app/features/home/details/actions/actions-routing.module.ts index 9994595c2..0586d29f3 100644 --- a/src/app/features/home/details/actions/actions-routing.module.ts +++ b/src/app/features/home/details/actions/actions-routing.module.ts @@ -7,6 +7,13 @@ const routes: Routes = [ path: '', component: ActionsPage, }, + { + path: 'action-details', + loadChildren: () => + import('./action-details/action-details.module').then( + m => m.ActionDetailsPageModule + ), + }, ]; @NgModule({ diff --git a/src/app/features/home/details/actions/actions.page.html b/src/app/features/home/details/actions/actions.page.html index 3e6f9dfff..01e97adc1 100644 --- a/src/app/features/home/details/actions/actions.page.html +++ b/src/app/features/home/details/actions/actions.page.html @@ -5,7 +5,7 @@
- +
{{ action.title_text }}
diff --git a/src/app/features/home/details/actions/actions.page.ts b/src/app/features/home/details/actions/actions.page.ts index 15b26b460..1bb3f36be 100644 --- a/src/app/features/home/details/actions/actions.page.ts +++ b/src/app/features/home/details/actions/actions.page.ts @@ -25,8 +25,8 @@ import { ErrorService } from '../../../../shared/error/error.service'; import { OrderDetailDialogComponent } from '../../../../shared/order-detail-dialog/order-detail-dialog.component'; import { ProofRepository } from '../../../../shared/repositories/proof/proof-repository.service'; import { - isNonNullable, VOID$, + isNonNullable, } from '../../../../utils/rx-operators/rx-operators'; import { InformationSessionService } from '../information/session/information-session.service'; @@ -232,6 +232,13 @@ export class ActionsPage { } } + performAction(action: Action) { + this.router.navigate(['action-details'], { + relativeTo: this.route, + state: action, + }); + } + doAction(action: Action) { this.blockingActionService .run$(this.canPerformAction$(action)) From 6600cc03dfbdc7cb28a776d9680388edc5ae0c45 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Mon, 11 Sep 2023 15:03:55 +0800 Subject: [PATCH 04/28] chore: refactor `syncProfile` to `syncUser` Since `syncProfile` currently retrieves information from auth/users/me/, it would be more sensible to rename it as `syncUser`. In the future, we plan to introduce a new method called `syncProfile` which will retrieve information from auth/users/profile/. --- .../home/edit-profile/edit-profile.page.ts | 20 ++++++++++++++++++- .../features/invitation/invitation.page.ts | 3 +-- src/app/features/profile/profile.page.ts | 2 +- src/app/features/settings/settings.page.ts | 2 +- .../auth/dia-backend-auth.service.ts | 4 ++-- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/app/features/home/edit-profile/edit-profile.page.ts b/src/app/features/home/edit-profile/edit-profile.page.ts index a05b62786..32eac6ad5 100644 --- a/src/app/features/home/edit-profile/edit-profile.page.ts +++ b/src/app/features/home/edit-profile/edit-profile.page.ts @@ -173,7 +173,7 @@ export class EditProfilePage { ) ) .pipe( - switchMap(() => this.diaBackendAuthService.syncProfile$()), + switchMap(() => this.diaBackendAuthService.syncUser$()), untilDestroyed(this) ); forkJoin([updateUserNameAction$, updateProfileAction$]) @@ -193,6 +193,24 @@ export class EditProfilePage { return this.errorService.toastError$(err); } + private updateProfile() { + const updateProfileAction$ = this.diaBackendAuthService + .updateProfile$({ + description: this.model.description, + profilePicture: this.model.profilePicture, + profileBackground: this.model.profileBackground, + }) + .pipe(catchError((err: unknown) => this.handleUpdateProfileError(err))); + + this.blockingActionService + .run$(updateProfileAction$) + .pipe( + switchMap(() => this.diaBackendAuthService.syncUser$()), + untilDestroyed(this) + ) + .subscribe(); + } + private handleUpdateProfileError(err: unknown): any { return this.errorService.toastError$(err); } diff --git a/src/app/features/invitation/invitation.page.ts b/src/app/features/invitation/invitation.page.ts index f35f2509f..0eb033b2a 100644 --- a/src/app/features/invitation/invitation.page.ts +++ b/src/app/features/invitation/invitation.page.ts @@ -21,8 +21,7 @@ export class InvitationPage implements OnInit { async refetchReferralCode() { const referralCode = await this.diaBackendAuthService.getReferralCode(); - if (!referralCode) - await this.diaBackendAuthService.syncProfile$().toPromise(); + if (!referralCode) await this.diaBackendAuthService.syncUser$().toPromise(); } async shareReferralCode() { diff --git a/src/app/features/profile/profile.page.ts b/src/app/features/profile/profile.page.ts index 18318d0da..72c60057f 100644 --- a/src/app/features/profile/profile.page.ts +++ b/src/app/features/profile/profile.page.ts @@ -41,7 +41,7 @@ export class ProfilePage { ) {} ionViewWillEnter() { - forkJoin([this.diaBackendAuthService.syncProfile$()]) + forkJoin([this.diaBackendAuthService.syncUser$()]) .pipe(untilDestroyed(this)) .subscribe(); } diff --git a/src/app/features/settings/settings.page.ts b/src/app/features/settings/settings.page.ts index 4c3072f49..f0281e513 100644 --- a/src/app/features/settings/settings.page.ts +++ b/src/app/features/settings/settings.page.ts @@ -99,7 +99,7 @@ export class SettingsPage { ) {} ionViewWillEnter() { - forkJoin([this.diaBackendAuthService.syncProfile$()]) + forkJoin([this.diaBackendAuthService.syncUser$()]) .pipe(untilDestroyed(this)) .subscribe(); } diff --git a/src/app/shared/dia-backend/auth/dia-backend-auth.service.ts b/src/app/shared/dia-backend/auth/dia-backend-auth.service.ts index 78594ac2c..9b98e3a56 100644 --- a/src/app/shared/dia-backend/auth/dia-backend-auth.service.ts +++ b/src/app/shared/dia-backend/auth/dia-backend-auth.service.ts @@ -151,7 +151,7 @@ export class DiaBackendAuthService { }) .pipe( concatMap(response => this.setToken(response.auth_token)), - concatMapTo(this.syncProfile$()), + concatMapTo(this.syncUser$()), map(([username, _email]) => ({ username, email: _email })) ); } @@ -420,7 +420,7 @@ export class DiaBackendAuthService { ); } - syncProfile$() { + syncUser$() { return this.readUser$().pipe( concatMap(response => { return forkJoin([ From d82ef0294dcfba79a4dc0965490dc4e0c832ab7b Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Wed, 4 Oct 2023 08:23:22 +0800 Subject: [PATCH 05/28] feat(uploading-bar): match new UI design --- .../uploading-bar/uploading-bar.component.html | 13 +++++++++---- .../uploading-bar/uploading-bar.component.scss | 14 ++++++++++---- .../uploading-bar/uploading-bar.component.ts | 2 ++ 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.html b/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.html index c628df35e..2625f0665 100644 --- a/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.html +++ b/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.html @@ -1,5 +1,10 @@ - - + + {{ uploadingBarState.text }} @@ -18,5 +23,5 @@ publish - - + + diff --git a/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.scss b/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.scss index 2ed466968..c19e15db5 100644 --- a/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.scss +++ b/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.scss @@ -1,6 +1,13 @@ +mat-toolbar { + margin: 16px; +} + .thin-upload-bar { + margin: 16px auto; + width: calc(100vw - 32px); min-height: 32px; - height: 32px; + max-height: 48px; + border-radius: 8px; justify-content: stretch; transition: all 1s; @@ -22,9 +29,8 @@ } #thin-upload-bar { - height: 32px; - color: var(--ion-color-medium-tint); - background-color: var(--ion-color-light); + color: white; + background-color: #212121; } .spacer { diff --git a/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.ts b/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.ts index e27cbfc74..623290aee 100644 --- a/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.ts +++ b/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.ts @@ -49,6 +49,7 @@ export class UploadingBarComponent { showProgressBar: tasks > 0 && networkConnected && !isPaused, showPauseButton: tasks > 0 && networkConnected && !isPaused, showResumeButton: tasks > 0 && networkConnected && isPaused, + hideUploadBar: tasks === 0, }; return uploadingBarState; }) @@ -85,4 +86,5 @@ interface UploadingBarState { readonly showProgressBar: boolean; readonly showPauseButton: boolean; readonly showResumeButton: boolean; + readonly hideUploadBar: boolean; } From aa7b452f0b02eb46a879ccf7c1c2a3c164016a8e Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Wed, 4 Oct 2023 08:23:57 +0800 Subject: [PATCH 06/28] feat(dia-backend-auth): add profileDescription$ --- .../dia-backend/auth/dia-backend-auth.service.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/app/shared/dia-backend/auth/dia-backend-auth.service.ts b/src/app/shared/dia-backend/auth/dia-backend-auth.service.ts index 9b98e3a56..d43970e3f 100644 --- a/src/app/shared/dia-backend/auth/dia-backend-auth.service.ts +++ b/src/app/shared/dia-backend/auth/dia-backend-auth.service.ts @@ -72,7 +72,20 @@ export class DiaBackendAuthService { ) ), map(response => response.profile_background_thumbnail), - isNonNullable() + isNonNullable(), + repeatWhen(() => this.refreshAvatar$) // TODO: refreshProfile$ + ); + + readonly profileDescription$ = defer(() => this.getAuthHeaders()).pipe( + concatMap(headers => + this.httpClient.get( + `${BASE_URL}/auth/users/profile/`, + { headers } + ) + ), + map(response => response.description), + isNonNullable(), + repeatWhen(() => this.refreshAvatar$) // TODO: refreshProfile$ ); readonly phoneVerified$ = this.preferences.getBoolean$( From ceed7e60f9dd72a62f573710e4a9b577a02f32e1 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Wed, 4 Oct 2023 09:07:51 +0800 Subject: [PATCH 07/28] chore: add icons for capture-tab --- src/assets/images/icons/capture-tab-collected.svg | 4 ++++ src/assets/images/icons/capture-tab-draft.svg | 3 +++ src/assets/images/icons/capture-tab-verified.svg | 3 +++ 3 files changed, 10 insertions(+) create mode 100644 src/assets/images/icons/capture-tab-collected.svg create mode 100644 src/assets/images/icons/capture-tab-draft.svg create mode 100644 src/assets/images/icons/capture-tab-verified.svg diff --git a/src/assets/images/icons/capture-tab-collected.svg b/src/assets/images/icons/capture-tab-collected.svg new file mode 100644 index 000000000..cfadf6cde --- /dev/null +++ b/src/assets/images/icons/capture-tab-collected.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/images/icons/capture-tab-draft.svg b/src/assets/images/icons/capture-tab-draft.svg new file mode 100644 index 000000000..372388c7b --- /dev/null +++ b/src/assets/images/icons/capture-tab-draft.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/images/icons/capture-tab-verified.svg b/src/assets/images/icons/capture-tab-verified.svg new file mode 100644 index 000000000..2450046cf --- /dev/null +++ b/src/assets/images/icons/capture-tab-verified.svg @@ -0,0 +1,3 @@ + + + From a49eb023455322e5f8d2d7ffa3add66aeaae3bb8 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Wed, 4 Oct 2023 09:08:13 +0800 Subject: [PATCH 08/28] feat(capture-tab): match new UI design --- .../capture-tab/capture-tab.component.html | 56 +++++++-- .../capture-tab/capture-tab.component.scss | 79 +++++++++++-- .../home/capture-tab/capture-tab.component.ts | 110 +++++++++++++++++- src/app/features/home/home.page.html | 4 +- src/global.scss | 6 + 5 files changed, 231 insertions(+), 24 deletions(-) diff --git a/src/app/features/home/capture-tab/capture-tab.component.html b/src/app/features/home/capture-tab/capture-tab.component.html index be080f5f1..06cd093b9 100644 --- a/src/app/features/home/capture-tab/capture-tab.component.html +++ b/src/app/features/home/capture-tab/capture-tab.component.html @@ -2,7 +2,40 @@ - + + + + + + + + +
@@ -14,21 +47,30 @@ >
- {{ email$ | ngrxPush }} + {{ profileDescription$ | ngrxPush }} +
+ +
-
- +
+ - {{ 'home.profileTab.verified' | transloco }} + - {{ 'home.profileTab.collected' | transloco }} + - {{ 'home.profileTab.draft' | transloco }} + diff --git a/src/app/features/home/capture-tab/capture-tab.component.scss b/src/app/features/home/capture-tab/capture-tab.component.scss index 074c2ccb7..99f55694a 100644 --- a/src/app/features/home/capture-tab/capture-tab.component.scss +++ b/src/app/features/home/capture-tab/capture-tab.component.scss @@ -11,7 +11,50 @@ mat-card { display: flex; flex-direction: column; align-items: center; - justify-content: center; + justify-content: start; + min-height: 45vh; + width: 100%; + padding: 0 0 8px; + box-shadow: none; + + mat-toolbar { + background: transparent; + + .custom-fab-button { + border-radius: 37px; + background: #ffffff40; + backdrop-filter: blur(2px); + + &.mat-mini-fab { + box-shadow: none; + } + + mat-icon { + color: white; + } + } + + .margin-left-8 { + margin-left: 8px; + } + } + + .vertical-spacer { + flex: 1; + } + + .background-image-gradient { + position: absolute; + bottom: 0; + height: 20vh; + width: 100%; + z-index: 1; + background: linear-gradient(to bottom, transparent, #00000080 10vh); + } +} + +mat-card-header { + z-index: 2; } mat-card-title { @@ -28,13 +71,6 @@ mat-card-subtitle { text-align: center; } -.user-card { - width: 100%; - padding-left: 16px; - padding-right: 16px; - box-shadow: none; -} - #user-card { background-color: var(--capture-color-dark-background, white); } @@ -50,8 +86,8 @@ mat-card-subtitle { } app-avatar { - width: 64px; - height: 64px; + width: 120px; + height: 120px; } .network-status { @@ -65,7 +101,7 @@ app-avatar { } .capture-container { - padding: 32px 16px; + padding: 32px 8px; } app-capture-item { @@ -77,7 +113,7 @@ app-capture-item { .post-captures { overflow: auto; - padding: 16px; + padding: 32px 8px; mat-grid-tile { ion-img { @@ -108,3 +144,22 @@ app-capture-item { } } } + +.segment-container { + margin-top: 16px; + padding: 8px 16px; + + ion-segment { + --background: #212121; + + ion-segment-button { + ion-icon { + margin: 8px; + } + + ion-icon.font-size-scaled { + transform: scale(1.3); + } + } + } +} diff --git a/src/app/features/home/capture-tab/capture-tab.component.ts b/src/app/features/home/capture-tab/capture-tab.component.ts index 5d54b5277..128ab9bd0 100644 --- a/src/app/features/home/capture-tab/capture-tab.component.ts +++ b/src/app/features/home/capture-tab/capture-tab.component.ts @@ -1,16 +1,25 @@ import { formatDate, KeyValue } from '@angular/common'; import { HttpErrorResponse } from '@angular/common/http'; -import { Component, OnInit } from '@angular/core'; -import { AlertController } from '@ionic/angular'; +import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { + ActionSheetButton, + ActionSheetController, + AlertController, +} from '@ionic/angular'; import { TranslocoService } from '@ngneat/transloco'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { groupBy } from 'lodash-es'; -import { BehaviorSubject, combineLatest, iif } from 'rxjs'; +import { BehaviorSubject, combineLatest, defer, iif } from 'rxjs'; import { catchError, + concatMap, + concatMapTo, finalize, map, pluck, + shareReplay, + startWith, switchMap, tap, } from 'rxjs/operators'; @@ -19,17 +28,23 @@ import { CaptureTabSegments, CaptureTabService, } from '../../../shared/capture-tab/capture-tab.service'; +import { ConfirmAlert } from '../../../shared/confirm-alert/confirm-alert.service'; +import { Database } from '../../../shared/database/database.service'; import { DiaBackendAsset, DiaBackendAssetRepository, } from '../../../shared/dia-backend/asset/dia-backend-asset-repository.service'; import { DiaBackendAsseRefreshingService } from '../../../shared/dia-backend/asset/refreshing/dia-backend-asset-refreshing.service'; import { DiaBackendAuthService } from '../../../shared/dia-backend/auth/dia-backend-auth.service'; +import { DiaBackendTransactionRepository } from '../../../shared/dia-backend/transaction/dia-backend-transaction-repository.service'; import { ErrorService } from '../../../shared/error/error.service'; +import { MediaStore } from '../../../shared/media/media-store/media-store.service'; import { NetworkService } from '../../../shared/network/network.service'; +import { PreferenceManager } from '../../../shared/preference-manager/preference-manager.service'; import { getOldProof } from '../../../shared/repositories/proof/old-proof-adapter'; import { Proof } from '../../../shared/repositories/proof/proof'; import { ProofRepository } from '../../../shared/repositories/proof/proof-repository.service'; +import { reloadApp } from '../../../utils/miscellaneous'; @UntilDestroy({ checkProperties: true }) @Component({ @@ -45,10 +60,28 @@ export class CaptureTabComponent implements OnInit { readonly captureTabSegments = CaptureTabSegments; segment: CaptureTabSegments = CaptureTabSegments.COLLECTED; + readonly hasNewInbox$ = this.diaBackendTransactionRepository.inbox$.pipe( + catchError((err: unknown) => this.errorService.toastError$(err)), + map(transactions => transactions.count !== 0), + /** + * WORKARDOUND: force changeDetection to update badge when returning to App + * by clicking push notification + */ + tap(() => this.changeDetectorRef.detectChanges()), + startWith(false) + ); + readonly username$ = this.diaBackendAuthService.username$; readonly email$ = this.diaBackendAuthService.email$; + readonly profileDescription$ = this.diaBackendAuthService.profileDescription$; + + readonly profileBackground$ = + this.diaBackendAuthService.profileBackground$.pipe( + shareReplay({ bufferSize: 1, refCount: true }) + ); + private readonly proofs$ = this.proofRepository.all$; readonly capturesByDate$ = this.proofs$.pipe( @@ -120,9 +153,17 @@ export class CaptureTabComponent implements OnInit { ); constructor( + private readonly actionSheetController: ActionSheetController, + private readonly router: Router, + private readonly mediaStore: MediaStore, + private readonly database: Database, + private readonly confirmAlert: ConfirmAlert, + private readonly preferenceManager: PreferenceManager, + private readonly changeDetectorRef: ChangeDetectorRef, private readonly proofRepository: ProofRepository, private readonly diaBackendAuthService: DiaBackendAuthService, private readonly diaBackendAssetRepository: DiaBackendAssetRepository, + private readonly diaBackendTransactionRepository: DiaBackendTransactionRepository, private readonly diaBackendAssetRefreshingService: DiaBackendAsseRefreshingService, private readonly alertController: AlertController, private readonly networkService: NetworkService, @@ -161,6 +202,69 @@ export class CaptureTabComponent implements OnInit { eventTarget.complete(); } + openMenu() { + const buttons: ActionSheetButton[] = [ + { + text: this.translocoService.translate('wallets.wallets'), + handler: () => this.router.navigate(['wallets']), + }, + { + text: this.translocoService.translate('invitation.inviteFriends'), + handler: () => this.router.navigate(['invitation']), + }, + { + text: this.translocoService.translate('settings.settings'), + handler: () => this.router.navigate(['settings']), + }, + { + text: this.translocoService.translate('friends'), + handler: () => this.router.navigate(['contacts']), + }, + { + text: this.translocoService.translate('dataPolicy'), + handler: () => this.router.navigate(['data-policy']), + }, + { + text: this.translocoService.translate('termsOfUse'), + handler: () => this.router.navigate(['terms-of-use']), + }, + { + text: this.translocoService.translate('faq'), + handler: () => this.router.navigate(['faq']), + }, + { + text: this.translocoService.translate('logout'), + handler: () => this.logout(), + cssClass: 'capture-tab-menu-logout-button', + }, + ]; + + this.actionSheetController + .create({ buttons }) + .then(sheet => sheet.present()); + } + + logout() { + const action$ = defer(() => this.mediaStore.clear()).pipe( + concatMapTo(defer(() => this.database.clear())), + concatMapTo(defer(() => this.preferenceManager.clear())), + concatMapTo(defer(reloadApp)), + catchError((err: unknown) => this.errorService.toastError$(err)) + ); + defer(() => + this.confirmAlert.present({ + message: this.translocoService.translate('message.confirmLogout'), + }) + ) + .pipe( + concatMap(result => + iif(() => result, this.blockingActionService.run$(action$)) + ), + untilDestroyed(this) + ) + .subscribe(); + } + async editUsername() { const alert = await this.alertController.create({ header: this.translocoService.translate('editUsername'), diff --git a/src/app/features/home/home.page.html b/src/app/features/home/home.page.html index db572fddb..188a7d211 100644 --- a/src/app/features/home/home.page.html +++ b/src/app/features/home/home.page.html @@ -53,7 +53,7 @@ - + Date: Wed, 4 Oct 2023 09:15:32 +0800 Subject: [PATCH 09/28] chore: add translation for "confrim" text --- src/assets/i18n/en-us.json | 1 + src/assets/i18n/zh-tw.json | 1 + 2 files changed, 2 insertions(+) diff --git a/src/assets/i18n/en-us.json b/src/assets/i18n/en-us.json index ceca496da..304badac7 100644 --- a/src/assets/i18n/en-us.json +++ b/src/assets/i18n/en-us.json @@ -18,6 +18,7 @@ "areYouSure": "Are You Sure", "cancel": "Cancel", "ok": "Ok", + "confirm": "Confirm", "emptyInbox": "Empty Inbox", "clickToEditCaption": "Click to Edit Caption", "editCaption": "Edit Caption", diff --git a/src/assets/i18n/zh-tw.json b/src/assets/i18n/zh-tw.json index e00412840..0c6a2d6ce 100644 --- a/src/assets/i18n/zh-tw.json +++ b/src/assets/i18n/zh-tw.json @@ -18,6 +18,7 @@ "areYouSure": "是否確定", "cancel": "取消", "ok": "確認", + "confirm": "確認", "emptyInbox": "空收件匣", "clickToEditCaption": "點擊以編輯標題", "editCaption": "編輯標題", From 13701d765a064f7b269e77395aa1d2b9f0b777bf Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Wed, 4 Oct 2023 09:16:08 +0800 Subject: [PATCH 10/28] fix(order-detail-dialog): change "ok" to "confirm" --- .../order-detail-dialog/order-detail-dialog.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/shared/order-detail-dialog/order-detail-dialog.component.html b/src/app/shared/order-detail-dialog/order-detail-dialog.component.html index a96b0629e..5f807fd19 100644 --- a/src/app/shared/order-detail-dialog/order-detail-dialog.component.html +++ b/src/app/shared/order-detail-dialog/order-detail-dialog.component.html @@ -45,7 +45,7 @@

{{ t('payment.confirmPayment') }}

fill="outline" (click)="cancel()" > - {{ t('cancel') }} + {{ t('cancel') | uppercase }} @@ -55,7 +55,7 @@

{{ t('payment.confirmPayment') }}

[disabled]="asset_wallet_mainnet_num_balance < num_charged" (click)="ok()" > - {{ t('ok') }} + {{ t('confirm') | uppercase }}
From def5c8c6c21c9a9feb9ca5498b478e1a28f201f1 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Wed, 4 Oct 2023 16:41:03 +0800 Subject: [PATCH 11/28] Revert "feat(uploading-bar): match new UI design" This reverts commit d82ef0294dcfba79a4dc0965490dc4e0c832ab7b. --- .../uploading-bar/uploading-bar.component.html | 13 ++++--------- .../uploading-bar/uploading-bar.component.scss | 14 ++++---------- .../uploading-bar/uploading-bar.component.ts | 2 -- 3 files changed, 8 insertions(+), 21 deletions(-) diff --git a/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.html b/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.html index 2625f0665..c628df35e 100644 --- a/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.html +++ b/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.html @@ -1,10 +1,5 @@ - - + + {{ uploadingBarState.text }} @@ -23,5 +18,5 @@ publish - - + +
diff --git a/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.scss b/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.scss index c19e15db5..2ed466968 100644 --- a/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.scss +++ b/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.scss @@ -1,13 +1,6 @@ -mat-toolbar { - margin: 16px; -} - .thin-upload-bar { - margin: 16px auto; - width: calc(100vw - 32px); min-height: 32px; - max-height: 48px; - border-radius: 8px; + height: 32px; justify-content: stretch; transition: all 1s; @@ -29,8 +22,9 @@ mat-toolbar { } #thin-upload-bar { - color: white; - background-color: #212121; + height: 32px; + color: var(--ion-color-medium-tint); + background-color: var(--ion-color-light); } .spacer { diff --git a/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.ts b/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.ts index 623290aee..e27cbfc74 100644 --- a/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.ts +++ b/src/app/features/home/capture-tab/uploading-bar/uploading-bar.component.ts @@ -49,7 +49,6 @@ export class UploadingBarComponent { showProgressBar: tasks > 0 && networkConnected && !isPaused, showPauseButton: tasks > 0 && networkConnected && !isPaused, showResumeButton: tasks > 0 && networkConnected && isPaused, - hideUploadBar: tasks === 0, }; return uploadingBarState; }) @@ -86,5 +85,4 @@ interface UploadingBarState { readonly showProgressBar: boolean; readonly showPauseButton: boolean; readonly showResumeButton: boolean; - readonly hideUploadBar: boolean; } From 27955ea5583cc191f928a4a628c2d1810e59e699 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Wed, 4 Oct 2023 16:41:30 +0800 Subject: [PATCH 12/28] Revert "chore: add icons for capture-tab" This reverts commit ceed7e60f9dd72a62f573710e4a9b577a02f32e1. --- src/assets/images/icons/capture-tab-collected.svg | 4 ---- src/assets/images/icons/capture-tab-draft.svg | 3 --- src/assets/images/icons/capture-tab-verified.svg | 3 --- 3 files changed, 10 deletions(-) delete mode 100644 src/assets/images/icons/capture-tab-collected.svg delete mode 100644 src/assets/images/icons/capture-tab-draft.svg delete mode 100644 src/assets/images/icons/capture-tab-verified.svg diff --git a/src/assets/images/icons/capture-tab-collected.svg b/src/assets/images/icons/capture-tab-collected.svg deleted file mode 100644 index cfadf6cde..000000000 --- a/src/assets/images/icons/capture-tab-collected.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/assets/images/icons/capture-tab-draft.svg b/src/assets/images/icons/capture-tab-draft.svg deleted file mode 100644 index 372388c7b..000000000 --- a/src/assets/images/icons/capture-tab-draft.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/assets/images/icons/capture-tab-verified.svg b/src/assets/images/icons/capture-tab-verified.svg deleted file mode 100644 index 2450046cf..000000000 --- a/src/assets/images/icons/capture-tab-verified.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - From 3540ae47a1c684b0421166f044f067b16693590f Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Wed, 4 Oct 2023 17:11:52 +0800 Subject: [PATCH 13/28] feat(capture-tab): use text instead of icons in segment --- .../capture-tab/capture-tab.component.html | 15 +++++--------- .../capture-tab/capture-tab.component.scss | 20 +++---------------- 2 files changed, 8 insertions(+), 27 deletions(-) diff --git a/src/app/features/home/capture-tab/capture-tab.component.html b/src/app/features/home/capture-tab/capture-tab.component.html index 06cd093b9..8c7d60acc 100644 --- a/src/app/features/home/capture-tab/capture-tab.component.html +++ b/src/app/features/home/capture-tab/capture-tab.component.html @@ -56,21 +56,16 @@ -
- +
+ - + {{ 'home.profileTab.verified' | transloco }} - + {{ 'home.profileTab.collected' | transloco }} - + {{ 'home.profileTab.draft' | transloco }} diff --git a/src/app/features/home/capture-tab/capture-tab.component.scss b/src/app/features/home/capture-tab/capture-tab.component.scss index 99f55694a..07a13b6b7 100644 --- a/src/app/features/home/capture-tab/capture-tab.component.scss +++ b/src/app/features/home/capture-tab/capture-tab.component.scss @@ -145,21 +145,7 @@ app-capture-item { } } -.segment-container { - margin-top: 16px; - padding: 8px 16px; - - ion-segment { - --background: #212121; - - ion-segment-button { - ion-icon { - margin: 8px; - } - - ion-icon.font-size-scaled { - transform: scale(1.3); - } - } - } +mat-grid-list { + margin-left: 12px; + margin-right: 12px; } From 42fe07399ddcbe0034ce1c2accb23ab6eb389ee6 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Thu, 5 Oct 2023 16:40:51 +0800 Subject: [PATCH 14/28] feat: add what-are-actions page --- .../what-are-actions-routing.module.ts | 17 +++++++ .../what-are-actions.module.ts | 12 +++++ .../what-are-actions.page.html | 17 +++++++ .../what-are-actions.page.scss | 31 ++++++++++++ .../what-are-actions.page.spec.ts | 26 ++++++++++ .../what-are-actions/what-are-actions.page.ts | 49 +++++++++++++++++++ 6 files changed, 152 insertions(+) create mode 100644 src/app/features/home/details/actions/what-are-actions/what-are-actions-routing.module.ts create mode 100644 src/app/features/home/details/actions/what-are-actions/what-are-actions.module.ts create mode 100644 src/app/features/home/details/actions/what-are-actions/what-are-actions.page.html create mode 100644 src/app/features/home/details/actions/what-are-actions/what-are-actions.page.scss create mode 100644 src/app/features/home/details/actions/what-are-actions/what-are-actions.page.spec.ts create mode 100644 src/app/features/home/details/actions/what-are-actions/what-are-actions.page.ts diff --git a/src/app/features/home/details/actions/what-are-actions/what-are-actions-routing.module.ts b/src/app/features/home/details/actions/what-are-actions/what-are-actions-routing.module.ts new file mode 100644 index 000000000..ad7ca1fa6 --- /dev/null +++ b/src/app/features/home/details/actions/what-are-actions/what-are-actions-routing.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; + +import { WhatAreActionsPage } from './what-are-actions.page'; + +const routes: Routes = [ + { + path: '', + component: WhatAreActionsPage, + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class WhatAreActionsPageRoutingModule {} diff --git a/src/app/features/home/details/actions/what-are-actions/what-are-actions.module.ts b/src/app/features/home/details/actions/what-are-actions/what-are-actions.module.ts new file mode 100644 index 000000000..b957069ae --- /dev/null +++ b/src/app/features/home/details/actions/what-are-actions/what-are-actions.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core'; + +import { WhatAreActionsPageRoutingModule } from './what-are-actions-routing.module'; + +import { SharedModule } from '../../../../../shared/shared.module'; +import { WhatAreActionsPage } from './what-are-actions.page'; + +@NgModule({ + imports: [SharedModule, WhatAreActionsPageRoutingModule], + declarations: [WhatAreActionsPage], +}) +export class WhatAreActionsPageModule {} diff --git a/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.html b/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.html new file mode 100644 index 000000000..e6a937712 --- /dev/null +++ b/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.html @@ -0,0 +1,17 @@ + + + + {{ 'networkActions' | transloco }} + +
+ {{ 'message.networkNotConnected' | transloco }} +
+
+ + + + + diff --git a/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.scss b/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.scss new file mode 100644 index 000000000..447ed91db --- /dev/null +++ b/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.scss @@ -0,0 +1,31 @@ +mat-toolbar { + span { + padding-right: 40px; + font-style: normal; + font-weight: 500; + font-size: 16px; + line-height: 21px; + text-align: center; + color: white; + } +} + +.no-network-text { + font-size: 18px; + margin: auto; +} + +.bubble-iframe { + background-color: black; + width: 100vw; + height: 100vh; + border: 0; +} + +ion-spinner { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + scale: 1.5; +} diff --git a/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.spec.ts b/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.spec.ts new file mode 100644 index 000000000..70b99dabb --- /dev/null +++ b/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.spec.ts @@ -0,0 +1,26 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { SharedTestingModule } from '../../../../../shared/shared-testing.module'; +import { WhatAreActionsPage } from './what-are-actions.page'; + +describe('WhatAreActionsPage', () => { + let component: WhatAreActionsPage; + let fixture: ComponentFixture; + + beforeEach( + waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [WhatAreActionsPage], + imports: [SharedTestingModule], + }).compileComponents(); + + fixture = TestBed.createComponent(WhatAreActionsPage); + component = fixture.componentInstance; + fixture.detectChanges(); + }) + ); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.ts b/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.ts new file mode 100644 index 000000000..b7b1eee4f --- /dev/null +++ b/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.ts @@ -0,0 +1,49 @@ +import { Component } from '@angular/core'; +import { NavController } from '@ionic/angular'; +import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; +import { BehaviorSubject, fromEvent } from 'rxjs'; +import { tap } from 'rxjs/operators'; +import { BUBBLE_IFRAME_URL } from '../../../../../shared/dia-backend/secret'; +import { BubbleToIonicPostMessage } from '../../../../../shared/iframe/iframe'; +import { NetworkService } from '../../../../../shared/network/network.service'; + +@UntilDestroy() +@Component({ + selector: 'app-what-are-actions', + templateUrl: './what-are-actions.page.html', + styleUrls: ['./what-are-actions.page.scss'], +}) +export class WhatAreActionsPage { + readonly networkConnected$ = this.networkService.connected$; + readonly iframeUrl = `${BUBBLE_IFRAME_URL}/what_are_actions`; + readonly iframeLoaded$ = new BehaviorSubject(false); + + constructor( + private readonly networkService: NetworkService, + private readonly navController: NavController + ) {} + + ionViewDidEnter() { + this.processIframeEvents(); + } + + processIframeEvents() { + fromEvent(window, 'message') + .pipe( + tap(event => { + const postMessageEvent = event as MessageEvent; + const data = postMessageEvent.data as BubbleToIonicPostMessage; + switch (data) { + case BubbleToIonicPostMessage.IFRAME_ON_LOAD: + this.iframeLoaded$.next(true); + break; + case BubbleToIonicPostMessage.IFRAME_BACK_BUTTON_CLICKED: + this.navController.back(); + break; + } + }), + untilDestroyed(this) + ) + .subscribe(); + } +} From 58481c15e6f2904defc3d73d6b6cf7b8c1222ea4 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Thu, 5 Oct 2023 16:48:26 +0800 Subject: [PATCH 15/28] feat(actions): add button to navigate to what-are-actions page --- .../details/actions/actions-routing.module.ts | 7 +++++++ .../home/details/actions/actions.page.html | 16 ++++++++++++++++ .../home/details/actions/actions.page.scss | 17 +++++++++++++++++ src/assets/i18n/en-us.json | 5 +++++ src/assets/i18n/zh-tw.json | 5 +++++ 5 files changed, 50 insertions(+) diff --git a/src/app/features/home/details/actions/actions-routing.module.ts b/src/app/features/home/details/actions/actions-routing.module.ts index 0586d29f3..00becfbf5 100644 --- a/src/app/features/home/details/actions/actions-routing.module.ts +++ b/src/app/features/home/details/actions/actions-routing.module.ts @@ -14,6 +14,13 @@ const routes: Routes = [ m => m.ActionDetailsPageModule ), }, + { + path: 'what-are-actions', + loadChildren: () => + import('./what-are-actions/what-are-actions.module').then( + m => m.WhatAreActionsPageModule + ), + }, ]; @NgModule({ diff --git a/src/app/features/home/details/actions/actions.page.html b/src/app/features/home/details/actions/actions.page.html index 01e97adc1..db1bb6b52 100644 --- a/src/app/features/home/details/actions/actions.page.html +++ b/src/app/features/home/details/actions/actions.page.html @@ -4,6 +4,22 @@
+ + +
+
+ {{ 'actions.whatAreNetworkActions' | transloco }} +
+
+ {{ 'actions.everythingYouNeedToKnow' | transloco }} +
+
+ + {{ 'actions.view' | transloco }} + +
+
+ diff --git a/src/app/features/home/details/actions/actions.page.scss b/src/app/features/home/details/actions/actions.page.scss index 24f1cb43e..cdef47bcf 100644 --- a/src/app/features/home/details/actions/actions.page.scss +++ b/src/app/features/home/details/actions/actions.page.scss @@ -53,6 +53,23 @@ mat-toolbar { font-style: normal; font-weight: 500; } + + .header-text-small { + .header-title-small { + color: white; + font-size: 14px; + font-style: normal; + font-weight: 500; + } + + .header-subtitle-small { + margin-top: 8px; + color: #ffffff80; + font-size: 12px; + font-style: normal; + font-weight: 500; + } + } } ion-card-subtitle { diff --git a/src/assets/i18n/en-us.json b/src/assets/i18n/en-us.json index 304badac7..4b79fe647 100644 --- a/src/assets/i18n/en-us.json +++ b/src/assets/i18n/en-us.json @@ -308,6 +308,11 @@ "networkActionsAreUnavailable": "Network Actions are unavailable. Please try again later." } }, + "actions": { + "whatAreNetworkActions": "What are network actions?", + "everythingYouNeedToKnow": "Everything you need to know, in one simple guide.", + "view": "View" + }, "customCamera": { "confirmCapture": "Next", "max": "Max", diff --git a/src/assets/i18n/zh-tw.json b/src/assets/i18n/zh-tw.json index 0c6a2d6ce..35d872d86 100644 --- a/src/assets/i18n/zh-tw.json +++ b/src/assets/i18n/zh-tw.json @@ -308,6 +308,11 @@ "networkActionsAreUnavailable": "暫時無法使用 Network Action,請稍後再試。" } }, + "actions": { + "whatAreNetworkActions": "什麼是網絡操作?", + "everythingYouNeedToKnow": "一個簡單指南,告訴您需要知道的一切。", + "view": "查看" + }, "customCamera": { "confirmCapture": "下一步", "max": "最佳畫質", From 3aa744decbe16fd642082d489cb9cbe6deeeb7fe Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Thu, 5 Oct 2023 16:52:59 +0800 Subject: [PATCH 16/28] style: fix linting --- .../details/actions/action-details/action-details.page.scss | 5 ++--- .../order-detail-dialog/order-detail-dialog.component.scss | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/app/features/home/details/actions/action-details/action-details.page.scss b/src/app/features/home/details/actions/action-details/action-details.page.scss index b54869ba5..3aea74250 100644 --- a/src/app/features/home/details/actions/action-details/action-details.page.scss +++ b/src/app/features/home/details/actions/action-details/action-details.page.scss @@ -16,7 +16,7 @@ ion-content { .description { margin: 24px 24px 48px; - color: #fff; + color: white; text-align: center; font-size: 14px; font-style: normal; @@ -30,7 +30,6 @@ ion-content { aspect-ratio: 179 / 216; border-radius: 16px; overflow: hidden; - border-radius: 16px; height: 25vh; ion-img { @@ -62,7 +61,7 @@ ion-footer { } .price-number { - color: #fff; + color: white; font-size: 20px; font-style: normal; font-weight: 700; diff --git a/src/app/shared/order-detail-dialog/order-detail-dialog.component.scss b/src/app/shared/order-detail-dialog/order-detail-dialog.component.scss index 627482fcd..b9f48ee8e 100644 --- a/src/app/shared/order-detail-dialog/order-detail-dialog.component.scss +++ b/src/app/shared/order-detail-dialog/order-detail-dialog.component.scss @@ -12,7 +12,7 @@ --border-color: #333; --background: #212121; --padding-start: 0; - --inner-padding-end: 0px; + --inner-padding-end: 0; } } From 038945e40f37d1148fae02371f375036cb98c013 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Thu, 5 Oct 2023 18:57:51 +0800 Subject: [PATCH 17/28] fix(what-are-actions.page): re-implement with ionic Due to bubble relase deadlines what-are-actions.page is re-implemented with ionic components instead of iframe + bubble page. In the future we might re-implement it with iframe + bubble. --- .../what-are-actions.page.html | 25 ++++------- .../what-are-actions.page.scss | 26 +++++------ .../what-are-actions/what-are-actions.page.ts | 43 +------------------ src/assets/i18n/en-us.json | 6 ++- src/assets/i18n/zh-tw.json | 8 +++- 5 files changed, 32 insertions(+), 76 deletions(-) diff --git a/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.html b/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.html index e6a937712..ed54165bd 100644 --- a/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.html +++ b/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.html @@ -1,17 +1,10 @@ - - - - {{ 'networkActions' | transloco }} - -
- {{ 'message.networkNotConnected' | transloco }} -
-
+ + + {{ 'actions.actions' | transloco }} + - - - - + +

{{ 'actions.whatAreActions' | transloco }}

+

{{ 'actions.whatAreActionsParagraph1' | transloco }}

+

{{ 'actions.whatAreActionsParagraph2' | transloco }}

+
diff --git a/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.scss b/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.scss index 447ed91db..b3a80c1dd 100644 --- a/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.scss +++ b/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.scss @@ -10,22 +10,16 @@ mat-toolbar { } } -.no-network-text { - font-size: 18px; - margin: auto; -} +ion-content { + --padding-start: 24px; + --padding-end: 24px; -.bubble-iframe { - background-color: black; - width: 100vw; - height: 100vh; - border: 0; -} + h1 { + margin-top: 32px; + } -ion-spinner { - position: absolute; - left: 50%; - top: 50%; - transform: translate(-50%, -50%); - scale: 1.5; + p { + opacity: 0.75; + margin-bottom: 32px; + } } diff --git a/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.ts b/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.ts index b7b1eee4f..bec7451ac 100644 --- a/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.ts +++ b/src/app/features/home/details/actions/what-are-actions/what-are-actions.page.ts @@ -1,11 +1,5 @@ import { Component } from '@angular/core'; -import { NavController } from '@ionic/angular'; -import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; -import { BehaviorSubject, fromEvent } from 'rxjs'; -import { tap } from 'rxjs/operators'; -import { BUBBLE_IFRAME_URL } from '../../../../../shared/dia-backend/secret'; -import { BubbleToIonicPostMessage } from '../../../../../shared/iframe/iframe'; -import { NetworkService } from '../../../../../shared/network/network.service'; +import { UntilDestroy } from '@ngneat/until-destroy'; @UntilDestroy() @Component({ @@ -13,37 +7,4 @@ import { NetworkService } from '../../../../../shared/network/network.service'; templateUrl: './what-are-actions.page.html', styleUrls: ['./what-are-actions.page.scss'], }) -export class WhatAreActionsPage { - readonly networkConnected$ = this.networkService.connected$; - readonly iframeUrl = `${BUBBLE_IFRAME_URL}/what_are_actions`; - readonly iframeLoaded$ = new BehaviorSubject(false); - - constructor( - private readonly networkService: NetworkService, - private readonly navController: NavController - ) {} - - ionViewDidEnter() { - this.processIframeEvents(); - } - - processIframeEvents() { - fromEvent(window, 'message') - .pipe( - tap(event => { - const postMessageEvent = event as MessageEvent; - const data = postMessageEvent.data as BubbleToIonicPostMessage; - switch (data) { - case BubbleToIonicPostMessage.IFRAME_ON_LOAD: - this.iframeLoaded$.next(true); - break; - case BubbleToIonicPostMessage.IFRAME_BACK_BUTTON_CLICKED: - this.navController.back(); - break; - } - }), - untilDestroyed(this) - ) - .subscribe(); - } -} +export class WhatAreActionsPage {} diff --git a/src/assets/i18n/en-us.json b/src/assets/i18n/en-us.json index 4b79fe647..b86cd21bc 100644 --- a/src/assets/i18n/en-us.json +++ b/src/assets/i18n/en-us.json @@ -309,9 +309,13 @@ } }, "actions": { + "actions": "Actions", "whatAreNetworkActions": "What are network actions?", "everythingYouNeedToKnow": "Everything you need to know, in one simple guide.", - "view": "View" + "view": "View", + "whatAreActions": "What are actions?", + "whatAreActionsParagraph1": "As a Web 3.0 photo network, Capture aims to become the central hub for managing the authenticity, liquidity and monetization of Web3 assets and providing an enhanced photo experience for users. With Capture, users can take a photo using the Capture Cam and then share it seamlessly across various platforms and applications in the Capture ecosystem, eliminating the need to upload the same photo multiple times to different platforms.", + "whatAreActionsParagraph2": "By registering your Web 3.0 assets, such as images and videos, on the Capture network, you can ensure that these assets are traceable and can be trusted by the Capture ecosystem. This allows other apps within the ecosystem to provide services for your assets. Additionally, by registering your assets on Capture, you retain ownership of them and have the freedom to use them within the Capture ecosystem as you see fit." }, "customCamera": { "confirmCapture": "Next", diff --git a/src/assets/i18n/zh-tw.json b/src/assets/i18n/zh-tw.json index 35d872d86..324aefc10 100644 --- a/src/assets/i18n/zh-tw.json +++ b/src/assets/i18n/zh-tw.json @@ -309,9 +309,13 @@ } }, "actions": { + "actions": "網絡動作", "whatAreNetworkActions": "什麼是網絡操作?", - "everythingYouNeedToKnow": "一個簡單指南,告訴您需要知道的一切。", - "view": "查看" + "everythingYouNeedToKnow": "簡易操作指南", + "view": "查看", + "whatAreActions": "什麼是操作?", + "whatAreActionsParagraph1": "什麼是 Action? 作為 Web3.0 照片網絡,Capture 旨在成為管理 Web3 資產真實性、流動性和貨幣化的中心樞紐,並為用戶提供流暢的拍照體驗。使用 Capture,用戶可以使用 Capture Cam 拍照,然後在 Capture 生態系統中的各種平台和應用程序上無縫共享,無需將同張照片多次上傳到不同的平台。", + "whatAreActionsParagraph2": "通過在 Capture 網絡上註冊您的 Web3.0 資產(例如影像和影片),您可以確保這些資產是可追溯的並且可以被 Capture 生態系統信任。這允許生態系統中的其他應用程式為您的資產提供服務。此外,通過在 Capture 上註冊您的資產,您可以保留對它們的所有權,並有權在 Capture 生態系中使用它們。" }, "customCamera": { "confirmCapture": "下一步", From 63f222562ff66c3f3526ad29e7723bf1add08c7e Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Fri, 6 Oct 2023 14:39:09 +0800 Subject: [PATCH 18/28] fix(zh-tw): translation for "What is action" --- src/assets/i18n/zh-tw.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/i18n/zh-tw.json b/src/assets/i18n/zh-tw.json index 324aefc10..3104b9253 100644 --- a/src/assets/i18n/zh-tw.json +++ b/src/assets/i18n/zh-tw.json @@ -313,7 +313,7 @@ "whatAreNetworkActions": "什麼是網絡操作?", "everythingYouNeedToKnow": "簡易操作指南", "view": "查看", - "whatAreActions": "什麼是操作?", + "whatAreActions": "什麼是 Action?", "whatAreActionsParagraph1": "什麼是 Action? 作為 Web3.0 照片網絡,Capture 旨在成為管理 Web3 資產真實性、流動性和貨幣化的中心樞紐,並為用戶提供流暢的拍照體驗。使用 Capture,用戶可以使用 Capture Cam 拍照,然後在 Capture 生態系統中的各種平台和應用程序上無縫共享,無需將同張照片多次上傳到不同的平台。", "whatAreActionsParagraph2": "通過在 Capture 網絡上註冊您的 Web3.0 資產(例如影像和影片),您可以確保這些資產是可追溯的並且可以被 Capture 生態系統信任。這允許生態系統中的其他應用程式為您的資產提供服務。此外,通過在 Capture 上註冊您的資產,您可以保留對它們的所有權,並有權在 Capture 生態系中使用它們。" }, From 45b5e2d4872b13199355d178486ef0322f616a61 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Fri, 6 Oct 2023 16:23:49 +0800 Subject: [PATCH 19/28] fix(action-details): navigate back to home page using browser history API --- .../actions/action-details/action-details.page.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/app/features/home/details/actions/action-details/action-details.page.ts b/src/app/features/home/details/actions/action-details/action-details.page.ts index a2f5fcf78..c92ac43fc 100644 --- a/src/app/features/home/details/actions/action-details/action-details.page.ts +++ b/src/app/features/home/details/actions/action-details/action-details.page.ts @@ -382,7 +382,15 @@ export class ActionDetailsPage { proof => { if (proof) { this.proofRepository.remove(proof); - this.router.navigate(['/home']); + /** + * WORKAROUND: https://github.com/numbersprotocol/capture-lite/issues/3050 + * After certain network actions we need to navigate user back to + * home page. We could not achieve this with this.router.navigate(['/home']); + * therefore we need to use `popstate` navigationTrigger. + */ + this.navController.back(); // goes back to Actions page + this.navController.back(); // goes back to Details page + this.navController.back(); // goes back to Home page } } ); From 74c1c9cb6e806de1331c9b27464c0759924fb993 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Tue, 10 Oct 2023 10:19:02 +0800 Subject: [PATCH 20/28] fix(action-details): make submit button responsive --- .../action-details/action-details.page.html | 6 +-- .../action-details/action-details.page.scss | 46 +++++++++++++++---- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/app/features/home/details/actions/action-details/action-details.page.html b/src/app/features/home/details/actions/action-details/action-details.page.html index a1b9365a2..1da436183 100644 --- a/src/app/features/home/details/actions/action-details/action-details.page.html +++ b/src/app/features/home/details/actions/action-details/action-details.page.html @@ -33,14 +33,14 @@
{{ price$ | async }} NUM
- {{ title$ | async | uppercase }} - + diff --git a/src/app/features/home/details/actions/action-details/action-details.page.scss b/src/app/features/home/details/actions/action-details/action-details.page.scss index 3aea74250..8cbba2bb5 100644 --- a/src/app/features/home/details/actions/action-details/action-details.page.scss +++ b/src/app/features/home/details/actions/action-details/action-details.page.scss @@ -52,19 +52,47 @@ ion-footer { justify-content: space-between; align-items: center; - .price-in-num { - font-size: 14px; - font-style: normal; - font-weight: 500; - line-height: 100%; - opacity: 0.5; + .price { + margin-right: 8px; + white-space: nowrap; + + .price-in-num { + color: white; + font-size: 14px; + font-style: normal; + font-weight: 500; + line-height: 100%; + opacity: 0.5; + } + + .price-number { + color: white; + font-size: 20px; + font-style: normal; + font-weight: 700; + } } - .price-number { + .custom-button { + padding: 16px 20px; + background-color: #3880ff; color: white; - font-size: 20px; + border: none; + border-radius: 37px; + cursor: pointer; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + font-size: 13px; font-style: normal; - font-weight: 700; + font-weight: 600; + line-height: normal; + letter-spacing: 0.26px; + text-transform: uppercase; + + &:hover { + background-color: #0056b3; + } } } From 63879d72705427e1755f7c3675299fd96481c87c Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Tue, 17 Oct 2023 12:39:11 +0800 Subject: [PATCH 21/28] fix(capture-tab): set profile image bg to cover --- src/app/features/home/capture-tab/capture-tab.component.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/features/home/capture-tab/capture-tab.component.scss b/src/app/features/home/capture-tab/capture-tab.component.scss index 07a13b6b7..330b266db 100644 --- a/src/app/features/home/capture-tab/capture-tab.component.scss +++ b/src/app/features/home/capture-tab/capture-tab.component.scss @@ -16,6 +16,8 @@ mat-card { width: 100%; padding: 0 0 8px; box-shadow: none; + background-size: cover !important; /* stylelint-disable-line declaration-no-important */ + background-position: center center !important; /* stylelint-disable-line declaration-no-important */ mat-toolbar { background: transparent; From 2b7df2f2a427b37e5d97434c44e8ee6c68e4d4f6 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Tue, 17 Oct 2023 12:58:22 +0800 Subject: [PATCH 22/28] fix(zh-tw): remove unnecessary sentence --- src/assets/i18n/zh-tw.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assets/i18n/zh-tw.json b/src/assets/i18n/zh-tw.json index 3104b9253..83ae29650 100644 --- a/src/assets/i18n/zh-tw.json +++ b/src/assets/i18n/zh-tw.json @@ -314,7 +314,7 @@ "everythingYouNeedToKnow": "簡易操作指南", "view": "查看", "whatAreActions": "什麼是 Action?", - "whatAreActionsParagraph1": "什麼是 Action? 作為 Web3.0 照片網絡,Capture 旨在成為管理 Web3 資產真實性、流動性和貨幣化的中心樞紐,並為用戶提供流暢的拍照體驗。使用 Capture,用戶可以使用 Capture Cam 拍照,然後在 Capture 生態系統中的各種平台和應用程序上無縫共享,無需將同張照片多次上傳到不同的平台。", + "whatAreActionsParagraph1": "作為 Web3.0 照片網絡,Capture 旨在成為管理 Web3 資產真實性、流動性和貨幣化的中心樞紐,並為用戶提供流暢的拍照體驗。使用 Capture,用戶可以使用 Capture Cam 拍照,然後在 Capture 生態系統中的各種平台和應用程序上無縫共享,無需將同張照片多次上傳到不同的平台。", "whatAreActionsParagraph2": "通過在 Capture 網絡上註冊您的 Web3.0 資產(例如影像和影片),您可以確保這些資產是可追溯的並且可以被 Capture 生態系統信任。這允許生態系統中的其他應用程式為您的資產提供服務。此外,通過在 Capture 上註冊您的資產,您可以保留對它們的所有權,並有權在 Capture 生態系中使用它們。" }, "customCamera": { From 0ccd8bb5b3f7b7ff431214737469d139f395ce92 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Wed, 25 Oct 2023 12:53:23 +0800 Subject: [PATCH 23/28] change(translation): for `fileSizeExeedsLimit` --- src/assets/i18n/en-us.json | 2 +- src/assets/i18n/zh-tw.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/assets/i18n/en-us.json b/src/assets/i18n/en-us.json index ceca496da..53771d611 100644 --- a/src/assets/i18n/en-us.json +++ b/src/assets/i18n/en-us.json @@ -323,7 +323,7 @@ "error": { "duplicateAsset": "The asset you are trying to upload already exists on the blockchain. Please try again or contact support.", "canNotStartCamera": "Sorry, we encountered an issue while starting the camera. We apologize for the inconvenience. If the problem persists, please report the issue to our developers through the 'Contact Developers' section on the app's support page. Your feedback will help us improve the app and resolve the issue faster. Thank you for your understanding and cooperation.", - "fileSizeExeedsLimit": "File size exceeds 30MB limit. Please select a smaller file and try again." + "fileSizeExeedsLimit": "File size exceeds 25MB limit. Please select a smaller file and try again." } }, "wallets": { diff --git a/src/assets/i18n/zh-tw.json b/src/assets/i18n/zh-tw.json index e00412840..a76bd5f09 100644 --- a/src/assets/i18n/zh-tw.json +++ b/src/assets/i18n/zh-tw.json @@ -323,7 +323,7 @@ "error": { "duplicateAsset": "您嘗試上傳的資產已有上鏈紀錄,請重新嘗試,或聯繫開發團隊取得協助。", "canNotStartCamera": "很抱歉,我們在啟動相機時遇到問題。對於造成的不便,我們深感抱歉。如果問題持續存在,請透過應用程式支援頁面的「聯絡開發人員」區域向我們的開發人員報告問題。您的反饋將有助於我們改善應用程式並更快地解決問題。感謝您的理解和配合。", - "fileSizeExeedsLimit": "檔案大小超過30MB的限制,請選擇較小的檔案並重試。" + "fileSizeExeedsLimit": "檔案大小超過25MB的限制,請選擇較小的檔案並重試。" } }, "wallets": { From d54067d1b855aadbd192c55211fd1d297fc88efd Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Wed, 25 Oct 2023 13:59:31 +0800 Subject: [PATCH 24/28] fix(action-details) navigation after "Gift Capture" --- .../action-details/action-details.page.ts | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/app/features/home/details/actions/action-details/action-details.page.ts b/src/app/features/home/details/actions/action-details/action-details.page.ts index c92ac43fc..b7a9e3afb 100644 --- a/src/app/features/home/details/actions/action-details/action-details.page.ts +++ b/src/app/features/home/details/actions/action-details/action-details.page.ts @@ -305,7 +305,11 @@ export class ActionDetailsPage { this.snackBar.open( this.translocoService.translate('message.sentSuccessfully') ); - this.navController.back(); + if (action.hide_capture_after_execution_boolean ?? false) { + this.removeCaptureAndNavigateHome(); + } else { + this.navController.back(); + } }), tap(networkAppOrder => { if (action.ext_action_destination_text) { @@ -315,10 +319,6 @@ export class ActionDetailsPage { ); } }), - tap(() => { - if (action.hide_capture_after_execution_boolean ?? false) - this.removeCapture(); - }), untilDestroyed(this) ); }) @@ -376,21 +376,15 @@ export class ActionDetailsPage { .subscribe(); } - removeCapture() { + removeCaptureAndNavigateHome() { if (this.informationSessionService.activatedDetailedCapture) { this.informationSessionService.activatedDetailedCapture.proof$.subscribe( proof => { if (proof) { this.proofRepository.remove(proof); - /** - * WORKAROUND: https://github.com/numbersprotocol/capture-lite/issues/3050 - * After certain network actions we need to navigate user back to - * home page. We could not achieve this with this.router.navigate(['/home']); - * therefore we need to use `popstate` navigationTrigger. - */ - this.navController.back(); // goes back to Actions page - this.navController.back(); // goes back to Details page - this.navController.back(); // goes back to Home page + this.navController.navigateRoot('/home', { + animationDirection: 'back', + }); } } ); From 077c71ef8f188bbceb4a8622a7068802174aa6f0 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Tue, 31 Oct 2023 13:39:04 +0800 Subject: [PATCH 25/28] fix(signup.page): show correct error message for duplicate username --- src/app/features/signup/signup.page.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/features/signup/signup.page.ts b/src/app/features/signup/signup.page.ts index cacf3155e..912d1564c 100644 --- a/src/app/features/signup/signup.page.ts +++ b/src/app/features/signup/signup.page.ts @@ -242,7 +242,7 @@ export class SignupPage { } if ( err instanceof HttpErrorResponse && - err.error.error?.details?.username?.length > 0 + err.error.error?.type === 'duplicate_username' ) { return this.errorService.toastError$( this.translocoService.translate('error.diaBackend.duplicate_username') From 00217399500eb9d0eaefd7a01ff1294f3e4a70d0 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Wed, 1 Nov 2023 18:10:31 +0800 Subject: [PATCH 26/28] chore: bump app version to 0.86.4 --- android/app/build.gradle | 4 ++-- ios/App/App.xcodeproj/project.pbxproj | 8 ++++---- package-lock.json | 4 ++-- package.json | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index b1b0349b7..6c3829b6f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "io.numbersprotocol.capturelite" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 852 - versionName "0.85.2" + versionCode 864 + versionName "0.86.4" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildFeatures { diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj index e017aef5e..4182af3ed 100644 --- a/ios/App/App.xcodeproj/project.pbxproj +++ b/ios/App/App.xcodeproj/project.pbxproj @@ -368,13 +368,13 @@ CODE_SIGN_ENTITLEMENTS = App/App.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 852; + CURRENT_PROJECT_VERSION = 864; DEVELOPMENT_TEAM = G7NB5YCKAP; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = G7NB5YCKAP; INFOPLIST_FILE = App/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 0.85.2; + MARKETING_VERSION = 0.86.4; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = io.numbersprotocol.capturelite; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -395,13 +395,13 @@ CODE_SIGN_ENTITLEMENTS = App/App.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 852; + CURRENT_PROJECT_VERSION = 864; DEVELOPMENT_TEAM = G7NB5YCKAP; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = G7NB5YCKAP; INFOPLIST_FILE = App/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.6; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 0.85.2; + MARKETING_VERSION = 0.86.4; PRODUCT_BUNDLE_IDENTIFIER = io.numbersprotocol.capturelite; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = NumbersAppDistributionV4; diff --git a/package-lock.json b/package-lock.json index 7c1f88f37..e7e6d619b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "capture-lite", - "version": "0.85.2", + "version": "0.86.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "capture-lite", - "version": "0.85.2", + "version": "0.86.4", "dependencies": { "packages": "^0.0.8", "@angular/animations": "^14.2.0", diff --git a/package.json b/package.json index 761806214..9b1459cc0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "capture-lite", - "version": "0.85.2", + "version": "0.86.4", "author": "numbersprotocol", "homepage": "https://numbersprotocol.io/", "scripts": { From 2302c9bd7f68cb42b3f919b7dad93e4fa7fa513e Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Wed, 1 Nov 2023 18:11:07 +0800 Subject: [PATCH 27/28] chore: update CHANGELOG.md for 0.86.4 --- CHANGELOG.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d94a94c6..c7824fa62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.86.4] - 2023-11-11 + +### Added + +1. Feature newtork app ui update (#3073) +1. Feature Update instructions about the upload size limitation (#3074) +1. Feature fit figma profile page tab (#3075) + +### Fixed + +1. Fix Issue When user registers the account but user inputs the existing name the error message is wrong (#3076) + ## [0.85.2] - 2023-09-21 ### Added @@ -2201,7 +2213,8 @@ This is the first release! _Capture Lite_ is a cross-platform app adapted from [ - Web - see the demo [here](https://github.com/numbersprotocol/capture-lite#demo-app) - Android - the APK file `app-debug.apk` is attached to this release -[unreleased]: https://github.com/numbersprotocol/capture-lite/compare/0.85.2...HEAD +[unreleased]: https://github.com/numbersprotocol/capture-lite/compare/0.86.4...HEAD +[0.86.4]: https://github.com/numbersprotocol/capture-lite/compare/0.83.2...0.86.4 [0.83.2]: https://github.com/numbersprotocol/capture-lite/compare/0.82.4...0.85.2 [0.82.4]: https://github.com/numbersprotocol/capture-lite/compare/0.82.4...0.83.2 [0.82.4]: https://github.com/numbersprotocol/capture-lite/compare/0.82.3...0.82.4 From 16490fbe18917a4613cd9f9aa2b8d377950ecca6 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Wed, 1 Nov 2023 19:37:17 +0800 Subject: [PATCH 28/28] fix: set iOS provisioning profile to NumbersAppDistributionV5 --- ios/App/App.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj index e017aef5e..75df961c9 100644 --- a/ios/App/App.xcodeproj/project.pbxproj +++ b/ios/App/App.xcodeproj/project.pbxproj @@ -379,7 +379,7 @@ PRODUCT_BUNDLE_IDENTIFIER = io.numbersprotocol.capturelite; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = NumbersAppDistributionV4; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = NumbersAppDistributionV4; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = NumbersAppDistributionV5; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -405,7 +405,7 @@ PRODUCT_BUNDLE_IDENTIFIER = io.numbersprotocol.capturelite; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = NumbersAppDistributionV4; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = NumbersAppDistributionV4; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = NumbersAppDistributionV5; SWIFT_ACTIVE_COMPILATION_CONDITIONS = ""; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2";