commit
03be3db8c1
|
@ -69,6 +69,18 @@ function createWindow() {
|
|||
// Create our menu entries so that we can use MAC shortcuts
|
||||
Menu.setApplicationMenu(
|
||||
Menu.buildFromTemplate([
|
||||
{
|
||||
label: "Sengi",
|
||||
submenu: [
|
||||
{ role: "close" },
|
||||
{ role: 'quit' }
|
||||
]
|
||||
},
|
||||
// {
|
||||
// label: "File",
|
||||
// submenu: [
|
||||
// ]
|
||||
// },
|
||||
{
|
||||
label: "Edit",
|
||||
submenu: [
|
||||
|
@ -80,12 +92,14 @@ function createWindow() {
|
|||
{ role: "paste" },
|
||||
{ role: "pasteandmatchstyle" },
|
||||
{ role: "delete" },
|
||||
{ role: "selectall" },
|
||||
{ type: "separator" },
|
||||
{ role: "close" },
|
||||
{ role: 'quit' }
|
||||
{ role: "selectall" }
|
||||
]
|
||||
},
|
||||
// {
|
||||
// label: "Format",
|
||||
// submenu: [
|
||||
// ]
|
||||
// },
|
||||
{
|
||||
label: "View",
|
||||
submenu: [
|
||||
|
@ -102,8 +116,13 @@ function createWindow() {
|
|||
{ role: 'togglefullscreen' }
|
||||
]
|
||||
},
|
||||
// {
|
||||
// label: "Window",
|
||||
// submenu: [
|
||||
// ]
|
||||
// },
|
||||
{
|
||||
role: "help",
|
||||
role: "Help",
|
||||
submenu: [
|
||||
{ role: "toggledevtools" },
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "sengi",
|
||||
"version": "0.15.0",
|
||||
"version": "0.16.2",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -857,6 +857,11 @@
|
|||
"@types/jasmine": "*"
|
||||
}
|
||||
},
|
||||
"@types/mousetrap": {
|
||||
"version": "1.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/mousetrap/-/mousetrap-1.6.3.tgz",
|
||||
"integrity": "sha512-13gmo3M2qVvjQrWNseqM3+cR6S2Ss3grbR2NZltgMq94wOwqJYQdgn8qzwDshzgXqMlSUtyPZjysImmktu22ew=="
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "8.9.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.9.5.tgz",
|
||||
|
@ -1189,6 +1194,15 @@
|
|||
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
|
||||
"dev": true
|
||||
},
|
||||
"angular2-hotkeys": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/angular2-hotkeys/-/angular2-hotkeys-2.1.5.tgz",
|
||||
"integrity": "sha512-HiAnK1pW7lns5LpxtRsdkRRb5iVa7fv8Cf69Jye6l9gI6/IyvaVDptRtsWmdIG7VAr2Ngz6Yeehkym39O/LdgA==",
|
||||
"requires": {
|
||||
"@types/mousetrap": "^1.6.0",
|
||||
"mousetrap": "^1.6.0"
|
||||
}
|
||||
},
|
||||
"ansi-align": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz",
|
||||
|
@ -2728,6 +2742,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"compute-scroll-into-view": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.11.tgz",
|
||||
"integrity": "sha512-uUnglJowSe0IPmWOdDtrlHXof5CTIJitfJEyITHBW6zDVOGu9Pjk5puaLM73SLcwak0L4hEjO7Td88/a6P5i7A=="
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
|
@ -8105,6 +8124,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"mousetrap": {
|
||||
"version": "1.6.3",
|
||||
"resolved": "https://registry.npmjs.org/mousetrap/-/mousetrap-1.6.3.tgz",
|
||||
"integrity": "sha512-bd+nzwhhs9ifsUrC2tWaSgm24/oo2c83zaRyZQF06hYA6sANfsXHtnZ19AbbbDXCDzeH5nZBSQ4NvCjgD62tJA=="
|
||||
},
|
||||
"move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||
|
@ -10302,6 +10326,14 @@
|
|||
"ajv-keywords": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"scroll-into-view-if-needed": {
|
||||
"version": "2.2.20",
|
||||
"resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.20.tgz",
|
||||
"integrity": "sha512-P9kYMrhi9f6dvWwTGpO5I3HgjSU/8Mts7xL3lkoH5xlewK7O9Obdc5WmMCzppln7bCVGNmf3qfoZXrpCeyNJXw==",
|
||||
"requires": {
|
||||
"compute-scroll-into-view": "1.0.11"
|
||||
}
|
||||
},
|
||||
"scss-tokenizer": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz",
|
||||
|
@ -10619,6 +10651,14 @@
|
|||
"integrity": "sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw==",
|
||||
"dev": true
|
||||
},
|
||||
"smooth-scroll-into-view-if-needed": {
|
||||
"version": "1.1.23",
|
||||
"resolved": "https://registry.npmjs.org/smooth-scroll-into-view-if-needed/-/smooth-scroll-into-view-if-needed-1.1.23.tgz",
|
||||
"integrity": "sha512-52177sj5yR2novVCB+vJRCYEUkHFz2mq5UKmm5wwIWs0ZtC1sotVaTjKBsuNzBPF4nOV1NxMctyD4V/VMmivCQ==",
|
||||
"requires": {
|
||||
"scroll-into-view-if-needed": "2.2.20"
|
||||
}
|
||||
},
|
||||
"snapdragon": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "sengi",
|
||||
"version": "0.16.2",
|
||||
"version": "0.17.0",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"main": "main-electron.js",
|
||||
"description": "A multi-account desktop client for Mastodon and Pleroma",
|
||||
|
@ -45,12 +45,14 @@
|
|||
"@fortawesome/free-solid-svg-icons": "^5.7.0",
|
||||
"@ngxs/storage-plugin": "^3.2.0",
|
||||
"@ngxs/store": "^3.2.0",
|
||||
"angular2-hotkeys": "^2.1.5",
|
||||
"bootstrap": "^4.1.3",
|
||||
"core-js": "^2.5.4",
|
||||
"emojione": "~4.5.0",
|
||||
"ng-pick-datetime": "^7.0.0",
|
||||
"ngx-contextmenu": "^5.2.0",
|
||||
"rxjs": "^6.4.0",
|
||||
"smooth-scroll-into-view-if-needed": "^1.1.23",
|
||||
"tslib": "^1.9.0",
|
||||
"zone.js": "^0.8.29"
|
||||
},
|
||||
|
|
|
@ -16,6 +16,7 @@ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
|||
import { ContextMenuModule } from 'ngx-contextmenu';
|
||||
import { PickerModule } from '@ctrl/ngx-emoji-mart';
|
||||
import { OwlDateTimeModule, OwlNativeDateTimeModule } from 'ng-pick-datetime';
|
||||
import { HotkeyModule } from 'angular2-hotkeys';
|
||||
|
||||
import { AppComponent } from "./app.component";
|
||||
import { LeftSideBarComponent } from "./components/left-side-bar/left-side-bar.component";
|
||||
|
@ -159,7 +160,8 @@ const routes: Routes = [
|
|||
SettingsState
|
||||
]),
|
||||
NgxsStoragePluginModule.forRoot(),
|
||||
ContextMenuModule.forRoot()
|
||||
ContextMenuModule.forRoot(),
|
||||
HotkeyModule.forRoot()
|
||||
],
|
||||
providers: [AuthService, NavigationService, NotificationService, MastodonService, StreamingService],
|
||||
bootstrap: [AppComponent],
|
||||
|
|
|
@ -148,6 +148,11 @@ $counter-width: 90px;
|
|||
background-color: darken($status-editor-footer-background, 20%);
|
||||
}
|
||||
|
||||
outline: inherit;
|
||||
&:focus {
|
||||
background-color: darken($status-editor-footer-background, 20%);
|
||||
}
|
||||
|
||||
& span {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
|
|
@ -8,18 +8,18 @@
|
|||
<app-waiting-animation class="waiting-icon"></app-waiting-animation>
|
||||
</div>
|
||||
<div class="media__loaded--hover">
|
||||
<button class="media__loaded--button" title="remove" (click)="removeMedia(m)">
|
||||
<a href class="media__loaded--button" title="remove" (click)="removeMedia(m)">
|
||||
<fa-icon [icon]="faTimes"></fa-icon>
|
||||
</button>
|
||||
</a>
|
||||
<input class="media__loaded--description" [(ngModel)]="m.description" autocomplete="off"
|
||||
placeholder="Describe for the visually impaired" />
|
||||
</div>
|
||||
<img class="media__loaded--preview" src="{{m.attachment.preview_url}}" />
|
||||
</div>
|
||||
<div *ngIf="m.attachment !== null && m.attachment.type === 'audio'" class="audio">
|
||||
<button class="audio__button" title="remove" (click)="removeMedia(m)">
|
||||
<a href class="audio__button" title="remove" (click)="removeMedia(m)">
|
||||
<fa-icon [icon]="faTimes"></fa-icon>
|
||||
</button>
|
||||
</a>
|
||||
|
||||
<div *ngIf="m.isMigrating">
|
||||
<app-waiting-animation class="waiting-icon"></app-waiting-animation>
|
||||
|
|
|
@ -46,12 +46,11 @@
|
|||
opacity: 100;
|
||||
}
|
||||
|
||||
&--button {
|
||||
@include clearButton;
|
||||
&--button {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
position: absolute;
|
||||
top:5px;
|
||||
top:0px;
|
||||
right:8px;
|
||||
color: white;
|
||||
}
|
||||
|
@ -61,13 +60,9 @@
|
|||
bottom:5px;
|
||||
left: 5px;
|
||||
width: calc(100% - 10px);
|
||||
// background: black;
|
||||
// color: white;
|
||||
}
|
||||
|
||||
&--preview {
|
||||
// display: block;
|
||||
|
||||
width: calc(100%);
|
||||
height: calc(100%);
|
||||
|
||||
|
@ -87,16 +82,12 @@
|
|||
}
|
||||
|
||||
&__button {
|
||||
@include clearButton;
|
||||
display: block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
color: white;
|
||||
float: right;
|
||||
|
||||
// position: absolute;
|
||||
// top:5px;
|
||||
// right:8px;
|
||||
|
||||
margin-top: 0px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ import { Subscription, Observable } from "rxjs";
|
|||
import { Store } from "@ngxs/store";
|
||||
import { faPlus, faCog, faSearch } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faCommentAlt, faCalendarAlt } from "@fortawesome/free-regular-svg-icons";
|
||||
import { HotkeysService, Hotkey } from 'angular2-hotkeys';
|
||||
|
||||
import { AccountWrapper } from "../../models/account.models";
|
||||
import { AccountInfo, SelectAccount } from "../../states/accounts.state";
|
||||
|
@ -33,6 +34,7 @@ export class LeftSideBarComponent implements OnInit, OnDestroy {
|
|||
private notificationSub: Subscription;
|
||||
|
||||
constructor(
|
||||
private readonly hotkeysService: HotkeysService,
|
||||
private readonly scheduledStatusService: ScheduledStatusService,
|
||||
private readonly toolsService: ToolsService,
|
||||
private readonly userNotificationServiceService: UserNotificationService,
|
||||
|
@ -40,6 +42,63 @@ export class LeftSideBarComponent implements OnInit, OnDestroy {
|
|||
private readonly store: Store) {
|
||||
|
||||
this.accounts$ = this.store.select(state => state.registeredaccounts.accounts);
|
||||
|
||||
this.hotkeysService.add(new Hotkey('n', (event: KeyboardEvent): boolean => {
|
||||
this.createNewStatus();
|
||||
return false;
|
||||
}));
|
||||
|
||||
this.hotkeysService.add(new Hotkey('s', (event: KeyboardEvent): boolean => {
|
||||
this.openSearch();
|
||||
return false;
|
||||
}));
|
||||
|
||||
this.hotkeysService.add(new Hotkey('a', (event: KeyboardEvent): boolean => {
|
||||
this.addNewAccount();
|
||||
return false;
|
||||
}));
|
||||
|
||||
this.hotkeysService.add(new Hotkey('c', (event: KeyboardEvent): boolean => {
|
||||
this.navigationService.openPanel(LeftPanelType.Closed);
|
||||
return false;
|
||||
}));
|
||||
|
||||
this.hotkeysService.add(new Hotkey('escape', (event: KeyboardEvent): boolean => {
|
||||
this.navigationService.openPanel(LeftPanelType.Closed);
|
||||
return false;
|
||||
}));
|
||||
|
||||
this.hotkeysService.add(new Hotkey('ctrl+up', (event: KeyboardEvent): boolean => {
|
||||
this.selectPreviousAccount();
|
||||
return false;
|
||||
}));
|
||||
|
||||
this.hotkeysService.add(new Hotkey('ctrl+down', (event: KeyboardEvent): boolean => {
|
||||
this.selectNextAccount();
|
||||
return false;
|
||||
}));
|
||||
}
|
||||
|
||||
private selectPreviousAccount(){
|
||||
let accounts = <AccountInfo[]>this.store.snapshot().registeredaccounts.accounts;
|
||||
let selectedAccount = accounts.find(x => x.isSelected);
|
||||
let selectedIndex = accounts.indexOf(selectedAccount);
|
||||
|
||||
if(selectedIndex > 0){
|
||||
let previousAccount = accounts[selectedIndex - 1];
|
||||
this.store.dispatch([new SelectAccount(previousAccount)]);
|
||||
}
|
||||
}
|
||||
|
||||
private selectNextAccount(){
|
||||
let accounts = <AccountInfo[]>this.store.snapshot().registeredaccounts.accounts;
|
||||
let selectedAccount = accounts.find(x => x.isSelected);
|
||||
let selectedIndex = accounts.indexOf(selectedAccount);
|
||||
|
||||
if(selectedIndex < accounts.length - 1){
|
||||
let nextAccount = accounts[selectedIndex + 1];
|
||||
this.store.dispatch([new SelectAccount(nextAccount)]);
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
@ -100,6 +159,7 @@ export class LeftSideBarComponent implements OnInit, OnDestroy {
|
|||
ngOnDestroy(): void {
|
||||
this.accountSub.unsubscribe();
|
||||
this.notificationSub.unsubscribe();
|
||||
this.scheduledSub.unsubscribe();
|
||||
}
|
||||
|
||||
onToogleAccountNotify(acc: AccountWrapper) {
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
<div class="media-viewer-canvas noselect">
|
||||
<div class="background__close" (click)="close()"></div>
|
||||
|
||||
<button class="media-viewer-canvas__close media-viewer-canvas__button" title="close" (click)="close()">
|
||||
<a href class="media-viewer-canvas__close media-viewer-canvas__button" title="close" (click)="close()">
|
||||
<fa-icon [icon]="faTimes"></fa-icon>
|
||||
</button>
|
||||
</a>
|
||||
|
||||
<button class="media-viewer-canvas__previous media-viewer-canvas__button" title="previous"
|
||||
<a href class="media-viewer-canvas__previous media-viewer-canvas__button" title="previous"
|
||||
(click)="previous($event)" *ngIf="previousAvailable">
|
||||
<fa-icon [icon]="faAngleLeft"></fa-icon>
|
||||
</button>
|
||||
</a>
|
||||
|
||||
<button class="media-viewer-canvas__next media-viewer-canvas__button" title="next" (click)="next($event)"
|
||||
<a href class="media-viewer-canvas__next media-viewer-canvas__button" title="next" (click)="next($event)"
|
||||
*ngIf="nextAvailable">
|
||||
<fa-icon [icon]="faAngleRight"></fa-icon>
|
||||
</button>
|
||||
</a>
|
||||
|
||||
<div *ngFor="let att of attachments" class="media-viewer-canvas__attachement"
|
||||
[class.collapsed]="currentIndex !== att.index">
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
position: relative;
|
||||
|
||||
&__button {
|
||||
@include clearButton;
|
||||
display: block;
|
||||
padding: 5px;
|
||||
position: absolute;
|
||||
}
|
||||
|
|
|
@ -46,37 +46,30 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="galery" *ngIf="isGifv">
|
||||
<!-- <video width="480" height="320" controls="controls"> -->
|
||||
<video class="galery__gifv" role="application" loop autoplay (click)="attachmentSelected(0)">
|
||||
<source src="{{ attachments[0].url }}" type="video/mp4">
|
||||
</video>
|
||||
</div>
|
||||
<div class="galery galery__hover" *ngIf="isVideo">
|
||||
<!-- <video width="480" height="320" controls="controls"> -->
|
||||
<video #videoPlayer class="galery__video" role="application" loop>
|
||||
<source src="{{ attachments[0].url }}" type="video/mp4">
|
||||
</video>
|
||||
<div class="galery__play-control">
|
||||
<button type="button" class="galery__control--button" (click)="onPlay()" *ngIf="!isPlaying">
|
||||
<a href class="galery__control--button" (click)="onPlay()" *ngIf="!isPlaying">
|
||||
<fa-icon [icon]="faPlay"></fa-icon>
|
||||
</button>
|
||||
<!-- <button type="button" id="play-pause" class="galery__control--button">
|
||||
<fa-icon [icon]="faPause"></fa-icon>
|
||||
</button> -->
|
||||
</a>
|
||||
</div>
|
||||
<div class="galery__control">
|
||||
<button type="button" class="galery__control--button" (click)="onPlay()">
|
||||
<a href class="galery__control--button" (click)="onPlay()">
|
||||
<fa-icon [icon]="faPause" *ngIf="isPlaying"></fa-icon>
|
||||
</button>
|
||||
<!-- <input type="range" id="seek-bar" class="video-control__button" value="0"> -->
|
||||
<button type="button" class="galery__control--button galery__control--expand" (click)="onExpand()">
|
||||
</a>
|
||||
<a href class="galery__control--button galery__control--expand" (click)="onExpand()">
|
||||
<fa-icon [icon]="faExpand"></fa-icon>
|
||||
</button>
|
||||
<!-- <input type="range" id="volume-bar" class="video-control__button" min="0" max="1" step="0.1" value="1"> -->
|
||||
<button type="button" class="galery__control--button galery__control--mute" (click)="onMute()">
|
||||
</a>
|
||||
<a href class="galery__control--button galery__control--mute" (click)="onMute()">
|
||||
<fa-icon [icon]="faVolumeUp" *ngIf="!isMuted"></fa-icon>
|
||||
<fa-icon [icon]="faVolumeMute" *ngIf="isMuted"></fa-icon>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="isAudio">
|
||||
|
|
|
@ -124,8 +124,8 @@
|
|||
padding-top: 55px;
|
||||
|
||||
&--button {
|
||||
@include clearButton;
|
||||
color: rgb(211, 211, 211);
|
||||
display: inline-block;
|
||||
color: rgb(211, 211, 211);
|
||||
font-size: 16px;
|
||||
padding: 10px 15px;
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ export class AttachementsComponent implements OnInit {
|
|||
return this.videoplayer.nativeElement;
|
||||
}
|
||||
|
||||
onPlay() {
|
||||
onPlay(): boolean {
|
||||
if (!this.isPlaying) {
|
||||
this.getVideo().play();
|
||||
} else {
|
||||
|
@ -72,10 +72,10 @@ export class AttachementsComponent implements OnInit {
|
|||
}
|
||||
|
||||
this.isPlaying = !this.isPlaying;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
onExpand() {
|
||||
onExpand(): boolean {
|
||||
if (!this.isMuted) {
|
||||
this.onMute();
|
||||
}
|
||||
|
@ -85,11 +85,13 @@ export class AttachementsComponent implements OnInit {
|
|||
}
|
||||
|
||||
this.attachmentSelected(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
onMute() {
|
||||
onMute(): boolean {
|
||||
this.isMuted = !this.isMuted;
|
||||
this.getVideo().muted = this.isMuted;
|
||||
return false;
|
||||
}
|
||||
|
||||
setAudioData(att: Attachment): any {
|
||||
|
|
|
@ -1,33 +1,33 @@
|
|||
<div class="stream-edition">
|
||||
<div class="stream-edition__settings">
|
||||
<div class="stream-edition__setting">
|
||||
<input [(ngModel)]="hideBoosts" (change)="settingsChanged()"
|
||||
class="stream-edition__setting--checkbox" type="checkbox" id="hideBoosts"> <label for="hideBoosts" class="noselect">hide
|
||||
<input [(ngModel)]="hideBoosts" (change)="settingsChanged()" class="stream-edition__setting--checkbox"
|
||||
type="checkbox" id="hideBoosts"> <label for="hideBoosts" class="noselect">hide
|
||||
boosts</label><br />
|
||||
</div>
|
||||
<div class="stream-edition__setting">
|
||||
<input [(ngModel)]="hideReplies" (change)="settingsChanged()"
|
||||
class="stream-edition__setting--checkbox" type="checkbox" id="hideReplies"> <label for="hideReplies" class="noselect">hide
|
||||
<input [(ngModel)]="hideReplies" (change)="settingsChanged()" class="stream-edition__setting--checkbox"
|
||||
type="checkbox" id="hideReplies"> <label for="hideReplies" class="noselect">hide
|
||||
replies</label><br />
|
||||
</div>
|
||||
<div class="stream-edition__setting">
|
||||
<input [(ngModel)]="hideBots" (change)="settingsChanged()"
|
||||
class="stream-edition__setting--checkbox" type="checkbox" id="hideBots" > <label for="hideBots" class="noselect">hide
|
||||
<input [(ngModel)]="hideBots" (change)="settingsChanged()" class="stream-edition__setting--checkbox"
|
||||
type="checkbox" id="hideBots"> <label for="hideBots" class="noselect">hide
|
||||
bots</label><br />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button (click)="delete()" class="stream-edition__button stream-edition__button--delete" title="remove column">
|
||||
<a href (click)="delete()" class="stream-edition__button stream-edition__button--delete" title="remove column">
|
||||
<fa-icon [icon]="faTimes"></fa-icon> <span class="stream-edition__button--delete--label">remove</span>
|
||||
</button>
|
||||
</a>
|
||||
|
||||
<button (click)="moveRight()"
|
||||
<a href (click)="moveRight()"
|
||||
class="stream-edition__button stream-edition__button--move stream-edition__button--move--right"
|
||||
title="move right">
|
||||
<fa-icon [icon]="faChevronRight"></fa-icon>
|
||||
</button>
|
||||
<button (click)="moveLeft()" class="stream-edition__button stream-edition__button--move" title="move left">
|
||||
</a>
|
||||
<a href (click)="moveLeft()" class="stream-edition__button stream-edition__button--move" title="move left">
|
||||
<fa-icon [icon]="faChevronLeft"></fa-icon>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
|
@ -26,9 +26,10 @@
|
|||
}
|
||||
|
||||
&__button {
|
||||
@include clearButton;
|
||||
display: inline-block;
|
||||
padding: 5px 10px 5px 10px;
|
||||
margin: 3px 0;
|
||||
color: $font-color-primary;
|
||||
|
||||
&--delete {
|
||||
// float: right;
|
||||
|
|
|
@ -1,35 +1,34 @@
|
|||
<div class="stream-overlay">
|
||||
<div class="stream-overlay__header">
|
||||
<button class="overlay__button overlay-close" title="close" (click)="close()">
|
||||
<fa-icon [icon]="faTimes"></fa-icon>
|
||||
</button>
|
||||
|
||||
<button class="overlay__button overlay-previous"
|
||||
[ngClass]="{'overlay__button--focus': hasPreviousElements }" title="previous" (click)="previous()">
|
||||
<fa-icon [icon]="faAngleLeft"></fa-icon>
|
||||
</button>
|
||||
<button class="overlay__button overlay-refresh" [ngClass]="{'overlay__button--focus': refreshFocused }"
|
||||
title="refresh" (click)="refresh()">
|
||||
<fa-icon [icon]="faRedoAlt"></fa-icon>
|
||||
</button>
|
||||
|
||||
<a href title="return to top" class="overlay-gototop" (click)="goToTop()">
|
||||
|
||||
<div class="overlay">
|
||||
<div class="overlay__header">
|
||||
<a href class="overlay__button overlay-close" title="close" (click)="close()">
|
||||
<fa-icon class="overlay-close__icon" [icon]="faTimes"></fa-icon>
|
||||
</a>
|
||||
|
||||
<button class="overlay__button overlay-next" [ngClass]="{'overlay__button--focus': hasNextElements }"
|
||||
<a href class="overlay__button overlay-previous"
|
||||
[ngClass]="{'overlay__button--focus': hasPreviousElements }" title="previous" (click)="previous()">
|
||||
<fa-icon class="overlay-previous__icon" [icon]="faAngleLeft"></fa-icon>
|
||||
</a>
|
||||
<a href class="overlay__button overlay-refresh" [ngClass]="{'overlay__button--focus': refreshFocused }"
|
||||
title="refresh" (click)="refresh()">
|
||||
<fa-icon class="overlay-refresh__icon" [icon]="faRedoAlt"></fa-icon>
|
||||
</a>
|
||||
|
||||
<a href title="return to top" class="overlay-gototop" (click)="goToTop()">
|
||||
</a>
|
||||
|
||||
<a href class="overlay__button overlay-next" [ngClass]="{'overlay__button--focus': hasNextElements }"
|
||||
title="next" (click)="next()">
|
||||
<fa-icon [icon]="faAngleRight"></fa-icon>
|
||||
</button>
|
||||
<fa-icon class="overlay-next__icon" [icon]="faAngleRight"></fa-icon>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div *ngFor="let e of loadedElements" class="stream-overlay__content-wrapper"
|
||||
[class.stream-overlay__content-wrapper--selected]="e.isVisible">
|
||||
<div *ngFor="let e of loadedElements" class="overlay__content-wrapper"
|
||||
[class.overlay__content-wrapper--selected]="e.isVisible">
|
||||
<app-user-profile #appUserProfile *ngIf="e.type === 'account'"
|
||||
[currentAccount]="e.account"
|
||||
[refreshEventEmitter]="e.refreshEventEmitter"
|
||||
[goToTopEventEmitter]="e.goToTopEventEmitter"
|
||||
class="stream-overlay__content"
|
||||
class="overlay__content"
|
||||
(browseAccountEvent)="browseAccount($event)"
|
||||
(browseHashtagEvent)="browseHashtag($event)"
|
||||
(browseThreadEvent)="browseThread($event)"></app-user-profile>
|
||||
|
@ -37,12 +36,12 @@
|
|||
[hashtagElement]="e.hashtag"
|
||||
[refreshEventEmitter]="e.refreshEventEmitter"
|
||||
[goToTopEventEmitter]="e.goToTopEventEmitter"
|
||||
class="stream-overlay__content"
|
||||
class="overlay__content"
|
||||
(browseAccountEvent)="browseAccount($event)"
|
||||
(browseHashtagEvent)="browseHashtag($event)"
|
||||
(browseThreadEvent)="browseThread($event)"></app-hashtag>
|
||||
<app-thread #appThread *ngIf="e.type === 'thread'"
|
||||
[currentThread]="e.thread" class="stream-overlay__content"
|
||||
[currentThread]="e.thread" class="overlay__content"
|
||||
[refreshEventEmitter]="e.refreshEventEmitter"
|
||||
[goToTopEventEmitter]="e.goToTopEventEmitter"
|
||||
(browseAccountEvent)="browseAccount($event)"
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
@import "mixins";
|
||||
@import "commons";
|
||||
$header-content-height: 40px;
|
||||
.stream-overlay {
|
||||
// width: $stream-column-width;
|
||||
.overlay {
|
||||
height: calc(100%);
|
||||
background-color: $column-color;
|
||||
position: relative;
|
||||
|
@ -11,13 +10,8 @@ $header-content-height: 40px;
|
|||
&__header {
|
||||
width: calc(100%);
|
||||
height: $header-content-height;
|
||||
background-color: $column-header-background-color; // padding: 6px 10px 0 10px;
|
||||
border-bottom: 1px solid #222736;
|
||||
& a {
|
||||
color: whitesmoke;
|
||||
font-size: 0.8em;
|
||||
font-weight: normal;
|
||||
}
|
||||
background-color: $column-header-background-color;
|
||||
border-bottom: 1px solid #222736;
|
||||
}
|
||||
&__content-wrapper {
|
||||
transition: all .2s;
|
||||
|
@ -26,9 +20,6 @@ $header-content-height: 40px;
|
|||
right: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
|
||||
// outline: 1px solid greenyellow;
|
||||
// background-color: salmon;
|
||||
|
||||
z-index: 1;
|
||||
opacity: 0;
|
||||
|
@ -51,12 +42,8 @@ $header-content-height: 40px;
|
|||
border-bottom: 1px solid whitesmoke;
|
||||
padding: 3px 10px 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.overlay {
|
||||
margin: 0;
|
||||
&__button {
|
||||
@include clearButton;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
color: #354060;
|
||||
|
@ -78,21 +65,35 @@ $header-content-height: 40px;
|
|||
display: block;
|
||||
float: left;
|
||||
font-size: 18px;
|
||||
& fa-icon {
|
||||
|
||||
&__icon {
|
||||
position: relative;
|
||||
left: -1px;
|
||||
left: 7px;
|
||||
top: -1px
|
||||
}
|
||||
}
|
||||
&-next {
|
||||
display: block;
|
||||
float: left;
|
||||
font-size: 18px;
|
||||
|
||||
&__icon {
|
||||
position: relative;
|
||||
left: 8px;
|
||||
top: -1px
|
||||
}
|
||||
}
|
||||
&-refresh {
|
||||
display: block;
|
||||
float: left;
|
||||
font-size: 14px;
|
||||
}
|
||||
&-next {
|
||||
display: block;
|
||||
float: left;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
position: relative;
|
||||
left: 5px;
|
||||
top: 1px
|
||||
}
|
||||
}
|
||||
&-gototop {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
@ -104,9 +105,15 @@ $header-content-height: 40px;
|
|||
&-close {
|
||||
display: block;
|
||||
float: right;
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
color: white;
|
||||
margin-right: 8px;
|
||||
|
||||
&__icon {
|
||||
position: relative;
|
||||
left: 7px;
|
||||
top: 1px
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,19 +1,21 @@
|
|||
<div class="stream-toots flexcroll" #statusstream (scroll)="onScroll()">
|
||||
<div class="stream-toots">
|
||||
<div class="stream-toots__remove-cw" *ngIf="isThread && hasContentWarnings">
|
||||
<button class="stream-toots__remove-cw--button" (click)="removeCw()"
|
||||
title="remove content warnings">Remove CWs</button>
|
||||
</div>
|
||||
<div *ngIf="displayError" class="stream-toots__error">{{displayError}}</div>
|
||||
|
||||
<!-- data-simplebar -->
|
||||
<div class="stream-toots__status" *ngFor="let statusWrapper of statuses">
|
||||
<app-status
|
||||
[statusWrapper]="statusWrapper"
|
||||
[isThreadDisplay]="isThread"
|
||||
(browseAccountEvent)="browseAccount($event)"
|
||||
(browseHashtagEvent)="browseHashtag($event)"
|
||||
(browseThreadEvent)="browseThread($event)"></app-status>
|
||||
<a href class="stream-toots__remove-cw--button" (click)="removeCw()" title="remove content warnings">
|
||||
Remove CWs
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<app-waiting-animation *ngIf="isLoading" class="waiting-icon"></app-waiting-animation>
|
||||
<div class="stream-toots__content flexcroll" #statusstream (scroll)="onScroll()" tabindex="0">
|
||||
<div *ngIf="displayError" class="stream-toots__error">{{displayError}}</div>
|
||||
|
||||
<!-- data-simplebar -->
|
||||
<div class="stream-toots__status" *ngFor="let statusWrapper of statuses" #status>
|
||||
<app-status
|
||||
[statusWrapper]="statusWrapper" [isThreadDisplay]="isThread"
|
||||
(browseAccountEvent)="browseAccount($event)" (browseHashtagEvent)="browseHashtag($event)"
|
||||
(browseThreadEvent)="browseThread($event)"></app-status>
|
||||
</div>
|
||||
|
||||
<app-waiting-animation *ngIf="isLoading" class="waiting-icon"></app-waiting-animation>
|
||||
</div>
|
||||
</div>
|
|
@ -4,45 +4,64 @@
|
|||
.stream-toots {
|
||||
height: calc(100%);
|
||||
width: calc(100%);
|
||||
overflow: auto;
|
||||
|
||||
// overflow: auto;
|
||||
position: relative;
|
||||
|
||||
&__error {
|
||||
padding: 20px 20px 0 20px;
|
||||
color: rgb(255, 113, 113);
|
||||
}
|
||||
|
||||
&__content {
|
||||
height: calc(100%);
|
||||
overflow: auto;
|
||||
outline: none;
|
||||
:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__status:not(:last-child) {
|
||||
border: solid #06070b;
|
||||
border-width: 0 0 1px 0;
|
||||
}
|
||||
&__remove-cw {
|
||||
&__remove-cw {
|
||||
z-index: 100;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 20px;
|
||||
|
||||
padding: 5px;
|
||||
// border: solid #06070b;
|
||||
// border-width: 0 0 1px 0;
|
||||
height: 45px;
|
||||
// width: calc(100%);
|
||||
// position: relative;
|
||||
|
||||
&--button {
|
||||
@include clearButton;
|
||||
&--button {
|
||||
|
||||
// position: absolute;
|
||||
|
||||
// width: calc(80%);
|
||||
// margin-left: 40%;
|
||||
// transform: translateX(-40%);
|
||||
|
||||
width: calc(100%);
|
||||
padding: 5px 0;
|
||||
|
||||
z-index: 10;
|
||||
text-align: center;
|
||||
border: 3px $status-secondary-color double;
|
||||
|
||||
transition: all .2s;
|
||||
text-decoration: none;
|
||||
padding: 5px 5px;
|
||||
padding: 5px 10px;
|
||||
text-align: center;
|
||||
|
||||
border: 3px $status-secondary-color double;
|
||||
border: 0;
|
||||
|
||||
background-color: $color-secondary;
|
||||
background-color: $status-secondary-color;
|
||||
// background-color: rgb(238, 238, 238);
|
||||
color: white;
|
||||
|
||||
&:hover{
|
||||
$hover-color: $status-secondary-color;
|
||||
background-color: $hover-color;
|
||||
color: white;
|
||||
border: 3px $hover-color double;
|
||||
background-color: $status-secondary-color;
|
||||
background-color: rgb(238, 238, 238);
|
||||
color: black;
|
||||
|
||||
//border: 3px $hover-color double;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Component, OnInit, Input, ViewChild, ElementRef, OnDestroy, EventEmitter, Output } from '@angular/core';
|
||||
import { Component, OnInit, Input, ViewChild, ElementRef, OnDestroy, EventEmitter, Output, ViewChildren, QueryList } from '@angular/core';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { Store } from '@ngxs/store';
|
||||
|
@ -79,7 +79,7 @@ export class StreamStatusesComponent implements OnInit, OnDestroy {
|
|||
|
||||
this.streamsSubscription = this.streams$.subscribe((streams: StreamElement[]) => {
|
||||
let updatedStream = streams.find(x => x.id === this.streamElement.id);
|
||||
if(!updatedStream) return;
|
||||
if (!updatedStream) return;
|
||||
|
||||
if (this.hideBoosts !== updatedStream.hideBoosts
|
||||
|| this.hideBots !== updatedStream.hideBots
|
||||
|
@ -181,6 +181,12 @@ export class StreamStatusesComponent implements OnInit, OnDestroy {
|
|||
behavior: 'smooth'
|
||||
});
|
||||
}, 0);
|
||||
setTimeout(() => {
|
||||
stream.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'auto'
|
||||
});
|
||||
}, 250);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -272,6 +278,14 @@ export class StreamStatusesComponent implements OnInit, OnDestroy {
|
|||
return regAccounts;
|
||||
}
|
||||
|
||||
// @ViewChildren('status') private statusEls: QueryList<ElementRef>;
|
||||
focus(): boolean {
|
||||
setTimeout(() => {
|
||||
var element = this.statustream.nativeElement as HTMLElement;
|
||||
element.focus();
|
||||
}, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
private retrieveToots(): void {
|
||||
this.mastodonService.getTimeline(this.account, this._streamElement.type, null, null, this.streamingService.nbStatusPerIteration, this._streamElement.tag, this._streamElement.listId)
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
&__stream-selector {
|
||||
display: block;
|
||||
width: $stream-column-width;
|
||||
height: $stream-header-height;
|
||||
height: calc(#{$stream-header-height} - 1px);
|
||||
background-color: $column-header-background-color;
|
||||
text-decoration: none;
|
||||
color: whitesmoke;
|
||||
|
|
|
@ -6,6 +6,7 @@ import { StreamElement, StreamTypeEnum } from "../../states/streams.state";
|
|||
import { Status } from "../../services/models/mastodon.interfaces";
|
||||
import { AccountInfo } from "../../states/accounts.state";
|
||||
import { OpenThreadEvent } from "../../services/tools.service";
|
||||
import { StreamStatusesComponent } from './stream-statuses/stream-statuses.component';
|
||||
|
||||
@Component({
|
||||
selector: "app-stream",
|
||||
|
@ -25,6 +26,8 @@ export class StreamComponent implements OnInit {
|
|||
|
||||
private _streamElement: StreamElement;
|
||||
|
||||
@ViewChild(StreamStatusesComponent) private streamStatusesComponent: StreamStatusesComponent;
|
||||
|
||||
@Input('streamElement')
|
||||
set streamElement(stream: StreamElement) {
|
||||
switch (stream.type) {
|
||||
|
@ -57,6 +60,13 @@ export class StreamComponent implements OnInit {
|
|||
ngOnInit() {
|
||||
}
|
||||
|
||||
focus(): boolean {
|
||||
if (!this.overlayActive) {
|
||||
this.streamStatusesComponent.focus();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
goToTop(): boolean {
|
||||
this.goToTopSubject.next();
|
||||
return false;
|
||||
|
|
|
@ -214,11 +214,12 @@ export class ThreadComponent implements OnInit, OnDestroy {
|
|||
this.browseThreadEvent.next(openThreadEvent);
|
||||
}
|
||||
|
||||
removeCw() {
|
||||
removeCw(): boolean {
|
||||
const statuses = this.statusChildren.toArray();
|
||||
statuses.forEach(x => {
|
||||
x.removeContentWarning();
|
||||
});
|
||||
this.hasContentWarnings = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,18 +22,18 @@
|
|||
</app-waiting-animation>
|
||||
|
||||
<div *ngIf="!loadingRelationShip">
|
||||
<button class="profile-header__follow--button profile-header__follow--unfollowed" title="follow"
|
||||
<a href class="profile-header__follow--button profile-header__follow--unfollowed" title="follow"
|
||||
(click)="follow()" *ngIf="!relationship.following && !relationship.requested">
|
||||
<fa-icon [icon]="faUserRegular"></fa-icon>
|
||||
</button>
|
||||
<button class="profile-header__follow--button profile-header__follow--followed" title="unfollow"
|
||||
</a>
|
||||
<a href class="profile-header__follow--button profile-header__follow--followed" title="unfollow"
|
||||
(click)="unfollow()" *ngIf="relationship.following">
|
||||
<fa-icon [icon]="faUserCheck"></fa-icon>
|
||||
</button>
|
||||
<button class="profile-header__follow--button profile-header__follow--followed" title="pending"
|
||||
</a>
|
||||
<a href class="profile-header__follow--button profile-header__follow--followed" title="pending"
|
||||
(click)="unfollow()" *ngIf="relationship.requested">
|
||||
<fa-icon [icon]="faHourglassHalf"></fa-icon>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -42,7 +42,7 @@
|
|||
<app-waiting-animation *ngIf="isLoading" class="waiting-icon"></app-waiting-animation>
|
||||
|
||||
<div class="profile__moved" *ngIf="displayedAccount && displayedAccount.moved">
|
||||
<span innerHTML="{{displayedAccount | accountEmoji }}"></span> has moved to <br/><a href
|
||||
<span innerHTML="{{displayedAccount | accountEmoji }}"></span> has moved to <br /><a href
|
||||
(click)="openMigratedAccount(displayedAccount.moved)" class="profile__moved--link"
|
||||
title="open @{{displayedAccount.moved.acct }}">@{{displayedAccount.moved.acct }}</a>
|
||||
</div>
|
||||
|
@ -65,18 +65,18 @@
|
|||
</app-waiting-animation>
|
||||
|
||||
<div *ngIf="!loadingRelationShip">
|
||||
<button class="profile-header__follow--button profile-header__follow--unfollowed" title="follow"
|
||||
<a href class="profile-header__follow--button profile-header__follow--unfollowed" title="follow"
|
||||
(click)="follow()" *ngIf="!relationship.following && !relationship.requested">
|
||||
<fa-icon [icon]="faUserRegular"></fa-icon>
|
||||
</button>
|
||||
<button class="profile-header__follow--button profile-header__follow--followed" title="unfollow"
|
||||
</a>
|
||||
<a href class="profile-header__follow--button profile-header__follow--followed" title="unfollow"
|
||||
(click)="unfollow()" *ngIf="relationship.following">
|
||||
<fa-icon [icon]="faUserCheck"></fa-icon>
|
||||
</button>
|
||||
<button class="profile-header__follow--button profile-header__follow--followed" title="pending"
|
||||
</a>
|
||||
<a href class="profile-header__follow--button profile-header__follow--followed" title="pending"
|
||||
(click)="unfollow()" *ngIf="relationship.requested">
|
||||
<fa-icon [icon]="faHourglassHalf"></fa-icon>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="profile-header__state"
|
||||
|
|
|
@ -167,15 +167,26 @@ $floating-header-height: 60px;
|
|||
text-rendering: optimizeLegibility;
|
||||
|
||||
&--button {
|
||||
@include clearButton;
|
||||
display: inline-block;
|
||||
transition: all .2s;
|
||||
color: white;
|
||||
&:hover{
|
||||
color: rgb(216, 216, 216);
|
||||
}
|
||||
}
|
||||
|
||||
&--unfollowed {}
|
||||
|
||||
&--followed {
|
||||
transition: all .2s;
|
||||
color: #38abff;
|
||||
color: #5fbcff;
|
||||
color: #85ccff;
|
||||
|
||||
&:hover{
|
||||
color: #85ccff;
|
||||
color: #38abff;
|
||||
}
|
||||
}
|
||||
|
||||
&--waiting {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<div class="streams-selection-footer">
|
||||
<a class="stream-selection" *ngFor="let str of streams; let i=index" href (click)="onColumnSelection(i)" title="open {{getDisplayableName(str)}}">
|
||||
<span class="stream-selection__column-reprensentation"></span>
|
||||
</a>
|
||||
<a class="stream-selection" *ngFor="let str of streams; let i=index" href (click)="onColumnSelection(i)"
|
||||
title="open {{getDisplayableName(str.stream)}}">
|
||||
<span class="stream-selection__column-reprensentation"
|
||||
[class.stream-selection__column-reprensentation--selected]="str.isSelected"></span>
|
||||
</a>
|
||||
</div>
|
|
@ -1,29 +1,37 @@
|
|||
@import "variables";
|
||||
|
||||
.streams-selection-footer {
|
||||
width: calc(100%);
|
||||
height: $stream-selector-height;
|
||||
text-align: center;
|
||||
width: calc(100%);
|
||||
height: $stream-selector-height;
|
||||
text-align: center;
|
||||
|
||||
background-color: $color-secondary;
|
||||
background-color: $color-secondary;
|
||||
}
|
||||
|
||||
.stream-selection {
|
||||
display: inline-block;
|
||||
width: 9px;
|
||||
padding: 4px 5px 0 5px;
|
||||
height: $stream-selector-height;
|
||||
|
||||
&__column-reprensentation {
|
||||
display: inline-block;
|
||||
width: 5px;
|
||||
height: $stream-selector-height - 8px;
|
||||
background-color:$font-link-primary;
|
||||
width: 9px;
|
||||
padding: 4px 5px 0 5px;
|
||||
height: $stream-selector-height;
|
||||
|
||||
|
||||
}
|
||||
&__column-reprensentation {
|
||||
transition: all .2s;
|
||||
display: inline-block;
|
||||
width: 5px;
|
||||
height: $stream-selector-height - 8px;
|
||||
background-color: $font-link-primary;
|
||||
|
||||
&:hover &__column-reprensentation{
|
||||
background-color:$font-link-primary-hover;
|
||||
}
|
||||
}
|
||||
&--selected {
|
||||
height: ($stream-selector-height - 8px)/1.75;
|
||||
background-color: rgb(168, 168, 168);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover &__column-reprensentation {
|
||||
background-color: $font-link-primary-hover;
|
||||
|
||||
&--selected {
|
||||
background-color: rgb(255, 255, 255);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { StreamElement, StreamTypeEnum } from '../../states/streams.state';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { HotkeysService, Hotkey } from 'angular2-hotkeys';
|
||||
|
||||
import { StreamElement, StreamTypeEnum } from '../../states/streams.state';
|
||||
import { NavigationService } from '../../services/navigation.service';
|
||||
|
||||
@Component({
|
||||
|
@ -10,22 +12,65 @@ import { NavigationService } from '../../services/navigation.service';
|
|||
styleUrls: ['./streams-selection-footer.component.scss']
|
||||
})
|
||||
export class StreamsSelectionFooterComponent implements OnInit {
|
||||
streams: StreamElement[] = [];
|
||||
streams: SelectableStream[] = [];
|
||||
private streams$: Observable<StreamElement[]>;
|
||||
|
||||
constructor(
|
||||
private readonly hotkeysService: HotkeysService,
|
||||
private readonly navigationService: NavigationService,
|
||||
private readonly store: Store) {
|
||||
this.streams$ = this.store.select(state => state.streamsstatemodel.streams);
|
||||
|
||||
this.hotkeysService.add(new Hotkey('ctrl+right', (event: KeyboardEvent): boolean => {
|
||||
this.nextColumnSelected();
|
||||
return false;
|
||||
}));
|
||||
|
||||
this.hotkeysService.add(new Hotkey('ctrl+left', (event: KeyboardEvent): boolean => {
|
||||
this.previousColumnSelected();
|
||||
return false;
|
||||
}));
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.streams$.subscribe((streams: StreamElement[]) => {
|
||||
this.streams = streams;
|
||||
this.streams = streams.map(x => new SelectableStream(x));
|
||||
});
|
||||
}
|
||||
|
||||
private nextColumnSelected() {
|
||||
const nbStreams = this.streams.length;
|
||||
const selectedElement = this.streams.find(x => x.isSelected);
|
||||
let currentSelectionIndex = 0;
|
||||
if (selectedElement) {
|
||||
currentSelectionIndex = this.streams.indexOf(selectedElement);
|
||||
}
|
||||
|
||||
if(currentSelectionIndex < nbStreams - 1){
|
||||
this.onColumnSelection(currentSelectionIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private previousColumnSelected() {
|
||||
const selectedElement = this.streams.find(x => x.isSelected);
|
||||
let currentSelectionIndex = 0;
|
||||
if (selectedElement) {
|
||||
currentSelectionIndex = this.streams.indexOf(selectedElement);
|
||||
}
|
||||
|
||||
if(currentSelectionIndex > 0){
|
||||
this.onColumnSelection(currentSelectionIndex - 1);
|
||||
} else {
|
||||
this.onColumnSelection(0);
|
||||
}
|
||||
}
|
||||
|
||||
onColumnSelection(index: number): boolean {
|
||||
this.streams.forEach(x => x.isSelected = false);
|
||||
|
||||
const selectedStream = this.streams[index];
|
||||
selectedStream.isSelected = true;
|
||||
|
||||
this.navigationService.columnSelected(index);
|
||||
return false;
|
||||
}
|
||||
|
@ -52,3 +97,10 @@ export class StreamsSelectionFooterComponent implements OnInit {
|
|||
return `${prefix}@${stream.instance}`;
|
||||
}
|
||||
}
|
||||
|
||||
class SelectableStream {
|
||||
constructor(public readonly stream: StreamElement) {
|
||||
}
|
||||
|
||||
isSelected: boolean;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import { Component, OnInit, OnDestroy, QueryList, ViewChildren, ElementRef } from "@angular/core";
|
||||
import { Observable, Subscription } from "rxjs";
|
||||
import { Select } from "@ngxs/store";
|
||||
import scrollIntoView from "smooth-scroll-into-view-if-needed";
|
||||
|
||||
import { StreamElement } from "../../states/streams.state";
|
||||
import { NavigationService } from "../../services/navigation.service";
|
||||
import { StreamComponent } from '../../components/stream/stream.component';
|
||||
|
||||
@Component({
|
||||
selector: "app-streams-main-display",
|
||||
|
@ -12,6 +14,7 @@ import { NavigationService } from "../../services/navigation.service";
|
|||
})
|
||||
export class StreamsMainDisplayComponent implements OnInit, OnDestroy {
|
||||
|
||||
@ViewChildren(StreamComponent) private streamComponents: QueryList<StreamComponent>;
|
||||
@Select(state => state.streamsstatemodel.streams) streamElements$: Observable<StreamElement[]>;
|
||||
private columnSelectedSub: Subscription;
|
||||
|
||||
|
@ -33,8 +36,21 @@ export class StreamsMainDisplayComponent implements OnInit, OnDestroy {
|
|||
private focusOnColumn(columnIndex: number): void {
|
||||
if (columnIndex > -1) {
|
||||
setTimeout(() => {
|
||||
this.streamsElementRef.toArray()[columnIndex].nativeElement.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' });
|
||||
});
|
||||
let element = this.streamsElementRef.toArray()[columnIndex].nativeElement;
|
||||
element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' });
|
||||
|
||||
const scrolling = <Promise<any>><any>scrollIntoView(element, { behavior: 'smooth', block: 'nearest'});
|
||||
scrolling
|
||||
.then(() => {
|
||||
this.streamComponents.toArray()[columnIndex].focus();
|
||||
});
|
||||
|
||||
// setTimeout(() => {
|
||||
// this.streamComponents.toArray()[columnIndex].focus();
|
||||
// }, 500);
|
||||
}, 0);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -60,12 +60,12 @@ export class ToolsService {
|
|||
}
|
||||
|
||||
getSelectedAccounts(): AccountInfo[] {
|
||||
var regAccounts = <AccountInfo[]>this.store.snapshot().registeredaccounts.accounts;
|
||||
let regAccounts = <AccountInfo[]>this.store.snapshot().registeredaccounts.accounts;
|
||||
return regAccounts.filter(x => x.isSelected);
|
||||
}
|
||||
|
||||
getAccountSettings(account: AccountInfo): AccountSettings {
|
||||
var accountsSettings = <AccountSettings[]>this.store.snapshot().globalsettings.settings.accountSettings;
|
||||
let accountsSettings = <AccountSettings[]>this.store.snapshot().globalsettings.settings.accountSettings;
|
||||
let accountSettings = accountsSettings.find(x => x.accountId === account.id);
|
||||
if (!accountSettings) {
|
||||
accountSettings = new AccountSettings();
|
||||
|
|
|
@ -13,5 +13,5 @@
|
|||
padding: 0;
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
outline: inherit;
|
||||
// outline: inherit;
|
||||
}
|
Loading…
Reference in New Issue