From 2d964e97865304b07e38abe31e1fe2f6d5d14c31 Mon Sep 17 00:00:00 2001 From: SondreB Date: Sat, 29 Apr 2023 14:33:15 +0200 Subject: [PATCH 01/12] WIP: New state management for abstracting services and UI --- src/app/app.html | 4 ++-- src/app/development/development.html | 19 ++++++++++++++++++- src/app/development/development.ts | 6 +++++- src/app/services/state.ts | 28 ++++++++++++++-------------- 4 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/app/app.html b/src/app/app.html index 03fb368..6f8873a 100644 --- a/src/app/app.html +++ b/src/app/app.html @@ -107,10 +107,10 @@ bookmarks {{ 'App.Bookmarks' | translate }} - + dns {{ 'App.Relays' | translate }} diff --git a/src/app/development/development.html b/src/app/development/development.html index 73a470b..3635135 100644 --- a/src/app/development/development.html +++ b/src/app/development/development.html @@ -1,4 +1,21 @@
+

State Service Management

+ + +
Metadata
+ + folder +
{{state.key}}
+
{{state.value.content}}
+
+ +
+ + State as JSON:
+ {{ state | json }} + +

+

This page act as examples for more specialized implementation details of the app.

@@ -21,4 +38,4 @@ -
\ No newline at end of file + diff --git a/src/app/development/development.ts b/src/app/development/development.ts index 99e1fd1..a1551f9 100644 --- a/src/app/development/development.ts +++ b/src/app/development/development.ts @@ -5,6 +5,7 @@ import { NostrService } from '../services/nostr'; import { RelayService } from '../services/relay'; import { RelayType } from '../types/relay'; import { Storage } from '../types/storage'; +import { State, StateService } from '../services/state'; @Component({ selector: 'app-development', @@ -15,10 +16,13 @@ export class DevelopmentComponent { worker?: Worker; storage?: Storage; - constructor(private nostr: NostrService, private dataService: DataService, private appState: ApplicationState, public relayService: RelayService) {} + constructor( + public state: State, + private nostr: NostrService, private dataService: DataService, private appState: ApplicationState, public relayService: RelayService) {} ngOnInit() { this.appState.updateTitle('Development & Debug'); + } async database() { diff --git a/src/app/services/state.ts b/src/app/services/state.ts index 8326272..846bfc8 100644 --- a/src/app/services/state.ts +++ b/src/app/services/state.ts @@ -10,14 +10,14 @@ export class StateService { addEvent(event: NostrEvent) { // TODO: Temporarily removed to avoid building massive in-memory state. - // switch (event.kind) { - // case Kind.Metadata: - // this.addIfNewer(event, this.state.events.shortTextNote); - // break; - // case Kind.Text: - // this.addIfMissing(event, this.state.events.shortTextNote); - // break; - // } + switch (event.kind) { + case Kind.Metadata: + this.addIfNewer(event, event.pubkey, this.state.events.metadata); + break; + case Kind.Text: + this.addIfMissing(event, this.state.events.shortTextNote); + break; + } } addIfMissing(event: NostrEvent, map: Map) { @@ -28,17 +28,17 @@ export class StateService { map.set(event.id, event); } - addIfNewer(event: NostrEvent, map: Map) { - if (!map.has(event.id)) { - map.set(event.id, event); + addIfNewer(event: NostrEvent, identifier: string, map: Map) { + if (!map.has(identifier)) { + map.set(identifier, event); } else { - const existing = map.get(event.id); + const existing = map.get(identifier); - if (existing!.created_at > event.created_at) { + if (existing!.created_at >= event.created_at) { return; } - map.set(event.id, event); + map.set(identifier, event); } } } From f19123c2cfef961973cdf739bbcf5b0d2dcc6236 Mon Sep 17 00:00:00 2001 From: missmeowness Date: Tue, 2 May 2023 18:04:08 +0300 Subject: [PATCH 02/12] add handling of more event types --- src/app/development/development.html | 32 ++++++++++++++++++++++++++++ src/app/services/state.ts | 5 +++++ 2 files changed, 37 insertions(+) diff --git a/src/app/development/development.html b/src/app/development/development.html index 3635135..f6e712f 100644 --- a/src/app/development/development.html +++ b/src/app/development/development.html @@ -11,6 +11,38 @@ + +
Text
+ + folder +
{{state.key}}
+
{{state.value.content}}
+
+ +
+ + +
Contacts
+ + folder +
{{state.key}}
+
{{state.value.content}}
+
+ +
+ + +
Reactions
+ + folder +
{{state.key}}
+
{{state.value.content}}
+
+ +
+ + + State as JSON:
{{ state | json }} diff --git a/src/app/services/state.ts b/src/app/services/state.ts index 846bfc8..24ada75 100644 --- a/src/app/services/state.ts +++ b/src/app/services/state.ts @@ -17,6 +17,11 @@ export class StateService { case Kind.Text: this.addIfMissing(event, this.state.events.shortTextNote); break; + case Kind.Contacts: + this.addIfNewer(event, event.pubkey, this.state.events.contacts); + break; + case Kind.Reaction: + this.addIfNewer(event, event.content, this.state.events.reaction) } } From ca31c46f002d0f61ff5a2b62c08acf466c05631b Mon Sep 17 00:00:00 2001 From: missmeowness Date: Tue, 2 May 2023 18:34:11 +0300 Subject: [PATCH 03/12] set metadata for loged in user --- src/app/app.ts | 7 +++++-- src/app/services/state.ts | 10 +++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/app/app.ts b/src/app/app.ts index 5289b53..c74892d 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -27,6 +27,7 @@ import { OptionsService } from './services/options'; import { LabelService } from './services/label'; import { TranslateService } from '@ngx-translate/core'; import { BadgeService } from './services/badge'; +import { State } from './services/state'; @Component({ selector: 'app-root', @@ -66,7 +67,8 @@ export class AppComponent { public ui: UIService, private bottomSheet: MatBottomSheet, public searchService: SearchService, - public theme: ThemeService + public theme: ThemeService, + private state: State ) { if (!this.visibilityHandler) { this.visibilityHandler = addEventListener('visibilitychange', (event) => { @@ -96,7 +98,8 @@ export class AppComponent { } this.authService.authInfo$.subscribe(async (auth) => { - auth.publicKeyHex; + this.state.pubkey = auth.publicKeyHex; + this.authenticated = auth.authenticated(); diff --git a/src/app/services/state.ts b/src/app/services/state.ts index 24ada75..15df2fb 100644 --- a/src/app/services/state.ts +++ b/src/app/services/state.ts @@ -13,6 +13,9 @@ export class StateService { switch (event.kind) { case Kind.Metadata: this.addIfNewer(event, event.pubkey, this.state.events.metadata); + if (this.state.pubkey == event.pubkey) { + this.state.metadata = event; + } break; case Kind.Text: this.addIfMissing(event, this.state.events.shortTextNote); @@ -21,7 +24,8 @@ export class StateService { this.addIfNewer(event, event.pubkey, this.state.events.contacts); break; case Kind.Reaction: - this.addIfNewer(event, event.content, this.state.events.reaction) + this.addIfNewer(event, event.content, this.state.events.reaction); + break; } } @@ -56,6 +60,10 @@ export class State { circles: Circle[] = []; + metadata?: NostrEvent; + + pubkey?: String; + events: EventsState = { metadata: new Map(), shortTextNote: new Map(), From 6313a7d48a763a43e6c07f6f04ecae4f6051c739 Mon Sep 17 00:00:00 2001 From: SondreB Date: Tue, 2 May 2023 17:58:11 +0200 Subject: [PATCH 04/12] Add example page for demonstrate implementations --- src/app/app-routing.module.ts | 11 ++++++++++- src/app/app.html | 4 ++++ src/app/example/example.html | 7 +++++++ src/app/example/example.ts | 14 ++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 src/app/example/example.html create mode 100644 src/app/example/example.ts diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 2942a28..d4fd7af 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -33,6 +33,7 @@ import { LoginComponent } from './connect/login/login'; import { CreateProfileComponent } from './connect/create/create'; import { EditorBadgesComponent } from './editor-badges/editor'; import { BadgeComponent } from './badge/badge'; +import { ExampleComponent } from './example/example'; const routes: Routes = [ { @@ -245,7 +246,7 @@ const routes: Routes = [ }, { path: 'about', - loadChildren: () => import('./about/about.module').then(m => m.AboutModule) + loadChildren: () => import('./about/about.module').then((m) => m.AboutModule), // component: AboutComponent, // canActivate: [AuthGuard], // resolve: { @@ -284,6 +285,14 @@ const routes: Routes = [ data: LoadingResolverService, }, }, + { + path: 'example', + component: ExampleComponent, + canActivate: [AuthGuard], + resolve: { + data: LoadingResolverService, + }, + }, { path: 'queue', component: QueueComponent, diff --git a/src/app/app.html b/src/app/app.html index 6f8873a..13aaa09 100644 --- a/src/app/app.html +++ b/src/app/app.html @@ -111,6 +111,10 @@ construction Development
+ + construction + Example + dns {{ 'App.Relays' | translate }} diff --git a/src/app/example/example.html b/src/app/example/example.html new file mode 100644 index 0000000..ccfc437 --- /dev/null +++ b/src/app/example/example.html @@ -0,0 +1,7 @@ +
+

This example demonstrates how to do sorting, filtering, virtual scrolling, dynamic updates of complex data within Blockcore Notes.

+
+ +
+ +
\ No newline at end of file diff --git a/src/app/example/example.ts b/src/app/example/example.ts new file mode 100644 index 0000000..7c13fce --- /dev/null +++ b/src/app/example/example.ts @@ -0,0 +1,14 @@ +import { Component, OnInit } from '@angular/core'; +import { ApplicationState } from '../services/applicationstate'; + +@Component({ + selector: 'app-example', + templateUrl: 'example.html', +}) +export class ExampleComponent implements OnInit { + constructor(private appState: ApplicationState) {} + + ngOnInit() { + this.appState.updateTitle('Example'); + } +} From cae47b192f0892393c443eb1e4528d1e289c59a2 Mon Sep 17 00:00:00 2001 From: missmeowness Date: Tue, 2 May 2023 19:23:20 +0300 Subject: [PATCH 05/12] Added article support --- src/app/app.ts | 4 ++- src/app/development/development.html | 40 ++++++++++++++++++++++++++++ src/app/services/state.ts | 36 +++++++++++++++++++++++-- 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/src/app/app.ts b/src/app/app.ts index c74892d..d326b2e 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -28,6 +28,7 @@ import { LabelService } from './services/label'; import { TranslateService } from '@ngx-translate/core'; import { BadgeService } from './services/badge'; import { State } from './services/state'; +import { EventService } from './services/event'; @Component({ selector: 'app-root', @@ -68,7 +69,8 @@ export class AppComponent { private bottomSheet: MatBottomSheet, public searchService: SearchService, public theme: ThemeService, - private state: State + private state: State, + private eventService: EventService ) { if (!this.visibilityHandler) { this.visibilityHandler = addEventListener('visibilitychange', (event) => { diff --git a/src/app/development/development.html b/src/app/development/development.html index f6e712f..fde9019 100644 --- a/src/app/development/development.html +++ b/src/app/development/development.html @@ -40,6 +40,46 @@ + + +
Reposts
+ + folder +
{{state.key}}
+
{{state.value.content}}
+
+ +
+ + +
Zap
+ + folder +
{{state.key}}
+
{{state.value.content}}
+
+ +
+ + +
Zap Request
+ + folder +
{{state.key}}
+
{{state.value.content}}
+
+ +
+ + +
Article
+ + folder +
{{state.key}}
+
{{state.value.content}}
+
+ +
diff --git a/src/app/services/state.ts b/src/app/services/state.ts index 15df2fb..270448d 100644 --- a/src/app/services/state.ts +++ b/src/app/services/state.ts @@ -10,7 +10,7 @@ export class StateService { addEvent(event: NostrEvent) { // TODO: Temporarily removed to avoid building massive in-memory state. - switch (event.kind) { + switch (event.kind as any) { case Kind.Metadata: this.addIfNewer(event, event.pubkey, this.state.events.metadata); if (this.state.pubkey == event.pubkey) { @@ -24,11 +24,43 @@ export class StateService { this.addIfNewer(event, event.pubkey, this.state.events.contacts); break; case Kind.Reaction: - this.addIfNewer(event, event.content, this.state.events.reaction); + this.addIfMissing(event, this.state.events.reaction); + break; + case 6: + this.addIfMissing(event, this.state.events.reposts); + break; + case Kind.Zap: + this.addIfMissing(event, this.state.events.zap); + break; + case Kind.ZapRequest: + this.addIfMissing(event, this.state.events.zapRequest); + break; + case Kind.Article: + const slug = this.firstDTag(event); + this.addIfNewer(event, slug!, this.state.events.longFormContent); break; } } + tagsOfType(event: NostrEvent | null, type: string) { + if (!event) { + return []; + } + + const tags = event.tags.filter((t) => t[0] === type); + return tags; + } + + firstDTag(event: NostrEvent | null | any) { + const tags = this.tagsOfType(event, 'd'); + + if (tags.length == 0) { + return undefined; + } + + return tags[0][1]; + } + addIfMissing(event: NostrEvent, map: Map) { if (map.has(event.id)) { return; From 4febc23d48f03909b2b2c76758783dc287841693 Mon Sep 17 00:00:00 2001 From: SondreB Date: Tue, 2 May 2023 19:10:42 +0200 Subject: [PATCH 06/12] Add some virtual scroll example --- src/app/app.module.ts | 2 ++ src/app/example/example.css | 19 ++++++++++++++++ src/app/example/example.html | 13 +++++++---- src/app/example/example.ts | 42 ++++++++++++++++++++++++++++++++++-- 4 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 src/app/example/example.css diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 9367d34..7b254da 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -153,6 +153,7 @@ import { BadgeComponent } from './badge/badge'; import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field'; import { DragScrollModule } from 'ngx-drag-scroll'; import { ZappersListDialogComponent } from './shared/zappers-list-dialog/zappers-list-dialog.component'; +import { ExampleComponent } from './example/example'; @NgModule({ declarations: [ AppComponent, @@ -244,6 +245,7 @@ import { ZappersListDialogComponent } from './shared/zappers-list-dialog/zappers TagsComponent, BadgeComponent, ZappersListDialogComponent, + ExampleComponent ], imports: [ HttpClientModule, diff --git a/src/app/example/example.css b/src/app/example/example.css new file mode 100644 index 0000000..bab7df6 --- /dev/null +++ b/src/app/example/example.css @@ -0,0 +1,19 @@ +.example-viewport { + height: 100%; + min-height: 500px; + width: 100%; + border: 1px solid black; +} + +.example-item { + box-sizing: border-box; + height: 200px; + background-color: purple; +} + +.example-item-content { + overflow: scroll; + width: 100%; + height: 100px; + border: 1px solid green; +} \ No newline at end of file diff --git a/src/app/example/example.html b/src/app/example/example.html index ccfc437..49b9e19 100644 --- a/src/app/example/example.html +++ b/src/app/example/example.html @@ -1,7 +1,12 @@

This example demonstrates how to do sorting, filtering, virtual scrolling, dynamic updates of complex data within Blockcore Notes.

+ + +
+ + {{item.value.id}} + +
{{item.value.content}}
+
+
- -
- -
\ No newline at end of file diff --git a/src/app/example/example.ts b/src/app/example/example.ts index 7c13fce..e45eebc 100644 --- a/src/app/example/example.ts +++ b/src/app/example/example.ts @@ -1,14 +1,52 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { ApplicationState } from '../services/applicationstate'; +import { State } from '../services/state'; @Component({ selector: 'app-example', templateUrl: 'example.html', + styleUrls: ['example.css'], + // changeDetection: ChangeDetectionStrategy.OnPush, }) export class ExampleComponent implements OnInit { - constructor(private appState: ApplicationState) {} + @ViewChild('scrollViewport') + private cdkVirtualScrollViewport: any; + + items = Array.from({ length: 10000 }).map((_, i) => `Item #${i + 1}`); + + constructor(public state: State, private appState: ApplicationState) {} ngOnInit() { this.appState.updateTitle('Example'); } + + calculateContainerHeight(): string { + const numberOfItems = this.items.length; + // This should be the height of your item in pixels + const itemHeight = 20; + // The final number of items you want to keep visible + const visibleItems = 10; + + setTimeout(() => { + // Makes CdkVirtualScrollViewport to refresh its internal size values after + // changing the container height. This should be delayed with a "setTimeout" + // because we want it to be executed after the container has effectively + // changed its height. Another option would be a resize listener for the + // container and call this line there but it may requires a library to detect + // the resize event. + + this.cdkVirtualScrollViewport.checkViewportSize(); + }, 300); + + // It calculates the container height for the first items in the list + // It means the container will expand until it reaches `200px` (20 * 10) + // and will keep this size. + if (numberOfItems <= visibleItems) { + return `${itemHeight * numberOfItems}px`; + } + + // This function is called from the template so it ensures the container will have + // the final height if number of items are greater than the value in "visibleItems". + return `${itemHeight * visibleItems}px`; + } } From 1d289f5dabaa1b607ebd96b44fcbd70da0c9ba5e Mon Sep 17 00:00:00 2001 From: SondreB Date: Fri, 12 May 2023 11:07:16 +0200 Subject: [PATCH 07/12] Add selection of circles on feed page for filtering - WIP: The data loading needs to be improved, as the behavior of the circle selection is not always as expected. --- src/app/feed-private/feed-private.css | 4 +++- src/app/feed-private/feed-private.html | 7 +++++++ src/app/feed-private/feed-private.ts | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/app/feed-private/feed-private.css b/src/app/feed-private/feed-private.css index 548f6e2..1b3d65c 100644 --- a/src/app/feed-private/feed-private.css +++ b/src/app/feed-private/feed-private.css @@ -1,4 +1,3 @@ - .loading-container { text-align: center; } @@ -7,3 +6,6 @@ margin: auto; } +.circle-selection { + margin-bottom: 1em; +} diff --git a/src/app/feed-private/feed-private.html b/src/app/feed-private/feed-private.html index 8def86c..482390c 100644 --- a/src/app/feed-private/feed-private.html +++ b/src/app/feed-private/feed-private.html @@ -12,6 +12,13 @@ -->
+ + + + trip_origin + + + diff --git a/src/app/feed-private/feed-private.ts b/src/app/feed-private/feed-private.ts index c99c4e1..2594b5f 100644 --- a/src/app/feed-private/feed-private.ts +++ b/src/app/feed-private/feed-private.ts @@ -13,6 +13,7 @@ import { MatSnackBar } from '@angular/material/snack-bar'; import { StorageService } from '../services/storage'; import { dexieToRx } from '../shared/utilities'; import { UIService } from '../services/ui'; +import { CircleService } from '../services/circle'; @Component({ selector: 'app-feed-private', @@ -42,6 +43,7 @@ export class FeedPrivateComponent { // } constructor( + public circleService: CircleService, public ui: UIService, private activatedRoute: ActivatedRoute, public db: StorageService, From f93fbb3a0eb0d7c63325039de811ad13fe5bd351 Mon Sep 17 00:00:00 2001 From: SondreB Date: Fri, 12 May 2023 11:17:05 +0200 Subject: [PATCH 08/12] Temporarily disable new state management --- src/app/app.html | 4 ++-- src/app/services/state.ts | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app/app.html b/src/app/app.html index 13aaa09..a3b5ea8 100644 --- a/src/app/app.html +++ b/src/app/app.html @@ -107,14 +107,14 @@ bookmarks {{ 'App.Bookmarks' | translate }} - + dns {{ 'App.Relays' | translate }} diff --git a/src/app/services/state.ts b/src/app/services/state.ts index 270448d..aff88e5 100644 --- a/src/app/services/state.ts +++ b/src/app/services/state.ts @@ -9,6 +9,8 @@ export class StateService { constructor(private state: State) {} addEvent(event: NostrEvent) { + return; + // TODO: Temporarily removed to avoid building massive in-memory state. switch (event.kind as any) { case Kind.Metadata: From ab70afbf599ef10622382112fbe05d3a9a9eb1bd Mon Sep 17 00:00:00 2001 From: missmeowness Date: Fri, 12 May 2023 13:02:23 +0300 Subject: [PATCH 09/12] Update following.html --- src/app/following/following.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/following/following.html b/src/app/following/following.html index 0fff36d..83304e8 100644 --- a/src/app/following/following.html +++ b/src/app/following/following.html @@ -7,7 +7,8 @@ - + +