Merge pull request #262 from NicolasConstant/topic_enhance-timelines
Topic enhance timelines
This commit is contained in:
commit
f1ec2a9068
|
@ -7,6 +7,7 @@ import { FavoriteResult, BookmarkResult } from '../../../../services/mastodon.se
|
|||
import { MastodonWrapperService } from '../../../../services/mastodon-wrapper.service';
|
||||
import { Status } from '../../../../services/models/mastodon.interfaces';
|
||||
import { NotificationService } from '../../../../services/notification.service';
|
||||
import { TimeLineModeEnum } from '../../../../states/settings.state';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bookmarks',
|
||||
|
@ -21,6 +22,8 @@ export class BookmarksComponent implements OnInit {
|
|||
hasContentWarnings = false;
|
||||
|
||||
bufferStream: Status[] = []; //html compatibility only
|
||||
streamPositionnedAtTop: boolean = true; //html compatibility only
|
||||
timelineLoadingMode: TimeLineModeEnum = TimeLineModeEnum.OnTop; //html compatibility only
|
||||
|
||||
@Output() browseAccountEvent = new EventEmitter<string>();
|
||||
@Output() browseHashtagEvent = new EventEmitter<string>();
|
||||
|
|
|
@ -7,6 +7,7 @@ import { FavoriteResult } from '../../../../services/mastodon.service';
|
|||
import { MastodonWrapperService } from '../../../../services/mastodon-wrapper.service';
|
||||
import { Status } from '../../../../services/models/mastodon.interfaces';
|
||||
import { NotificationService } from '../../../../services/notification.service';
|
||||
import { TimeLineModeEnum } from '../../../../states/settings.state';
|
||||
|
||||
@Component({
|
||||
selector: 'app-favorites',
|
||||
|
@ -21,6 +22,8 @@ export class FavoritesComponent implements OnInit {
|
|||
hasContentWarnings = false;
|
||||
|
||||
bufferStream: Status[] = []; //html compatibility only
|
||||
streamPositionnedAtTop: boolean = true; //html compatibility only
|
||||
timelineLoadingMode: TimeLineModeEnum = TimeLineModeEnum.OnTop; //html compatibility only
|
||||
|
||||
@Output() browseAccountEvent = new EventEmitter<string>();
|
||||
@Output() browseHashtagEvent = new EventEmitter<string>();
|
||||
|
|
|
@ -8,6 +8,7 @@ import { Status, Notification } from '../../../../services/models/mastodon.inter
|
|||
import { MastodonWrapperService } from '../../../../services/mastodon-wrapper.service';
|
||||
import { NotificationService } from '../../../../services/notification.service';
|
||||
import { OpenThreadEvent, ToolsService } from '../../../../services/tools.service';
|
||||
import { TimeLineModeEnum } from '../../../../states/settings.state';
|
||||
|
||||
|
||||
@Component({
|
||||
|
@ -23,6 +24,8 @@ export class MentionsComponent implements OnInit, OnDestroy {
|
|||
hasContentWarnings = false;
|
||||
|
||||
bufferStream: Status[] = []; //html compatibility only
|
||||
streamPositionnedAtTop: boolean = true; //html compatibility only
|
||||
timelineLoadingMode: TimeLineModeEnum = TimeLineModeEnum.OnTop; //html compatibility only
|
||||
|
||||
@Output() browseAccountEvent = new EventEmitter<string>();
|
||||
@Output() browseHashtagEvent = new EventEmitter<string>();
|
||||
|
|
|
@ -91,15 +91,69 @@
|
|||
[(ngModel)]="setContentHidedCompletely" placeholder="example;other example" />
|
||||
</div>
|
||||
|
||||
<span class="sub-section__title" *ngIf="contentWarningPolicyChanged"><br/>this settings needs a <a href (click)="reload()">reload</a> to be effective.</span>
|
||||
<span class="sub-section__title" *ngIf="contentWarningPolicyChanged"><br />this settings needs a <a href
|
||||
(click)="reload()">reload</a> to be effective.</span>
|
||||
</div>
|
||||
|
||||
<h4 class="panel__subtitle">Timelines</h4>
|
||||
<div class="sub-section">
|
||||
<span class="sub-section__title">header display:</span><br />
|
||||
<input class="sub-section__checkbox" [checked]="timeLineHeader === 1" (change)="onTimeLineHeaderChange(1)"
|
||||
type="radio" name="timelineheader-1" value="timelineheader-1" id="timelineheader-1">
|
||||
<label class="noselect sub-section__label" for="timelineheader-1">Title - Domain Name</label>
|
||||
<br>
|
||||
|
||||
<input class="sub-section__checkbox" [checked]="timeLineHeader === 2" (change)="onTimeLineHeaderChange(2)"
|
||||
type="radio" name="timelineheader-2" value="timelineheader-2" id="timelineheader-2">
|
||||
<label class="noselect sub-section__label" for="timelineheader-2">Title - Username - Domain Name</label>
|
||||
<br>
|
||||
|
||||
<input class="sub-section__checkbox" [checked]="timeLineHeader === 3" (change)="onTimeLineHeaderChange(3)"
|
||||
type="radio" name="timelineheader-3" value="timelineheader-3" id="timelineheader-3">
|
||||
<label class="noselect sub-section__label" for="timelineheader-3">Title - Account Icon - Domain Name</label>
|
||||
<br>
|
||||
|
||||
<input class="sub-section__checkbox" [checked]="timeLineHeader === 4" (change)="onTimeLineHeaderChange(4)"
|
||||
type="radio" name="timelineheader-4" value="timelineheader-4" id="timelineheader-4">
|
||||
<label class="noselect sub-section__label" for="timelineheader-4">Title - Account Icon</label>
|
||||
<br>
|
||||
|
||||
<input class="sub-section__checkbox" [checked]="timeLineHeader === 5" (change)="onTimeLineHeaderChange(5)"
|
||||
type="radio" name="timelineheader-5" value="timelineheader-5" id="timelineheader-5">
|
||||
<label class="noselect sub-section__label" for="timelineheader-5">Title</label>
|
||||
<br>
|
||||
|
||||
<span class="sub-section__title" *ngIf="timeLineHeaderChanged">this settings needs a <a href
|
||||
(click)="reload()">reload</a> to be effective.</span>
|
||||
|
||||
<span class="sub-section__title">loading behavior:</span><br />
|
||||
|
||||
<input class="sub-section__checkbox" [checked]="timeLineMode === 1" (change)="onTimeLineModeChange(1)"
|
||||
type="radio" name="timelinemode-1" value="timelinemode-1" id="timelinemode-1">
|
||||
<label class="noselect sub-section__label" for="timelinemode-1">Load new statuses only on top</label>
|
||||
<br>
|
||||
|
||||
<input class="sub-section__checkbox" [checked]="timeLineMode === 2" (change)="onTimeLineModeChange(2)"
|
||||
type="radio" name="timelinemode-2" value="timelinemode-2" id="timelinemode-2">
|
||||
<label class="noselect sub-section__label" for="timelinemode-2">Continuously loading new statuses</label>
|
||||
<br>
|
||||
|
||||
<input class="sub-section__checkbox" [checked]="timeLineMode === 3" (change)="onTimeLineModeChange(3)"
|
||||
type="radio" name="timelinemode-3" value="timelinemode-3" id="timelinemode-3">
|
||||
<label class="noselect sub-section__label" for="timelinemode-3">Slow mode (manual loading)</label>
|
||||
<br>
|
||||
|
||||
<span class="sub-section__title" *ngIf="timeLineModeChanged">this settings needs a <a href
|
||||
(click)="reload()">reload</a> to be effective.</span>
|
||||
</div>
|
||||
|
||||
<h4 class="panel__subtitle">Other</h4>
|
||||
<div class="sub-section">
|
||||
<input class="sub-section__checkbox" [(ngModel)]="disableRemoteStatusFetchingEnabled"
|
||||
(change)="onDisableRemoteStatusFetchingChanged()" type="checkbox" name="disableRemoteFetching" value="disableRemoteFetching"
|
||||
id="disableRemoteFetching">
|
||||
<label class="noselect sub-section__label" for="disableRemoteFetching">disable remote status fetching</label>
|
||||
(change)="onDisableRemoteStatusFetchingChanged()" type="checkbox" name="disableRemoteFetching"
|
||||
value="disableRemoteFetching" id="disableRemoteFetching">
|
||||
<label class="noselect sub-section__label" for="disableRemoteFetching">disable remote status
|
||||
fetching</label>
|
||||
<br>
|
||||
</div>
|
||||
|
||||
|
@ -128,7 +182,7 @@
|
|||
(click)="cancelClearAll()">
|
||||
Cancel
|
||||
</a>
|
||||
<br/>
|
||||
<br />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,7 @@ import { environment } from '../../../../environments/environment';
|
|||
import { ToolsService } from '../../../services/tools.service';
|
||||
import { UserNotificationService, NotificationSoundDefinition } from '../../../services/user-notification.service';
|
||||
import { ServiceWorkerService } from '../../../services/service-worker.service';
|
||||
import { ContentWarningPolicy, ContentWarningPolicyEnum } from '../../../states/settings.state';
|
||||
import { ContentWarningPolicy, ContentWarningPolicyEnum, TimeLineModeEnum, TimeLineHeaderEnum } from '../../../states/settings.state';
|
||||
|
||||
@Component({
|
||||
selector: 'app-settings',
|
||||
|
@ -29,6 +29,12 @@ export class SettingsComponent implements OnInit {
|
|||
columnShortcutEnabled: ColumnShortcut = ColumnShortcut.Ctrl;
|
||||
columnShortcutChanged = false;
|
||||
|
||||
timeLineHeader: TimeLineHeaderEnum = TimeLineHeaderEnum.Title_DomainName;
|
||||
timeLineHeaderChanged = false;
|
||||
|
||||
timeLineMode: TimeLineModeEnum = TimeLineModeEnum.OnTop;
|
||||
timeLineModeChanged = false;
|
||||
|
||||
contentWarningPolicy: ContentWarningPolicyEnum = ContentWarningPolicyEnum.None;
|
||||
contentWarningPolicyChanged = false;
|
||||
|
||||
|
@ -91,6 +97,9 @@ export class SettingsComponent implements OnInit {
|
|||
this.addCwOnContent = settings.contentWarningPolicy.addCwOnContent.join(';');
|
||||
this.removeCwOnContent = settings.contentWarningPolicy.removeCwOnContent.join(';');
|
||||
this.contentHidedCompletely = settings.contentWarningPolicy.hideCompletlyContent.join(';');
|
||||
|
||||
this.timeLineHeader = settings.timelineHeader;
|
||||
this.timeLineMode = settings.timelineMode;
|
||||
}
|
||||
|
||||
onShortcutChange(id: ColumnShortcut) {
|
||||
|
@ -102,6 +111,24 @@ export class SettingsComponent implements OnInit {
|
|||
this.toolsService.saveSettings(settings);
|
||||
}
|
||||
|
||||
onTimeLineHeaderChange(id: TimeLineHeaderEnum){
|
||||
this.timeLineHeader = id;
|
||||
this.timeLineHeaderChanged = true;
|
||||
|
||||
let settings = this.toolsService.getSettings();
|
||||
settings.timelineHeader = id;
|
||||
this.toolsService.saveSettings(settings);
|
||||
}
|
||||
|
||||
onTimeLineModeChange(id: TimeLineModeEnum){
|
||||
this.timeLineMode = id;
|
||||
this.timeLineModeChanged = true;
|
||||
|
||||
let settings = this.toolsService.getSettings();
|
||||
settings.timelineMode = id;
|
||||
this.toolsService.saveSettings(settings);
|
||||
}
|
||||
|
||||
onCwPolicyChange(id: ContentWarningPolicyEnum) {
|
||||
this.contentWarningPolicy = id;
|
||||
this.contentWarningPolicyChanged = true;
|
||||
|
|
|
@ -6,12 +6,15 @@
|
|||
</div>
|
||||
|
||||
<div class="stream-toots__new-notification"
|
||||
[class.stream-toots__new-notification--display]="bufferStream && bufferStream.length > 0"></div>
|
||||
[class.stream-toots__new-notification--display]="bufferStream && bufferStream.length > 0 && !streamPositionnedAtTop"></div>
|
||||
|
||||
<div class="stream-toots__content flexcroll" #statusstream (scroll)="onScroll()" tabindex="0">
|
||||
<div *ngIf="displayError" class="stream-toots__error">{{displayError}}</div>
|
||||
|
||||
<!-- data-simplebar -->
|
||||
<div *ngIf="timelineLoadingMode === 3 && bufferStream && bufferStream.length > 0">
|
||||
<a href (click)="loadBuffer()" class="stream-toots__load-buffer" title="load new items">{{ bufferStream.length }} new item<span *ngIf="bufferStream.length > 1">s</span></a>
|
||||
</div>
|
||||
|
||||
<div class="stream-toots__status" *ngFor="let statusWrapper of statuses" #status>
|
||||
<app-status
|
||||
[statusWrapper]="statusWrapper" [isThreadDisplay]="isThread"
|
||||
|
|
|
@ -8,6 +8,25 @@
|
|||
overflow: auto;
|
||||
position: relative;
|
||||
|
||||
&__load-buffer {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: inline-block;
|
||||
border-bottom: 1px solid black;
|
||||
padding: 10px;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
// border: 1px dotted greenyellow ;
|
||||
transition: all .2s;
|
||||
color: $status-secondary-color;
|
||||
|
||||
&:hover {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__error {
|
||||
padding: 20px 20px 0 20px;
|
||||
color: rgb(255, 113, 113);
|
||||
|
|
|
@ -11,6 +11,7 @@ import { MastodonWrapperService } from '../../../services/mastodon-wrapper.servi
|
|||
import { NotificationService } from '../../../services/notification.service';
|
||||
import { OpenThreadEvent, ToolsService } from '../../../services/tools.service';
|
||||
import { StatusWrapper } from '../../../models/common.model';
|
||||
import { TimeLineModeEnum } from '../../../states/settings.state';
|
||||
|
||||
@Component({
|
||||
selector: 'app-stream-statuses',
|
||||
|
@ -24,6 +25,8 @@ export class StreamStatusesComponent implements OnInit, OnDestroy {
|
|||
displayError: string;
|
||||
hasContentWarnings = false;
|
||||
|
||||
timelineLoadingMode: TimeLineModeEnum;
|
||||
|
||||
private _streamElement: StreamElement;
|
||||
private account: AccountInfo;
|
||||
private websocketStreaming: StreamingWrapper;
|
||||
|
@ -31,6 +34,8 @@ export class StreamStatusesComponent implements OnInit, OnDestroy {
|
|||
statuses: StatusWrapper[] = [];
|
||||
bufferStream: Status[] = [];
|
||||
private bufferWasCleared: boolean;
|
||||
streamPositionnedAtTop: boolean = true;
|
||||
private isProcessingInfiniteScroll: boolean;
|
||||
|
||||
private hideBoosts: boolean;
|
||||
private hideReplies: boolean;
|
||||
|
@ -75,6 +80,9 @@ export class StreamStatusesComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
ngOnInit() {
|
||||
let settings = this.toolsService.getSettings();
|
||||
this.timelineLoadingMode = settings.timelineMode;
|
||||
|
||||
this.goToTopSubscription = this.goToTop.subscribe(() => {
|
||||
this.applyGoToTop();
|
||||
});
|
||||
|
@ -112,7 +120,7 @@ export class StreamStatusesComponent implements OnInit, OnDestroy {
|
|||
|
||||
this.deleteStatusSubscription = this.notificationService.deletedStatusStream.subscribe((status: StatusWrapper) => {
|
||||
if (status) {
|
||||
this.statuses = this.statuses.filter(x => {
|
||||
this.statuses = this.statuses.filter(x => {
|
||||
return !(x.status.url.replace('https://', '').split('/')[0] === status.provider.instance && x.status.id === status.status.id);
|
||||
});
|
||||
}
|
||||
|
@ -158,7 +166,9 @@ export class StreamStatusesComponent implements OnInit, OnDestroy {
|
|||
if (update) {
|
||||
if (update.type === EventEnum.update) {
|
||||
if (!this.statuses.find(x => x.status.id == update.status.id)) {
|
||||
if (this.streamPositionnedAtTop) {
|
||||
if ((this.streamPositionnedAtTop || this.timelineLoadingMode === TimeLineModeEnum.Continuous)
|
||||
&& this.timelineLoadingMode !== TimeLineModeEnum.SlowMode) {
|
||||
|
||||
if (this.isFiltered(update.status)) {
|
||||
return;
|
||||
}
|
||||
|
@ -198,9 +208,6 @@ export class StreamStatusesComponent implements OnInit, OnDestroy {
|
|||
return false;
|
||||
}
|
||||
|
||||
private streamPositionnedAtTop: boolean = true;
|
||||
private isProcessingInfiniteScroll: boolean;
|
||||
|
||||
onScroll() {
|
||||
var element = this.statustream.nativeElement as HTMLElement;
|
||||
const atBottom = element.scrollHeight <= element.clientHeight + element.scrollTop + 1000;
|
||||
|
@ -233,10 +240,12 @@ export class StreamStatusesComponent implements OnInit, OnDestroy {
|
|||
private scrolledToTop() {
|
||||
this.streamPositionnedAtTop = true;
|
||||
|
||||
this.loadBuffer();
|
||||
if (this.timelineLoadingMode !== TimeLineModeEnum.SlowMode) {
|
||||
this.loadBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
private loadBuffer() {
|
||||
loadBuffer(): boolean {
|
||||
if (this.bufferWasCleared) {
|
||||
this.statuses.length = 0;
|
||||
this.bufferWasCleared = false;
|
||||
|
@ -253,6 +262,7 @@ export class StreamStatusesComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
this.bufferStream.length = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
private scrolledToBottom() {
|
||||
|
@ -274,7 +284,7 @@ export class StreamStatusesComponent implements OnInit, OnDestroy {
|
|||
this.statuses.push(wrapper);
|
||||
}
|
||||
|
||||
if(!status || status.length === 0){
|
||||
if (!status || status.length === 0) {
|
||||
this.lastInfinityFetchReturnedNothing = true;
|
||||
}
|
||||
})
|
||||
|
|
|
@ -7,19 +7,20 @@
|
|||
<!-- <div> -->
|
||||
<div class="stream-column__stream-header">
|
||||
<a class="stream-column__stream-selector" href title="return to top" (click)="goToTop()">
|
||||
<img *ngIf="timelineHeader === 3 || timelineHeader === 4" class="stream-column__stream-selector--avatar" src="{{avatar}}" />
|
||||
<fa-icon class="stream-column__stream-selector--icon" [icon]="columnFaIcon"></fa-icon>
|
||||
<h1 class="stream-column__stream-selector--title">{{ streamElement.name.toUpperCase() }}</h1>
|
||||
<span class="stream-column__stream-selector--subtitle"
|
||||
*ngIf="streamElement.instance">{{ streamElement.instance.toLowerCase() }}</span>
|
||||
<span class="stream-column__stream-selector--text">
|
||||
<h1 class="stream-column__stream-selector--title" [class.stream-column__stream-selector--title--only]="timelineHeader === 4 || timelineHeader === 5">{{ streamElement.name.toUpperCase() }}</h1>
|
||||
<span class="stream-column__stream-selector--subtitle" *ngIf="streamElement.instance && timelineHeader !== 4 && timelineHeader !== 5"><span *ngIf="timelineHeader === 2">{{account.username}}@</span>{{ streamElement.instance.toLowerCase() }}</span>
|
||||
</span>
|
||||
</a>
|
||||
<a class="stream-column__open-menu" href title="edit column" (click)="openEditionMenu()">
|
||||
<fa-icon class="stream-column__open-menu--icon" [icon]="menuFaIcon"></fa-icon>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<app-stream-edition class="stream-edition" *ngIf="editionPanelIsOpen"
|
||||
[streamElement]="streamElement" [displayingNotifications]="displayingNotifications"
|
||||
(closed)="streamEditionClosed()">
|
||||
<app-stream-edition class="stream-edition" *ngIf="editionPanelIsOpen" [streamElement]="streamElement"
|
||||
[displayingNotifications]="displayingNotifications" (closed)="streamEditionClosed()">
|
||||
</app-stream-edition>
|
||||
|
||||
<app-stream-statuses *ngIf="!displayingNotifications" class="stream-statuses" [streamElement]="streamElement"
|
||||
|
@ -27,9 +28,10 @@
|
|||
(browseHashtagEvent)="browseHashtag($event)" (browseThreadEvent)="browseThread($event)">
|
||||
</app-stream-statuses>
|
||||
|
||||
<app-stream-notifications *ngIf="displayingNotifications" class="stream-statuses" [streamElement]="streamElement"
|
||||
[goToTop]="goToTopSubject.asObservable()" (browseAccountEvent)="browseAccount($event)"
|
||||
(browseHashtagEvent)="browseHashtag($event)" (browseThreadEvent)="browseThread($event)">
|
||||
<app-stream-notifications *ngIf="displayingNotifications" class="stream-statuses"
|
||||
[streamElement]="streamElement" [goToTop]="goToTopSubject.asObservable()"
|
||||
(browseAccountEvent)="browseAccount($event)" (browseHashtagEvent)="browseHashtag($event)"
|
||||
(browseThreadEvent)="browseThread($event)">
|
||||
|
||||
</app-stream-notifications>
|
||||
<!-- </div> -->
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
@import "panel";
|
||||
|
||||
.stream-edition {
|
||||
display: block;
|
||||
width: $stream-column-width;
|
||||
position: absolute;
|
||||
z-index: 50;
|
||||
|
@ -48,27 +49,58 @@
|
|||
text-decoration: none;
|
||||
color: whitesmoke;
|
||||
position: relative;
|
||||
&--avatar {
|
||||
width: 20px;
|
||||
float: left;
|
||||
margin-left: 11px;
|
||||
position: relative;
|
||||
// left: 11px;
|
||||
top: 9px;
|
||||
}
|
||||
&--icon {
|
||||
float: left;
|
||||
margin-left: 11px;
|
||||
position: relative;
|
||||
left: 11px;
|
||||
// left: 11px;
|
||||
top: 9px;
|
||||
}
|
||||
&--text {
|
||||
float: left;
|
||||
margin-left: 9px;
|
||||
}
|
||||
&--title {
|
||||
font-size: 0.8em;
|
||||
font-weight: normal;
|
||||
position: absolute;
|
||||
// float: left;
|
||||
// margin-left: 10px;
|
||||
// position: absolute;
|
||||
position: relative;
|
||||
top: 9px;
|
||||
left: 35px;
|
||||
}
|
||||
// left: 35px;
|
||||
|
||||
&--only {
|
||||
top: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
&--subtitle {
|
||||
color: $font-link-primary-hover;
|
||||
font-size: 0.7em;
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
position: absolute;
|
||||
top: 21px;
|
||||
left: 35px;;
|
||||
// position: absolute;
|
||||
position: relative;
|
||||
top: -2px;
|
||||
// top: 21px;
|
||||
// top: 10px;
|
||||
// left: 35px;;
|
||||
// outline: 1px solid greenyellow;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
max-width: 240px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
padding-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,11 @@ import { Subject } from "rxjs";
|
|||
import { faHome, faGlobe, faUser, faHashtag, faListUl, faBars, IconDefinition, faBell } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
import { StreamElement, StreamTypeEnum } from "../../states/streams.state";
|
||||
import { OpenThreadEvent } from "../../services/tools.service";
|
||||
import { OpenThreadEvent, ToolsService } from "../../services/tools.service";
|
||||
import { StreamStatusesComponent } from './stream-statuses/stream-statuses.component';
|
||||
import { StreamNotificationsComponent } from './stream-notifications/stream-notifications.component';
|
||||
import { TimeLineHeaderEnum } from '../../states/settings.state';
|
||||
import { AccountInfo } from '../../states/accounts.state';
|
||||
|
||||
@Component({
|
||||
selector: "app-stream",
|
||||
|
@ -21,6 +23,10 @@ export class StreamComponent implements OnInit {
|
|||
overlayHashtagToBrowse: string;
|
||||
overlayThreadToBrowse: OpenThreadEvent;
|
||||
|
||||
timelineHeader: TimeLineHeaderEnum;
|
||||
account: AccountInfo;
|
||||
avatar: string;
|
||||
|
||||
displayingNotifications: boolean;
|
||||
|
||||
goToTopSubject: Subject<void> = new Subject<void>();
|
||||
|
@ -48,26 +54,33 @@ export class StreamComponent implements OnInit {
|
|||
case StreamTypeEnum.list:
|
||||
this.columnFaIcon = faListUl;
|
||||
break;
|
||||
case StreamTypeEnum.activity:
|
||||
case StreamTypeEnum.activity:
|
||||
this.columnFaIcon = faBell;
|
||||
this.displayingNotifications = true;
|
||||
break;
|
||||
}
|
||||
|
||||
this._streamElement = stream;
|
||||
this.account = this.toolsService.getAccountById(stream.accountId);
|
||||
this.toolsService.getAvatar(this.account)
|
||||
.then(a => {
|
||||
this.avatar = a;
|
||||
})
|
||||
.catch(err => { });
|
||||
}
|
||||
get streamElement(): StreamElement {
|
||||
return this._streamElement;
|
||||
}
|
||||
|
||||
|
||||
constructor() { }
|
||||
constructor(private toolsService: ToolsService) { }
|
||||
|
||||
ngOnInit() {
|
||||
let settings = this.toolsService.getSettings();
|
||||
this.timelineHeader = settings.timelineHeader;
|
||||
}
|
||||
|
||||
focus(): boolean {
|
||||
if(this.overlayActive) return false;
|
||||
if (this.overlayActive) return false;
|
||||
|
||||
if (!this.displayingNotifications) {
|
||||
this.streamStatusesComponent.focus();
|
||||
|
|
|
@ -11,6 +11,7 @@ import { StatusWrapper } from '../../../models/common.model';
|
|||
import { StatusComponent } from '../status/status.component';
|
||||
import scrollIntoView from 'scroll-into-view-if-needed';
|
||||
import { UserNotificationService, UserNotification } from '../../../services/user-notification.service';
|
||||
import { TimeLineModeEnum } from '../../../states/settings.state';
|
||||
|
||||
@Component({
|
||||
selector: 'app-thread',
|
||||
|
@ -26,6 +27,8 @@ export class ThreadComponent implements OnInit, OnDestroy {
|
|||
private remoteStatusFetchingDisabled = false;
|
||||
|
||||
bufferStream: Status[] = []; //html compatibility only
|
||||
streamPositionnedAtTop: boolean = true; //html compatibility only
|
||||
timelineLoadingMode: TimeLineModeEnum = TimeLineModeEnum.OnTop; //html compatibility only
|
||||
|
||||
private lastThreadEvent: OpenThreadEvent;
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ export class StreamingWrapper {
|
|||
private apiRoutes = new ApiRoutes();
|
||||
private errorClosing: boolean;
|
||||
private since_id: string;
|
||||
private since_id_notifications: string;
|
||||
private disposed: boolean;
|
||||
|
||||
constructor(
|
||||
|
@ -67,7 +68,7 @@ export class StreamingWrapper {
|
|||
});
|
||||
}
|
||||
|
||||
private webSocketGotError(x: Event) {
|
||||
private webSocketGotError(x: Event) {
|
||||
this.errorClosing = true;
|
||||
}
|
||||
|
||||
|
@ -76,6 +77,7 @@ export class StreamingWrapper {
|
|||
setTimeout(() => {
|
||||
if (stream.type === StreamTypeEnum.personnal) {
|
||||
this.pullNewNotifications();
|
||||
this.pullNewStatuses();
|
||||
} else {
|
||||
this.pullNewStatuses();
|
||||
}
|
||||
|
@ -87,10 +89,10 @@ export class StreamingWrapper {
|
|||
}
|
||||
|
||||
private pullNewNotifications() {
|
||||
this.mastodonService.getNotifications(this.account, null, null, this.since_id, 10)
|
||||
this.mastodonService.getNotifications(this.account, null, null, this.since_id_notifications, 10)
|
||||
.then((notifications: Notification[]) => {
|
||||
//notifications = notifications.sort((a, b) => a.id.localeCompare(b.id));
|
||||
let soundMuted = !this.since_id;
|
||||
let soundMuted = !this.since_id_notifications;
|
||||
|
||||
notifications = notifications.reverse();
|
||||
for (const n of notifications) {
|
||||
|
@ -100,7 +102,7 @@ export class StreamingWrapper {
|
|||
update.type = EventEnum.notification;
|
||||
update.muteSound = soundMuted;
|
||||
|
||||
this.since_id = n.id;
|
||||
this.since_id_notifications = n.id;
|
||||
this.statusUpdateSubjet.next(update);
|
||||
}
|
||||
})
|
||||
|
|
|
@ -5,8 +5,7 @@ import { AccountInfo } from '../states/accounts.state';
|
|||
import { MastodonWrapperService } from './mastodon-wrapper.service';
|
||||
import { Account, Results, Status, Emoji } from "./models/mastodon.interfaces";
|
||||
import { StatusWrapper } from '../models/common.model';
|
||||
import { AccountSettings, SaveAccountSettings, GlobalSettings, SaveSettings, ContentWarningPolicy, SaveContentWarningPolicy, ContentWarningPolicyEnum } from '../states/settings.state';
|
||||
import { AppInfo, RegisteredAppsStateModel } from '../states/registered-apps.state';
|
||||
import { AccountSettings, SaveAccountSettings, GlobalSettings, SaveSettings, ContentWarningPolicy, SaveContentWarningPolicy, ContentWarningPolicyEnum, TimeLineModeEnum, TimeLineHeaderEnum } from '../states/settings.state';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
@ -155,6 +154,16 @@ export class ToolsService {
|
|||
return <GlobalSettings>this.store.snapshot().globalsettings.settings;
|
||||
}
|
||||
|
||||
if(!settings.timelineMode){
|
||||
settings.timelineMode = TimeLineModeEnum.OnTop;
|
||||
this.saveSettings(settings);
|
||||
}
|
||||
|
||||
if(!settings.timelineHeader){
|
||||
settings.timelineHeader = TimeLineHeaderEnum.Title_DomainName;
|
||||
this.saveSettings(settings);
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,20 @@ export enum ContentWarningPolicyEnum {
|
|||
AddOnAllContent = 3
|
||||
}
|
||||
|
||||
export enum TimeLineModeEnum {
|
||||
OnTop = 1,
|
||||
Continuous = 2,
|
||||
SlowMode = 3
|
||||
}
|
||||
|
||||
export enum TimeLineHeaderEnum {
|
||||
Title_DomainName = 1,
|
||||
Title_Username_DomainName = 2,
|
||||
Title_AccountIcon_DomainName = 3,
|
||||
Title_AccountIcon = 4,
|
||||
Title = 5
|
||||
}
|
||||
|
||||
export class ContentWarningPolicy {
|
||||
policy: ContentWarningPolicyEnum = ContentWarningPolicyEnum.None;
|
||||
addCwOnContent: string[] = [];
|
||||
|
@ -55,6 +69,9 @@ export class GlobalSettings {
|
|||
|
||||
notificationSoundFileId: string = '0';
|
||||
|
||||
timelineHeader: TimeLineHeaderEnum = TimeLineHeaderEnum.Title_DomainName;
|
||||
timelineMode: TimeLineModeEnum = TimeLineModeEnum.OnTop;
|
||||
|
||||
contentWarningPolicy: ContentWarningPolicy = new ContentWarningPolicy();
|
||||
|
||||
columnSwitchingWinAlt = false;
|
||||
|
@ -145,6 +162,8 @@ export class SettingsState {
|
|||
newSettings.notificationSoundFileId = oldSettings.notificationSoundFileId;
|
||||
newSettings.columnSwitchingWinAlt = oldSettings.columnSwitchingWinAlt;
|
||||
newSettings.disableRemoteStatusFetching = oldSettings.disableRemoteStatusFetching;
|
||||
newSettings.timelineHeader = oldSettings.timelineHeader;
|
||||
newSettings.timelineMode = oldSettings.timelineMode;
|
||||
|
||||
return newSettings;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue