diff --git a/LICENSE b/LICENSE deleted file mode 100644 index dc06b413..00000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2018 Nicolas Constant - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/src/app/components/stream/status/status.component.html b/src/app/components/stream/status/status.component.html index 024746ea..5a189ed6 100644 --- a/src/app/components/stream/status/status.component.html +++ b/src/app/components/stream/status/status.component.html @@ -1,5 +1,9 @@ -
- - @ -
-
\ No newline at end of file +
+ + + + @{{status.account.acct}} + +
{{ getCompactRelativeTime(status.created_at) }}
+
+
\ No newline at end of file diff --git a/src/app/components/stream/status/status.component.scss b/src/app/components/stream/status/status.component.scss index 20278222..aebb10d8 100644 --- a/src/app/components/stream/status/status.component.scss +++ b/src/app/components/stream/status/status.component.scss @@ -1,47 +1,56 @@ -.toot { - border: solid #06070b; - border-width: 0 0 1px 0; +@import "variables"; +.status { margin: 0; padding: 0; width: calc(100%); min-height: 70px; overflow: hidden; + position: relative; &__avatar { - margin: 10px 0 0 10px; + position: absolute; + top: 10px; + left: 10px; // margin: 10px 0 0 10px; /* margin: 0; */ width: 50px; - height: 50px; - float: left; + height: 50px; // float: left; + border-radius: 2px; } &__fullname { - color: white; + display: block; + color: $status-primary-color; } &__profile-link { - color: #353e64; + color: $status-secondary-color; margin: 7px 0 0 70px; display: block; + text-decoration: none; + overflow: hidden; } &__content { /*width: calc(100% - 50px);*/ - margin: 10px 10px 10px 70px; + margin: 0px 10px 10px 70px; } &__content p { margin: 0; font-size: 0.85em; } + &__created-at { + color: $status-secondary-color; + position: absolute; + top: 5px; + right: 10px; + } } -// #toot-avatar img { -// width: 50px; -// height: 50px; -// border-radius: 2px; -// margin: 0; -// } -/* #toot-username { - color: grey; -} */ - -/* ::ng-deep .invisible { - display: inline; - color: red; -} */ \ No newline at end of file +//Mastodon styling +:host ::ng-deep .status__content { + color: $status-primary-color; + & a, + .mention, + .ellipsis { + color: $status-links-color; + } + & .invisible { + display: none; + } +} \ No newline at end of file diff --git a/src/app/components/stream/status/status.component.ts b/src/app/components/stream/status/status.component.ts index 3a4c9304..34d2b6d4 100644 --- a/src/app/components/stream/status/status.component.ts +++ b/src/app/components/stream/status/status.component.ts @@ -1,18 +1,36 @@ -import { Component, OnInit, Input } from "@angular/core"; +import { Component, OnInit, Input, Inject, LOCALE_ID } from "@angular/core"; import { Status } from "../../../services/models/mastodon.interfaces"; +import { formatDate } from '@angular/common'; @Component({ - selector: "app-status", - templateUrl: "./status.component.html", - styleUrls: ["./status.component.scss"] + selector: "app-status", + templateUrl: "./status.component.html", + styleUrls: ["./status.component.scss"] }) export class StatusComponent implements OnInit { - @Input() status: Status; + @Input() status: Status; - constructor() { } + constructor(@Inject(LOCALE_ID) private locale: string) { } - ngOnInit() { - } + ngOnInit() { + } + getCompactRelativeTime(d: string): string { + const date = (new Date(d)).getTime(); + const now = Date.now(); + const timeDelta = (now - date) / (1000); + + if (timeDelta < 60) { + return `${timeDelta | 0}s`; + } else if (timeDelta < 60 * 60) { + return `${timeDelta / 60 | 0}m`; + } else if (timeDelta < 60 * 60 * 24) { + return `${timeDelta / (60 * 60)| 0}h`; + } else if (timeDelta < 60 * 60 * 24 * 31) { + return `${timeDelta / (60 * 60 * 24) | 0}d`; + } + + return formatDate(date, 'MM/dd', this.locale); + } } diff --git a/src/app/components/stream/stream.component.html b/src/app/components/stream/stream.component.html index 884b57dd..fbfd0357 100644 --- a/src/app/components/stream/stream.component.html +++ b/src/app/components/stream/stream.component.html @@ -3,7 +3,7 @@

{{ streamElement.name.toUpperCase() }}

-
+
diff --git a/src/app/components/stream/stream.component.scss b/src/app/components/stream/stream.component.scss index 7e52b612..a179cc8d 100644 --- a/src/app/components/stream/stream.component.scss +++ b/src/app/components/stream/stream.component.scss @@ -1,33 +1,32 @@ @import "variables"; .stream-column { - width: $stream-column-width; - height: calc(100%); - - background-color: #0f111a; - margin: 0 0 0 $stream-column-separator; - - &__stream-header { - width: calc(100%); - height: 30px; - - background-color: black; - - border-bottom: 1px solid black; - - & h1 { - color: whitesmoke; - font-size: 0.8em; - font-weight: normal; - margin: 0; - padding: 8px 0 0 10px; + width: $stream-column-width; + height: calc(100%); + background-color: #0f111a; + margin: 0 0 0 $stream-column-separator; + &__stream-header { + width: calc(100%); + height: 30px; + background-color: black; + border-bottom: 1px solid black; + & h1 { + color: whitesmoke; + font-size: 0.8em; + font-weight: normal; + margin: 0; + padding: 8px 0 0 10px; + } } - } } .stream-toots { - height: calc(100% - 30px); - width: 320px; - overflow: auto; + height: calc(100% - 30px); + width: 320px; + overflow: auto; + &__status:not(:last-child) { + border: solid #06070b; + border-width: 0 0 1px 0; + } } .flexcroll { diff --git a/src/app/components/stream/stream.component.ts b/src/app/components/stream/stream.component.ts index 3df37602..bb1d433d 100644 --- a/src/app/components/stream/stream.component.ts +++ b/src/app/components/stream/stream.component.ts @@ -18,6 +18,8 @@ export class StreamComponent implements OnInit { private websocketStreaming: StreamingWrapper; statuses: Status[] = []; + private bufferStream: Status[] = []; + private bufferWasCleared: boolean; @Input() set streamElement(streamElement: StreamElement) { @@ -28,7 +30,7 @@ export class StreamComponent implements OnInit { const instance = splitedUserName[1]; this.account = this.getRegisteredAccounts().find(x => x.username == user && x.instance == instance); - this.retrieveToots(); //TODO change this for WebSockets + this.retrieveToots(); this.launchWebsocket(); } @@ -47,6 +49,10 @@ export class StreamComponent implements OnInit { @ViewChild('statusstream') public statustream: ElementRef; goToTop(): boolean { + this.loadBuffer(); + if (this.statuses.length > 40) { + this.statuses.length = 40; + } const stream = this.statustream.nativeElement as HTMLElement; stream.scrollTo({ top: 0, @@ -56,25 +62,58 @@ export class StreamComponent implements OnInit { } private streamPositionnedAtTop: boolean = true; - private streamPositionnedAtBottom: boolean; + private isProcessingInfiniteScroll: boolean; onScroll() { var element = this.statustream.nativeElement as HTMLElement; - const atBottom = element.scrollHeight - element.scrollTop === element.clientHeight; + const atBottom = element.scrollHeight <= element.clientHeight + element.scrollTop + 500; const atTop = element.scrollTop === 0; this.streamPositionnedAtTop = false; - this.streamPositionnedAtBottom = false; - - if (atBottom) { - console.log('Bottom reached!!'); - this.streamPositionnedAtBottom = true; + if (atBottom && !this.isProcessingInfiniteScroll) { + this.scrolledToBottom(); } else if (atTop) { - console.log('Top reached!!'); - this.streamPositionnedAtTop = true; + this.scrolledToTop(); } } + private scrolledToTop() { + this.streamPositionnedAtTop = true; + + this.loadBuffer(); + } + + private loadBuffer(){ + if(this.bufferWasCleared) { + this.statuses.length = 0; + this.bufferWasCleared = false; + } + + for (const status of this.bufferStream) { + this.statuses.unshift(status); + } + + this.bufferStream.length = 0; + } + + private scrolledToBottom() { + this.isProcessingInfiniteScroll = true; + + const lastStatus = this.statuses[this.statuses.length - 1]; + this.mastodonService.getTimeline(this.account, this._streamElement.type, lastStatus.id) + .then((status: Status[]) => { + for (const s of status) { + this.statuses.push(s); + } + }) + .catch(err => { + console.error(err); + }) + .then(() => { + this.isProcessingInfiniteScroll = false; + }); + } + private getRegisteredAccounts(): AccountInfo[] { var regAccounts = this.store.snapshot().registeredaccounts.accounts; return regAccounts; @@ -95,7 +134,11 @@ export class StreamComponent implements OnInit { if (update) { if (update.type === EventEnum.update) { if (!this.statuses.find(x => x.id == update.status.id)) { - this.statuses.unshift(update.status); + if (this.streamPositionnedAtTop) { + this.statuses.unshift(update.status); + } else { + this.bufferStream.push(update.status); + } } } } @@ -104,11 +147,16 @@ export class StreamComponent implements OnInit { }); } + private checkAndCleanUpStream(): void { if (this.streamPositionnedAtTop && this.statuses.length > 60) { - console.log(`clean up start! ${this.statuses.length}`); this.statuses.length = 40; - console.log(`clean up ends! ${this.statuses.length}`); + } + + if (this.bufferStream.length > 60) { + this.bufferWasCleared = true; + this.bufferStream.length = 40; + } } } \ No newline at end of file diff --git a/src/sass/_variables.scss b/src/sass/_variables.scss index 29797028..370d9515 100644 --- a/src/sass/_variables.scss +++ b/src/sass/_variables.scss @@ -10,6 +10,11 @@ $color-secondary: #090b10; $default-font-size: 15px; $small-font-size: 12px; +$status-primary-color: #fff; +$status-secondary-color: #353e64; +$status-secondary-color: #4e5572; +$status-links-color: #d9e1e8; + // Block dispositions $stream-selector-height: 30px; diff --git a/src/sass/styles.scss b/src/sass/styles.scss index 524815e2..c39de373 100644 --- a/src/sass/styles.scss +++ b/src/sass/styles.scss @@ -28,16 +28,16 @@ html, body { background-color: $color-primary; } - .invisible { - display: none; - } +// .invisible { +// display: none; +// } /* .ellipsis { } */ - #toot-content p { - margin-bottom: 0 !important; - } +// #toot-content p { +// margin-bottom: 0 !important; +// } - #toot-content a { - color: #bec3d8; - } \ No newline at end of file +// #toot-content a { +// color: #bec3d8; +// } \ No newline at end of file