commit
0f58252c61
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "sengi",
|
"name": "sengi",
|
||||||
"version": "1.5.0",
|
"version": "1.6.0",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"main": "main-electron.js",
|
"main": "main-electron.js",
|
||||||
"description": "A multi-account desktop client for Mastodon and Pleroma",
|
"description": "A multi-account desktop client for Mastodon and Pleroma",
|
||||||
|
@ -25,13 +25,14 @@
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^7.2.7",
|
"@angular/animations": "^7.2.16",
|
||||||
"@angular/cdk": "^7.2.7",
|
"@angular/cdk": "^7.3.7",
|
||||||
"@angular/common": "^7.2.7",
|
"@angular/common": "^7.2.7",
|
||||||
"@angular/compiler": "^7.2.7",
|
"@angular/compiler": "^7.2.7",
|
||||||
"@angular/core": "^7.2.7",
|
"@angular/core": "^7.2.7",
|
||||||
"@angular/forms": "^7.2.7",
|
"@angular/forms": "^7.2.7",
|
||||||
"@angular/http": "^7.2.7",
|
"@angular/http": "^7.2.7",
|
||||||
|
"@angular/material": "^16.2.1",
|
||||||
"@angular/platform-browser": "^7.2.7",
|
"@angular/platform-browser": "^7.2.7",
|
||||||
"@angular/platform-browser-dynamic": "^7.2.7",
|
"@angular/platform-browser-dynamic": "^7.2.7",
|
||||||
"@angular/pwa": "^0.12.4",
|
"@angular/pwa": "^0.12.4",
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { HttpModule } from "@angular/http";
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
import { NgModule, APP_INITIALIZER, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
|
import { NgModule, APP_INITIALIZER, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
|
||||||
import { RouterModule, Routes } from "@angular/router";
|
import { RouterModule, Routes } from "@angular/router";
|
||||||
|
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||||
// import { NgxElectronModule } from 'ngx-electron';
|
// import { NgxElectronModule } from 'ngx-electron';
|
||||||
|
|
||||||
import { NgxsModule } from '@ngxs/store';
|
import { NgxsModule } from '@ngxs/store';
|
||||||
|
@ -177,6 +178,7 @@ const routes: Routes = [
|
||||||
OwlDateTimeModule,
|
OwlDateTimeModule,
|
||||||
OwlNativeDateTimeModule,
|
OwlNativeDateTimeModule,
|
||||||
OverlayModule,
|
OverlayModule,
|
||||||
|
DragDropModule,
|
||||||
// NgxElectronModule,
|
// NgxElectronModule,
|
||||||
RouterModule.forRoot(routes),
|
RouterModule.forRoot(routes),
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,8 @@ export class CreateStatusComponent implements OnInit, OnDestroy {
|
||||||
this.detectAutosuggestion(value);
|
this.detectAutosuggestion(value);
|
||||||
this._status = value;
|
this._status = value;
|
||||||
|
|
||||||
|
this.languageService.autoDetectLang(value);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.autoGrow();
|
this.autoGrow();
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
|
@ -79,6 +79,8 @@ export class PollEditorComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadPollParameters(poll: Poll) {
|
private loadPollParameters(poll: Poll) {
|
||||||
|
if(!this.oldPoll) return;
|
||||||
|
|
||||||
const isMulti = poll.multiple;
|
const isMulti = poll.multiple;
|
||||||
|
|
||||||
this.entries.length = 0;
|
this.entries.length = 0;
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
<button type="submit" class="form-button"
|
<button type="submit" class="form-button"
|
||||||
title="add account"
|
title="add account"
|
||||||
[class.comrade__button]="isComrade">
|
[class.comrade__button]="isComrade">
|
||||||
<span *ngIf="!isLoading">Submit</span>
|
|
||||||
|
<span *ngIf="!isLoading && !this.isInstanceMultiAccountLoading">Submit</span>
|
||||||
|
<span *ngIf="!isLoading && this.isInstanceMultiAccountLoading" class="faq__warning">See FAQ</span>
|
||||||
<app-waiting-animation *ngIf="isLoading" class="waiting-icon"></app-waiting-animation>
|
<app-waiting-animation *ngIf="isLoading" class="waiting-icon"></app-waiting-animation>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
@ -29,5 +31,12 @@
|
||||||
allowfullscreen></iframe>
|
allowfullscreen></iframe>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="faq" *ngIf="isInstanceMultiAccount">
|
||||||
|
<p>
|
||||||
|
FAQ<br/>
|
||||||
|
<a href="https://github.com/NicolasConstant/sengi/wiki/How-to-add-multiple-accounts-from-the-same-instance" target="_blank">How to add multiple accounts from the same instance?</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -109,4 +109,21 @@ $comrade_red: #a50000;
|
||||||
background-color: $comrade_red;
|
background-color: $comrade_red;
|
||||||
background-position: 0 0;
|
background-position: 0 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.faq {
|
||||||
|
margin: 20px 0 0 0;
|
||||||
|
|
||||||
|
& a {
|
||||||
|
color: #ffcc00;
|
||||||
|
text-decoration: underline;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #ffe88a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__warning {
|
||||||
|
color: #ffdc52;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -6,13 +6,14 @@ import { RegisteredAppsStateModel, AppInfo, AddRegisteredApp } from '../../../st
|
||||||
import { AuthService, CurrentAuthProcess } from '../../../services/auth.service';
|
import { AuthService, CurrentAuthProcess } from '../../../services/auth.service';
|
||||||
import { AppData } from '../../../services/models/mastodon.interfaces';
|
import { AppData } from '../../../services/models/mastodon.interfaces';
|
||||||
import { NotificationService } from '../../../services/notification.service';
|
import { NotificationService } from '../../../services/notification.service';
|
||||||
|
import { ToolsService } from '../../../services/tools.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-add-new-account',
|
selector: 'app-add-new-account',
|
||||||
templateUrl: './add-new-account.component.html',
|
templateUrl: './add-new-account.component.html',
|
||||||
styleUrls: ['./add-new-account.component.scss']
|
styleUrls: ['./add-new-account.component.scss']
|
||||||
})
|
})
|
||||||
export class AddNewAccountComponent implements OnInit {
|
export class AddNewAccountComponent implements OnInit {
|
||||||
private blockList = ['gab.com', 'gab.ai', 'cyzed.com'];
|
private blockList = ['gab.com', 'gab.ai', 'cyzed.com'];
|
||||||
private comradeList = ['juche.town'];
|
private comradeList = ['juche.town'];
|
||||||
|
|
||||||
|
@ -24,12 +25,14 @@ export class AddNewAccountComponent implements OnInit {
|
||||||
set setInstance(value: string) {
|
set setInstance(value: string) {
|
||||||
this.instance = value.replace('http://', '').replace('https://', '').replace('/', '').toLowerCase().trim();
|
this.instance = value.replace('http://', '').replace('https://', '').replace('/', '').toLowerCase().trim();
|
||||||
this.checkComrad();
|
this.checkComrad();
|
||||||
|
this.checkInstanceMultiAccount(value);
|
||||||
}
|
}
|
||||||
get setInstance(): string {
|
get setInstance(): string {
|
||||||
return this.instance;
|
return this.instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private readonly toolsService: ToolsService,
|
||||||
private readonly notificationService: NotificationService,
|
private readonly notificationService: NotificationService,
|
||||||
private readonly authService: AuthService,
|
private readonly authService: AuthService,
|
||||||
private readonly store: Store) { }
|
private readonly store: Store) { }
|
||||||
|
@ -51,8 +54,27 @@ export class AddNewAccountComponent implements OnInit {
|
||||||
this.isComrade = false;
|
this.isComrade = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isInstanceMultiAccount: boolean;
|
||||||
|
isInstanceMultiAccountLoading: boolean;
|
||||||
|
checkInstanceMultiAccount(value: string) {
|
||||||
|
if(value) {
|
||||||
|
const instances: string[] = this.toolsService.getAllAccounts().map(x => x.instance);
|
||||||
|
if(instances && instances.indexOf(value) > -1){
|
||||||
|
this.isInstanceMultiAccount = true;
|
||||||
|
this.isInstanceMultiAccountLoading = true;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.isInstanceMultiAccountLoading = false;
|
||||||
|
}, 2000);
|
||||||
|
} else {
|
||||||
|
this.isInstanceMultiAccount = false;
|
||||||
|
this.isInstanceMultiAccountLoading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onSubmit(): boolean {
|
onSubmit(): boolean {
|
||||||
if(this.isLoading || !this.instance) return false;
|
if(this.isLoading || !this.instance || this.isInstanceMultiAccountLoading) return false;
|
||||||
|
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
|
|
||||||
|
|
|
@ -62,12 +62,20 @@
|
||||||
<a href (click)="onRemoveLang(l)" class="form-button language__entry__action sound__play">remove</a>
|
<a href (click)="onRemoveLang(l)" class="form-button language__entry__action sound__play">remove</a>
|
||||||
</div>
|
</div>
|
||||||
<input type="text" (input)="onSearchLang($event.target.value)" [(ngModel)]="searchLang"
|
<input type="text" (input)="onSearchLang($event.target.value)" [(ngModel)]="searchLang"
|
||||||
placeholder="Find Language" autocomplete="off" class="form-control form-control-sm language__search"/>
|
placeholder="Find Language" autocomplete="off"
|
||||||
|
class="form-control form-control-sm language__search" />
|
||||||
<div *ngFor="let l of searchedLangs" class="language__entry">
|
<div *ngFor="let l of searchedLangs" class="language__entry">
|
||||||
<span class="language__entry__name">{{ l.name }} ({{l.iso639}})</span>
|
<span class="language__entry__name">{{ l.name }} ({{l.iso639}})</span>
|
||||||
<a href (click)="onAddLang(l)" class="form-button language__entry__action sound__play">add</a>
|
<a href (click)="onAddLang(l)" class="form-button language__entry__action sound__play">add</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<input class="sub-section__checkbox" [(ngModel)]="disableLangAutodetectEnabled"
|
||||||
|
(change)="onDisableLangAutodetectChanged()" type="checkbox" name="disableLangAutodetec"
|
||||||
|
value="disableLangAutodetec" id="disableLangAutodetec">
|
||||||
|
<label class="noselect sub-section__label" for="disableLangAutodetec">disable language autodetection</label>
|
||||||
</div>
|
</div>
|
||||||
<h4 class="panel__subtitle">Twitter Bridge</h4>
|
<h4 class="panel__subtitle">Twitter Bridge</h4>
|
||||||
<div class="sub-section">
|
<div class="sub-section">
|
||||||
|
@ -159,7 +167,8 @@
|
||||||
|
|
||||||
<input class="sub-section__checkbox" [checked]="timeLineHeader === 6" (change)="onTimeLineHeaderChange(6)"
|
<input class="sub-section__checkbox" [checked]="timeLineHeader === 6" (change)="onTimeLineHeaderChange(6)"
|
||||||
type="radio" name="timelineheader-6" value="timelineheader-6" id="timelineheader-6">
|
type="radio" name="timelineheader-6" value="timelineheader-6" id="timelineheader-6">
|
||||||
<label class="noselect sub-section__label" for="timelineheader-6">Title - Account Icon - Username - Domain Name</label>
|
<label class="noselect sub-section__label" for="timelineheader-6">Title - Account Icon - Username - Domain
|
||||||
|
Name</label>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<span class="sub-section__title">loading behavior:</span><br />
|
<span class="sub-section__title">loading behavior:</span><br />
|
||||||
|
@ -186,7 +195,8 @@
|
||||||
<input class="sub-section__checkbox" [(ngModel)]="autoFollowOnListEnabled"
|
<input class="sub-section__checkbox" [(ngModel)]="autoFollowOnListEnabled"
|
||||||
(change)="onAutoFollowOnListChanged()" type="checkbox" name="onAutoFollowOnListChanged"
|
(change)="onAutoFollowOnListChanged()" type="checkbox" name="onAutoFollowOnListChanged"
|
||||||
value="onAutoFollowOnListChanged" id="onAutoFollowOnListChanged">
|
value="onAutoFollowOnListChanged" id="onAutoFollowOnListChanged">
|
||||||
<label class="noselect sub-section__label" for="onAutoFollowOnListChanged">autofollow accounts when adding to list</label>
|
<label class="noselect sub-section__label" for="onAutoFollowOnListChanged">autofollow accounts when
|
||||||
|
adding to list</label>
|
||||||
<br>
|
<br>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -199,6 +209,20 @@
|
||||||
<label class="noselect sub-section__label" for="disableRemoteFetching">disable remote status
|
<label class="noselect sub-section__label" for="disableRemoteFetching">disable remote status
|
||||||
fetching</label>
|
fetching</label>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
<input class="sub-section__checkbox" [(ngModel)]="enableAltLabelEnabled"
|
||||||
|
(change)="onEnableAltLabelChanged()" type="checkbox" name="enableAltLabel"
|
||||||
|
value="enableAltLabel" id="enableAltLabel">
|
||||||
|
<label class="noselect sub-section__label" for="enableAltLabel">enable alt label</label>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<input class="sub-section__checkbox" [(ngModel)]="enableFreezeAvatarEnabled"
|
||||||
|
(change)="onEnableFreezeAvatarChanged()" type="checkbox" name="enableFreezeAvatar"
|
||||||
|
value="enableFreezeAvatar" id="enableFreezeAvatar">
|
||||||
|
<label class="noselect sub-section__label" for="enableFreezeAvatar">freeze animated avatar</label>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
reorder account's icons: <a href class="toogle-lock-icon-menu" (click)="toogleLockIconMenu()"><span *ngIf="iconMenuLocked">Unlock Icons</span><span *ngIf="!iconMenuLocked">Lock Icons</span></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4 class="panel__subtitle">About</h4>
|
<h4 class="panel__subtitle">About</h4>
|
||||||
|
|
|
@ -153,4 +153,22 @@
|
||||||
background-color: #32384d;
|
background-color: #32384d;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.toogle-lock-icon-menu {
|
||||||
|
display: block;
|
||||||
|
padding: 3px 40px;
|
||||||
|
width: 170px;
|
||||||
|
|
||||||
|
float: right;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
color: white;
|
||||||
|
background-color: #1f2330;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: #32384d;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -29,6 +29,9 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||||
disableRemoteStatusFetchingEnabled: boolean;
|
disableRemoteStatusFetchingEnabled: boolean;
|
||||||
disableAvatarNotificationsEnabled: boolean;
|
disableAvatarNotificationsEnabled: boolean;
|
||||||
disableSoundsEnabled: boolean;
|
disableSoundsEnabled: boolean;
|
||||||
|
disableLangAutodetectEnabled: boolean;
|
||||||
|
enableAltLabelEnabled: boolean;
|
||||||
|
enableFreezeAvatarEnabled: boolean;
|
||||||
version: string;
|
version: string;
|
||||||
|
|
||||||
hasPleromaAccount: boolean;
|
hasPleromaAccount: boolean;
|
||||||
|
@ -146,11 +149,21 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||||
this.twitterBridgeInstance = settings.twitterBridgeInstance;
|
this.twitterBridgeInstance = settings.twitterBridgeInstance;
|
||||||
|
|
||||||
this.configuredLangs = this.languageService.getConfiguredLanguages();
|
this.configuredLangs = this.languageService.getConfiguredLanguages();
|
||||||
|
this.disableLangAutodetectEnabled = settings.disableLangAutodetec;
|
||||||
|
this.enableAltLabelEnabled = settings.enableAltLabel;
|
||||||
|
this.enableFreezeAvatarEnabled = settings.enableFreezeAvatar;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if(this.languageSub) this.languageSub.unsubscribe();
|
if(this.languageSub) this.languageSub.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iconMenuLocked = true;
|
||||||
|
toogleLockIconMenu(): boolean {
|
||||||
|
this.navigationService.changeIconMenuState(this.iconMenuLocked);
|
||||||
|
this.iconMenuLocked = ! this.iconMenuLocked;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
onSearchLang(input: string) {
|
onSearchLang(input: string) {
|
||||||
this.searchedLangs = this.languageService.searchLanguage(input);
|
this.searchedLangs = this.languageService.searchLanguage(input);
|
||||||
|
@ -273,6 +286,27 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onEnableFreezeAvatarChanged(){
|
||||||
|
this.notifyRestartNeeded();
|
||||||
|
let settings = this.settingsService.getSettings();
|
||||||
|
settings.enableFreezeAvatar = this.enableFreezeAvatarEnabled;
|
||||||
|
this.settingsService.saveSettings(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
onEnableAltLabelChanged(){
|
||||||
|
this.notifyRestartNeeded();
|
||||||
|
let settings = this.settingsService.getSettings();
|
||||||
|
settings.enableAltLabel = this.enableAltLabelEnabled;
|
||||||
|
this.settingsService.saveSettings(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDisableLangAutodetectChanged() {
|
||||||
|
this.notifyRestartNeeded();
|
||||||
|
let settings = this.settingsService.getSettings();
|
||||||
|
settings.disableLangAutodetec = this.disableLangAutodetectEnabled;
|
||||||
|
this.settingsService.saveSettings(settings);
|
||||||
|
}
|
||||||
|
|
||||||
onDisableAutofocusChanged() {
|
onDisableAutofocusChanged() {
|
||||||
this.notifyRestartNeeded();
|
this.notifyRestartNeeded();
|
||||||
let settings = this.settingsService.getSettings();
|
let settings = this.settingsService.getSettings();
|
||||||
|
|
|
@ -8,27 +8,36 @@
|
||||||
<fa-icon [icon]="faSearch"></fa-icon>
|
<fa-icon [icon]="faSearch"></fa-icon>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div *ngFor="let account of accounts">
|
<div *ngIf="!iconMenuIsDraggable">
|
||||||
<app-account-icon [account]="account" (toogleAccountNotify)="onToogleAccountNotify($event)"
|
<div *ngFor="let account of accounts">
|
||||||
(openMenuNotify)="onOpenMenuNotify($event)">
|
<app-account-icon [account]="account" (toogleAccountNotify)="onToogleAccountNotify($event)"
|
||||||
</app-account-icon>
|
(openMenuNotify)="onOpenMenuNotify($event)">
|
||||||
|
</app-account-icon>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="iconMenuIsDraggable" cdkDropList [cdkDropListData]="accounts" (cdkDropListDropped)="onDrop($event)">
|
||||||
|
<div *ngFor="let account of accounts" cdkDrag class="draggable">
|
||||||
|
<fa-icon class="draggable__icon" [icon]="faArrowsAltV"></fa-icon>
|
||||||
|
<img class="draggable__avatar" src="{{ account.avatar }}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<a class="left-bar-button left-bar-button--add left-bar-link" [ngClass]="{'no-accounts': hasAccounts === false }"
|
<a class="left-bar-button left-bar-button--add left-bar-link" [ngClass]="{'no-accounts': hasAccounts === false }"
|
||||||
href title="add new account" (click)="addNewAccount()" (contextmenu)="addNewAccount()">
|
href title="add new account" (click)="addNewAccount()" (contextmenu)="addNewAccount()">
|
||||||
<fa-icon [icon]="faPlus"></fa-icon>
|
<fa-icon [icon]="faPlus"></fa-icon>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
||||||
<a class="left-bar-button left-bar-button--scheduled left-bar-button--bottom left-bar-link" href title="scheduled statuses"
|
<a class="left-bar-button left-bar-button--scheduled left-bar-button--bottom left-bar-link" href
|
||||||
*ngIf="hasAccounts && hasScheduledStatuses"
|
title="scheduled statuses" *ngIf="hasAccounts && hasScheduledStatuses" (click)="openScheduledStatuses()"
|
||||||
(click)="openScheduledStatuses()"
|
|
||||||
(contextmenu)="openScheduledStatuses()">
|
(contextmenu)="openScheduledStatuses()">
|
||||||
<fa-icon [icon]="faCalendarAlt"></fa-icon>
|
<fa-icon [icon]="faCalendarAlt"></fa-icon>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a class="left-bar-button left-bar-button--cog left-bar-button--bottom left-bar-link" href title="settings" (click)="openSettings()"
|
<a class="left-bar-button left-bar-button--cog left-bar-button--bottom left-bar-link" href title="settings"
|
||||||
(contextmenu)="openSettings()">
|
(click)="openSettings()" (contextmenu)="openSettings()">
|
||||||
<fa-icon [icon]="faCog"></fa-icon>
|
<fa-icon [icon]="faCog"></fa-icon>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
|
@ -82,4 +82,38 @@ $height-button: 40px;
|
||||||
.no-accounts {
|
.no-accounts {
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
// color: cornflowerblue;
|
// color: cornflowerblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$draggable-accent-color: #47e927;
|
||||||
|
// $draggable-accent-color: #a8ff97;
|
||||||
|
.draggable {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
margin: auto;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
|
border: 2px solid #df0adf;
|
||||||
|
border: 2px solid $draggable-accent-color;
|
||||||
|
border-radius: 2px;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&__avatar {
|
||||||
|
width: calc(100%);
|
||||||
|
opacity: .8;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
float: left;
|
||||||
|
z-index: 5;
|
||||||
|
color:$draggable-accent-color;
|
||||||
|
|
||||||
|
top: 6px;
|
||||||
|
left: 12px;
|
||||||
|
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,12 +1,13 @@
|
||||||
import { Component, OnInit, OnDestroy } from "@angular/core";
|
import { Component, OnInit, OnDestroy } from "@angular/core";
|
||||||
|
import { CdkDragDrop, moveItemInArray } from "@angular/cdk/drag-drop";
|
||||||
import { Subscription, Observable } from "rxjs";
|
import { Subscription, Observable } from "rxjs";
|
||||||
import { Store } from "@ngxs/store";
|
import { Store } from "@ngxs/store";
|
||||||
import { faPlus, faCog, faSearch } from "@fortawesome/free-solid-svg-icons";
|
import { faPlus, faCog, faSearch, faArrowsAltV } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { faCommentAlt, faCalendarAlt } from "@fortawesome/free-regular-svg-icons";
|
import { faCommentAlt, faCalendarAlt } from "@fortawesome/free-regular-svg-icons";
|
||||||
import { HotkeysService, Hotkey } from 'angular2-hotkeys';
|
import { HotkeysService, Hotkey } from 'angular2-hotkeys';
|
||||||
|
|
||||||
import { AccountWrapper } from "../../models/account.models";
|
import { AccountWrapper } from "../../models/account.models";
|
||||||
import { AccountInfo, SelectAccount } from "../../states/accounts.state";
|
import { AccountInfo, ReorderAccounts, SelectAccount } from "../../states/accounts.state";
|
||||||
import { NavigationService, LeftPanelType } from "../../services/navigation.service";
|
import { NavigationService, LeftPanelType } from "../../services/navigation.service";
|
||||||
import { UserNotificationService, UserNotification } from '../../services/user-notification.service';
|
import { UserNotificationService, UserNotification } from '../../services/user-notification.service';
|
||||||
import { ToolsService } from '../../services/tools.service';
|
import { ToolsService } from '../../services/tools.service';
|
||||||
|
@ -24,6 +25,7 @@ export class LeftSideBarComponent implements OnInit, OnDestroy {
|
||||||
faPlus = faPlus;
|
faPlus = faPlus;
|
||||||
faCog = faCog;
|
faCog = faCog;
|
||||||
faCalendarAlt = faCalendarAlt;
|
faCalendarAlt = faCalendarAlt;
|
||||||
|
faArrowsAltV = faArrowsAltV;
|
||||||
|
|
||||||
accounts: AccountWithNotificationWrapper[] = [];
|
accounts: AccountWithNotificationWrapper[] = [];
|
||||||
hasAccounts: boolean;
|
hasAccounts: boolean;
|
||||||
|
@ -33,6 +35,7 @@ export class LeftSideBarComponent implements OnInit, OnDestroy {
|
||||||
private accountSub: Subscription;
|
private accountSub: Subscription;
|
||||||
private scheduledSub: Subscription;
|
private scheduledSub: Subscription;
|
||||||
private notificationSub: Subscription;
|
private notificationSub: Subscription;
|
||||||
|
private draggableIconMenuSub: Subscription;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly settingsService: SettingsService,
|
private readonly settingsService: SettingsService,
|
||||||
|
@ -103,7 +106,13 @@ export class LeftSideBarComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iconMenuIsDraggable = false;
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
this.draggableIconMenuSub = this.navigationService.enableDraggableIconMenu.subscribe(x => {
|
||||||
|
this.iconMenuIsDraggable = x;
|
||||||
|
});
|
||||||
|
|
||||||
this.accountSub = this.accounts$.subscribe((accounts: AccountInfo[]) => {
|
this.accountSub = this.accounts$.subscribe((accounts: AccountInfo[]) => {
|
||||||
if (accounts) {
|
if (accounts) {
|
||||||
//Update and Add
|
//Update and Add
|
||||||
|
@ -164,6 +173,17 @@ export class LeftSideBarComponent implements OnInit, OnDestroy {
|
||||||
this.accountSub.unsubscribe();
|
this.accountSub.unsubscribe();
|
||||||
this.notificationSub.unsubscribe();
|
this.notificationSub.unsubscribe();
|
||||||
this.scheduledSub.unsubscribe();
|
this.scheduledSub.unsubscribe();
|
||||||
|
this.draggableIconMenuSub.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
onDrop(event: CdkDragDrop<AccountWithNotificationWrapper[]>) {
|
||||||
|
if (event.previousContainer === event.container) {
|
||||||
|
moveItemInArray(event.container.data,
|
||||||
|
event.previousIndex,
|
||||||
|
event.currentIndex);
|
||||||
|
|
||||||
|
this.store.dispatch([new ReorderAccounts(this.accounts.map(x => x.info))])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onToogleAccountNotify(acc: AccountWrapper) {
|
onToogleAccountNotify(acc: AccountWrapper) {
|
||||||
|
|
|
@ -27,7 +27,13 @@
|
||||||
<ng-template contextMenuItem (execute)="unmuteConversation()" *ngIf="statusWrapper && isOwnerSelected && displayedStatus.muted">
|
<ng-template contextMenuItem (execute)="unmuteConversation()" *ngIf="statusWrapper && isOwnerSelected && displayedStatus.muted">
|
||||||
Unmute conversation
|
Unmute conversation
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template contextMenuItem divider="true"></ng-template>
|
<ng-template contextMenuItem (execute)="hideBoosts()" *ngIf="!isOwnerSelected && this.relationship && this.relationship.following && this.relationship.showing_reblogs">
|
||||||
|
Hide boosts from @{{ this.username }}
|
||||||
|
</ng-template>
|
||||||
|
<ng-template contextMenuItem (execute)="unhideBoosts()" *ngIf="!isOwnerSelected && this.relationship && this.relationship.following && !this.relationship.showing_reblogs">
|
||||||
|
Unhide boosts from @{{ this.username }}
|
||||||
|
</ng-template>
|
||||||
|
<ng-template contextMenuItem divider="true" *ngIf="!isOwnerSelected"></ng-template>
|
||||||
<ng-template contextMenuItem (execute)="muteAccount()" *ngIf="!isOwnerSelected && this.relationship && !this.relationship.muting">
|
<ng-template contextMenuItem (execute)="muteAccount()" *ngIf="!isOwnerSelected && this.relationship && !this.relationship.muting">
|
||||||
Mute @{{ this.username }}
|
Mute @{{ this.username }}
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -40,6 +46,14 @@
|
||||||
<ng-template contextMenuItem (execute)="unblockAccount()" *ngIf="!isOwnerSelected && this.relationship && this.relationship.blocking">
|
<ng-template contextMenuItem (execute)="unblockAccount()" *ngIf="!isOwnerSelected && this.relationship && this.relationship.blocking">
|
||||||
Unblock @{{ this.username }}
|
Unblock @{{ this.username }}
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
<ng-template contextMenuItem divider="true" *ngIf="!isOwnerSelected"></ng-template>
|
||||||
|
<ng-template contextMenuItem (execute)="blockDomain()" *ngIf="!isOwnerSelected && this.relationship && !this.relationship.domain_blocking">
|
||||||
|
Block domain {{ this.domain }}
|
||||||
|
</ng-template>
|
||||||
|
<ng-template contextMenuItem (execute)="unblockDomain()" *ngIf="!isOwnerSelected && this.relationship && this.relationship.domain_blocking">
|
||||||
|
Unblock domain {{ this.domain }}
|
||||||
|
</ng-template>
|
||||||
|
<ng-template contextMenuItem divider="true" *ngIf="isOwnerSelected"></ng-template>
|
||||||
<ng-template contextMenuItem (execute)="pinOnProfile()" *ngIf="statusWrapper && isOwnerSelected && !displayedStatus.pinned && displayedStatus.visibility === 'public'">
|
<ng-template contextMenuItem (execute)="pinOnProfile()" *ngIf="statusWrapper && isOwnerSelected && !displayedStatus.pinned && displayedStatus.visibility === 'public'">
|
||||||
Pin on profile
|
Pin on profile
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
|
@ -25,6 +25,7 @@ export class StatusUserContextMenuComponent implements OnInit, OnDestroy {
|
||||||
private loadedAccounts: AccountInfo[];
|
private loadedAccounts: AccountInfo[];
|
||||||
displayedStatus: Status;
|
displayedStatus: Status;
|
||||||
username: string;
|
username: string;
|
||||||
|
domain: string;
|
||||||
isOwnerSelected: boolean;
|
isOwnerSelected: boolean;
|
||||||
|
|
||||||
isEditingAvailable: boolean;
|
isEditingAvailable: boolean;
|
||||||
|
@ -74,6 +75,7 @@ export class StatusUserContextMenuComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.username = account.acct.split('@')[0];
|
this.username = account.acct.split('@')[0];
|
||||||
|
this.domain = account.acct.split('@')[1];
|
||||||
this.fullHandle = this.toolsService.getAccountFullHandle(account);
|
this.fullHandle = this.toolsService.getAccountFullHandle(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,6 +169,38 @@ export class StatusUserContextMenuComponent implements OnInit, OnDestroy {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hideBoosts(): boolean {
|
||||||
|
const acc = this.toolsService.getSelectedAccounts()[0];
|
||||||
|
|
||||||
|
this.toolsService.findAccount(acc, this.fullHandle)
|
||||||
|
.then(async (target: Account) => {
|
||||||
|
const relationship = await this.mastodonService.hideBoosts(acc, target);
|
||||||
|
this.relationship = relationship;
|
||||||
|
this.relationshipChanged.next(relationship);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
this.notificationService.notifyHttpError(err, acc);
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unhideBoosts(): boolean {
|
||||||
|
const acc = this.toolsService.getSelectedAccounts()[0];
|
||||||
|
|
||||||
|
this.toolsService.findAccount(acc, this.fullHandle)
|
||||||
|
.then(async (target: Account) => {
|
||||||
|
const relationship = await this.mastodonService.unhideBoosts(acc, target);
|
||||||
|
this.relationship = relationship;
|
||||||
|
this.relationshipChanged.next(relationship);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
this.notificationService.notifyHttpError(err, acc);
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
muteAccount(): boolean {
|
muteAccount(): boolean {
|
||||||
const acc = this.toolsService.getSelectedAccounts()[0];
|
const acc = this.toolsService.getSelectedAccounts()[0];
|
||||||
|
|
||||||
|
@ -241,6 +275,37 @@ export class StatusUserContextMenuComponent implements OnInit, OnDestroy {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blockDomain(): boolean {
|
||||||
|
const response = confirm(`Are you really sure you want to block the entire ${this.domain} domain? You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.`);
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
const acc = this.toolsService.getSelectedAccounts()[0];
|
||||||
|
|
||||||
|
this.mastodonService.blockDomain(acc, this.domain)
|
||||||
|
.then(_ => {
|
||||||
|
this.relationship.domain_blocking = true;
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
this.notificationService.notifyHttpError(err, acc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unblockDomain(): boolean {
|
||||||
|
const acc = this.toolsService.getSelectedAccounts()[0];
|
||||||
|
|
||||||
|
this.mastodonService.blockDomain(acc, this.domain)
|
||||||
|
.then(_ => {
|
||||||
|
this.relationship.domain_blocking = false;
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
this.notificationService.notifyHttpError(err, acc);
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
muteConversation(): boolean {
|
muteConversation(): boolean {
|
||||||
const selectedAccount = this.toolsService.getSelectedAccounts()[0];
|
const selectedAccount = this.toolsService.getSelectedAccounts()[0];
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<div class="image">
|
<div class="image">
|
||||||
|
<div class="image__alt" *ngIf="displayAltLabel">ALT</div>
|
||||||
<a href class="image__link" (click)="openExternal()" (auxclick)="openExternal()" title="open image">
|
<a href class="image__link" (click)="openExternal()" (auxclick)="openExternal()" title="open image">
|
||||||
<fa-icon class="image__link--icon" [icon]="faLink"></fa-icon>
|
<fa-icon class="image__link--icon" [icon]="faLink"></fa-icon>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -29,6 +29,24 @@
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__alt {
|
||||||
|
display: inline;
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
bottom: 5px;
|
||||||
|
left: 5px;
|
||||||
|
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: bolder;
|
||||||
|
|
||||||
|
background-color: rgba($color: #000000, $alpha: 0.5);
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 2px 5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
img,
|
img,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||||
import { faLink } from "@fortawesome/free-solid-svg-icons";
|
import { faLink } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
|
||||||
|
import { SettingsService } from '../../../../../services/settings.service';
|
||||||
import { Attachment } from '../../../../../services/models/mastodon.interfaces';
|
import { Attachment } from '../../../../../services/models/mastodon.interfaces';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -10,11 +11,16 @@ import { Attachment } from '../../../../../services/models/mastodon.interfaces';
|
||||||
})
|
})
|
||||||
export class AttachementImageComponent implements OnInit {
|
export class AttachementImageComponent implements OnInit {
|
||||||
faLink = faLink;
|
faLink = faLink;
|
||||||
|
displayAltLabel: boolean;
|
||||||
|
|
||||||
@Input() attachment: Attachment;
|
@Input() attachment: Attachment;
|
||||||
@Output() openEvent = new EventEmitter();
|
@Output() openEvent = new EventEmitter();
|
||||||
|
|
||||||
constructor() { }
|
constructor(
|
||||||
|
private readonly settingsService: SettingsService
|
||||||
|
) {
|
||||||
|
this.displayAltLabel = this.settingsService.getSettings().enableAltLabel;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ export class StatusTranslateComponent implements OnInit, OnDestroy {
|
||||||
.then(canTranslate => {
|
.then(canTranslate => {
|
||||||
if (canTranslate
|
if (canTranslate
|
||||||
&& !this.status.isRemote
|
&& !this.status.isRemote
|
||||||
|
&& this.status.status.language
|
||||||
&& this.configuredLanguages.length > 0
|
&& this.configuredLanguages.length > 0
|
||||||
&& this.configuredLanguages.findIndex(x => x.iso639 === this.status.status.language) === -1) {
|
&& this.configuredLanguages.findIndex(x => x.iso639 === this.status.status.language) === -1) {
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<div class="reblog" *ngIf="reblog">
|
<div class="reblog" *ngIf="reblog">
|
||||||
<a class="reblog__profile-link" href title="{{ status.account.acct }}"
|
<a class="reblog__profile-link" href title="{{ status.account.acct }}"
|
||||||
(click)="openAccount(status.account)"
|
(click)="openAccount(status.account)"
|
||||||
(auxclick)="openUrl(status.account.url)"><span innerHTML="{{ status.account | accountEmoji }}"></span> <img *ngIf="reblog" class="reblog__avatar" src="{{ status.account.avatar | ensureHttps }}" /></a> boosted
|
(auxclick)="openUrl(status.account.url)"><span innerHTML="{{ status.account | accountEmoji }}"></span> <img *ngIf="reblog" class="reblog__avatar" src="{{ getAvatar(status.account) | ensureHttps }}" /></a> boosted
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="statusWrapper.status.pinned && !notificationType" class="pinned">
|
<div *ngIf="statusWrapper.status.pinned && !notificationType" class="pinned">
|
||||||
<div class="notification--icon">
|
<div class="notification--icon">
|
||||||
|
@ -60,9 +60,9 @@
|
||||||
<div [ngClass]="{'notification--status': notificationAccount }">
|
<div [ngClass]="{'notification--status': notificationAccount }">
|
||||||
<a href class="status__profile-link" title="{{displayedStatus.account.acct}}"
|
<a href class="status__profile-link" title="{{displayedStatus.account.acct}}"
|
||||||
(click)="openAccount(displayedStatus.account)" (auxclick)="openUrl(displayedStatus.account.url)">
|
(click)="openAccount(displayedStatus.account)" (auxclick)="openUrl(displayedStatus.account.url)">
|
||||||
<img [class.status__avatar--boosted]="reblog || notificationAccount" class="status__avatar" src="{{ displayedStatus.account.avatar | ensureHttps }}" />
|
<img [class.status__avatar--boosted]="reblog || notificationAccount" class="status__avatar" src="{{ getAvatar(displayedStatus.account) | ensureHttps }}" />
|
||||||
<!-- <img *ngIf="reblog" class="status__avatar--reblog" src="{{ status.account.avatar }}" /> -->
|
<!-- <img *ngIf="reblog" class="status__avatar--reblog" src="{{ status.account.avatar }}" /> -->
|
||||||
<img *ngIf="notificationAccount" class="notification--avatar" src="{{ notificationAccount.avatar | ensureHttps }}" />
|
<img *ngIf="notificationAccount" class="notification--avatar" src="{{ getAvatar(notificationAccount) | ensureHttps }}" />
|
||||||
<span class="status__name">
|
<span class="status__name">
|
||||||
<span class="status__name--displayname"
|
<span class="status__name--displayname"
|
||||||
innerHTML="{{displayedStatus.account | accountEmoji}}"></span><span
|
innerHTML="{{displayedStatus.account | accountEmoji}}"></span><span
|
||||||
|
@ -109,6 +109,11 @@
|
||||||
<span class="status__content-warning--title">sensitive content</span>
|
<span class="status__content-warning--title">sensitive content</span>
|
||||||
<span innerHTML="{{ contentWarningText }}"></span>
|
<span innerHTML="{{ contentWarningText }}"></span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
<div class="status__content-warning__closed" *ngIf="!isContentWarned && contentWarningText" title="content warning">
|
||||||
|
<span innerHTML="{{ contentWarningText }}"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<app-databinded-text #databindedtext class="status__content" *ngIf="!isContentWarned" [text]="statusContent" [selected]="isSelected"
|
<app-databinded-text #databindedtext class="status__content" *ngIf="!isContentWarned" [text]="statusContent" [selected]="isSelected"
|
||||||
(accountSelected)="accountSelected($event)" (hashtagSelected)="hashtagSelected($event)"
|
(accountSelected)="accountSelected($event)" (hashtagSelected)="hashtagSelected($event)"
|
||||||
(textSelected)="textSelected()"></app-databinded-text>
|
(textSelected)="textSelected()"></app-databinded-text>
|
||||||
|
|
|
@ -172,6 +172,26 @@
|
||||||
border: 3px solid $status-secondary-color;
|
border: 3px solid $status-secondary-color;
|
||||||
color: whitesmoke;
|
color: whitesmoke;
|
||||||
|
|
||||||
|
&__closed {
|
||||||
|
//margin: 0 5px 0 $avatar-column-space;
|
||||||
|
margin: 0 5px 0 calc(#{$avatar-column-space} - 1px);
|
||||||
|
padding: 3px 5px 3px 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
// color: #6d8fd3;
|
||||||
|
// color: #7282a1;
|
||||||
|
// color: #838da1;
|
||||||
|
color: #919bb1;
|
||||||
|
// background-color: #273149;
|
||||||
|
// background-color: #1f273a;
|
||||||
|
background-color: #171d2b;
|
||||||
|
}
|
||||||
|
|
||||||
&--title {
|
&--title {
|
||||||
color: $content-warning-font-color;
|
color: $content-warning-font-color;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { EmojiConverter, EmojiTypeEnum } from '../../../tools/emoji.tools';
|
||||||
import { ContentWarningPolicyEnum } from '../../../states/settings.state';
|
import { ContentWarningPolicyEnum } from '../../../states/settings.state';
|
||||||
import { StatusesStateService, StatusState } from "../../../services/statuses-state.service";
|
import { StatusesStateService, StatusState } from "../../../services/statuses-state.service";
|
||||||
import { DatabindedTextComponent } from "./databinded-text/databinded-text.component";
|
import { DatabindedTextComponent } from "./databinded-text/databinded-text.component";
|
||||||
|
import { SettingsService } from "../../../services/settings.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-status",
|
selector: "app-status",
|
||||||
|
@ -44,6 +45,8 @@ export class StatusComponent implements OnInit {
|
||||||
isSelected: boolean;
|
isSelected: boolean;
|
||||||
isRemote: boolean;
|
isRemote: boolean;
|
||||||
|
|
||||||
|
private freezeAvatarEnabled: boolean;
|
||||||
|
|
||||||
hideStatus: boolean = false;
|
hideStatus: boolean = false;
|
||||||
|
|
||||||
@Output() browseAccountEvent = new EventEmitter<string>();
|
@Output() browseAccountEvent = new EventEmitter<string>();
|
||||||
|
@ -103,6 +106,7 @@ export class StatusComponent implements OnInit {
|
||||||
constructor(
|
constructor(
|
||||||
public elem: ElementRef,
|
public elem: ElementRef,
|
||||||
private readonly toolsService: ToolsService,
|
private readonly toolsService: ToolsService,
|
||||||
|
private readonly settingsService: SettingsService,
|
||||||
private readonly statusesStateService: StatusesStateService) { }
|
private readonly statusesStateService: StatusesStateService) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
@ -111,12 +115,22 @@ export class StatusComponent implements OnInit {
|
||||||
this.statusWrapper = notification.editedStatus;
|
this.statusWrapper = notification.editedStatus;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.freezeAvatarEnabled = this.settingsService.getSettings().enableFreezeAvatar;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
if (this.statusesStateServiceSub) this.statusesStateServiceSub.unsubscribe();
|
if (this.statusesStateServiceSub) this.statusesStateServiceSub.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getAvatar(acc: Account): string {
|
||||||
|
if(this.freezeAvatarEnabled){
|
||||||
|
return acc.avatar_static;
|
||||||
|
} else {
|
||||||
|
return acc.avatar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private ensureMentionAreDisplayed(data: string): string {
|
private ensureMentionAreDisplayed(data: string): string {
|
||||||
const mentions = this.displayedStatus.mentions;
|
const mentions = this.displayedStatus.mentions;
|
||||||
if (!mentions || mentions.length === 0) return data;
|
if (!mentions || mentions.length === 0) return data;
|
||||||
|
|
|
@ -30,7 +30,7 @@ export class TimeAgoPipe implements PipeTransform {
|
||||||
const hours = minutes / 60;
|
const hours = minutes / 60;
|
||||||
const days = hours / 24;
|
const days = hours / 24;
|
||||||
// const months = days / 30.416;
|
// const months = days / 30.416;
|
||||||
// const years = days / 365;
|
const years = days / 365;
|
||||||
|
|
||||||
if (seconds <= 59) {
|
if (seconds <= 59) {
|
||||||
text = Math.round(seconds) + 's';
|
text = Math.round(seconds) + 's';
|
||||||
|
@ -38,8 +38,10 @@ export class TimeAgoPipe implements PipeTransform {
|
||||||
text = Math.round(minutes) + 'm';
|
text = Math.round(minutes) + 'm';
|
||||||
} else if (hours <= 23) {
|
} else if (hours <= 23) {
|
||||||
text = Math.round(hours) + 'h';
|
text = Math.round(hours) + 'h';
|
||||||
} else {
|
} else if (days < 365) {
|
||||||
text = Math.round(days) + 'd';
|
text = Math.round(days) + 'd';
|
||||||
|
} else {
|
||||||
|
text = Math.round(years) + 'y';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (minutes < 1) {
|
if (minutes < 1) {
|
||||||
|
|
|
@ -1,10 +1,30 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class MyElectronService {
|
export class MyElectronService {
|
||||||
|
detectedLangSubject = new Subject<DetectedLang[]>();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
try {
|
||||||
|
if ((<any>window).api) {
|
||||||
|
(<any>window).api.receive("detectedLang", (data) => {
|
||||||
|
const result = [];
|
||||||
|
for (const l of data) {
|
||||||
|
let newLang = new DetectedLang(l[0], l[1]);
|
||||||
|
result.push(newLang);
|
||||||
|
}
|
||||||
|
this.detectedLangSubject.next(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.detectLang("ceci est une phrase");
|
||||||
}
|
}
|
||||||
|
|
||||||
setLang(lang: string) {
|
setLang(lang: string) {
|
||||||
|
@ -17,4 +37,22 @@ export class MyElectronService {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detectLang(text: string) {
|
||||||
|
try {
|
||||||
|
if ((<any>window).api) {
|
||||||
|
(<any>window).api.send("detectLang", text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DetectedLang {
|
||||||
|
constructor(
|
||||||
|
public lang: string,
|
||||||
|
public score: number
|
||||||
|
) {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { Injectable } from '@angular/core';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject } from 'rxjs';
|
||||||
|
|
||||||
import { ILanguage } from '../states/settings.state';
|
import { ILanguage } from '../states/settings.state';
|
||||||
import { MyElectronService } from './electron.service';
|
import { DetectedLang, MyElectronService } from './electron.service';
|
||||||
import { SettingsService } from './settings.service';
|
import { SettingsService } from './settings.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
|
@ -19,6 +19,42 @@ export class LanguageService {
|
||||||
) {
|
) {
|
||||||
this.configuredLanguagesChanged.next(this.getConfiguredLanguages());
|
this.configuredLanguagesChanged.next(this.getConfiguredLanguages());
|
||||||
this.selectedLanguageChanged.next(this.getSelectedLanguage());
|
this.selectedLanguageChanged.next(this.getSelectedLanguage());
|
||||||
|
|
||||||
|
this.electronService.detectedLangSubject.subscribe(l => {
|
||||||
|
this.detectedLanguage(l);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private detectedLanguage(lang: DetectedLang[]) {
|
||||||
|
if (!lang) return;
|
||||||
|
|
||||||
|
if (lang.length >= 1) {
|
||||||
|
const languages = this.getConfiguredLanguages();
|
||||||
|
|
||||||
|
let firstLang = lang[0].lang;
|
||||||
|
let firstLocalLang = languages.find(x => x.iso639 == firstLang);
|
||||||
|
if (firstLocalLang) {
|
||||||
|
this.setSelectedLanguage(firstLocalLang);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lang.length > 1) {
|
||||||
|
firstLang = lang[1].lang;
|
||||||
|
firstLocalLang = languages.find(x => x.iso639 == firstLang);
|
||||||
|
if (firstLocalLang) {
|
||||||
|
this.setSelectedLanguage(firstLocalLang);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
autoDetectLang(text: string): void {
|
||||||
|
if (!text || text.length < 5) return;
|
||||||
|
|
||||||
|
if (!this.settingsService.getSettings().disableLangAutodetec) {
|
||||||
|
this.electronService.detectLang(text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getSelectedLanguage(): ILanguage {
|
getSelectedLanguage(): ILanguage {
|
||||||
|
|
|
@ -22,14 +22,14 @@ export class MastodonWrapperService {
|
||||||
private readonly mastodonService: MastodonService) { }
|
private readonly mastodonService: MastodonService) { }
|
||||||
|
|
||||||
refreshAccountIfNeeded(accountInfo: AccountInfo): Promise<AccountInfo> {
|
refreshAccountIfNeeded(accountInfo: AccountInfo): Promise<AccountInfo> {
|
||||||
if(this.refreshingToken[accountInfo.id]){
|
if (this.refreshingToken[accountInfo.id]) {
|
||||||
return this.refreshingToken[accountInfo.id];
|
return this.refreshingToken[accountInfo.id];
|
||||||
}
|
}
|
||||||
|
|
||||||
let isExpired = false;
|
let isExpired = false;
|
||||||
let storedAccountInfo = this.getStoreAccountInfo(accountInfo.id);
|
let storedAccountInfo = this.getStoreAccountInfo(accountInfo.id);
|
||||||
|
|
||||||
if(!storedAccountInfo || !(storedAccountInfo.token))
|
if (!storedAccountInfo || !(storedAccountInfo.token))
|
||||||
return Promise.resolve(accountInfo);
|
return Promise.resolve(accountInfo);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -96,7 +96,7 @@ export class MastodonWrapperService {
|
||||||
return this.mastodonService.getInstance(instance);
|
return this.mastodonService.getInstance(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
translate(account: AccountInfo, statusId: string, lang: string): Promise<Translation>{
|
translate(account: AccountInfo, statusId: string, lang: string): Promise<Translation> {
|
||||||
return this.refreshAccountIfNeeded(account)
|
return this.refreshAccountIfNeeded(account)
|
||||||
.then((refreshedAccount: AccountInfo) => {
|
.then((refreshedAccount: AccountInfo) => {
|
||||||
return this.mastodonService.translate(refreshedAccount, statusId, lang);
|
return this.mastodonService.translate(refreshedAccount, statusId, lang);
|
||||||
|
@ -146,7 +146,7 @@ export class MastodonWrapperService {
|
||||||
}
|
}
|
||||||
|
|
||||||
search(account: AccountInfo, query: string, version: 'v1' | 'v2', resolve: boolean = false): Promise<Results> {
|
search(account: AccountInfo, query: string, version: 'v1' | 'v2', resolve: boolean = false): Promise<Results> {
|
||||||
if(query.includes('twitter.com')){
|
if (query.includes('twitter.com')) {
|
||||||
query = this.processTwitterQuery(query);
|
query = this.processTwitterQuery(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,17 +158,17 @@ export class MastodonWrapperService {
|
||||||
|
|
||||||
private processTwitterQuery(query: string): string {
|
private processTwitterQuery(query: string): string {
|
||||||
const settings = this.settingsService.getSettings();
|
const settings = this.settingsService.getSettings();
|
||||||
if(!settings.twitterBridgeInstance) return query;
|
if (!settings.twitterBridgeInstance) return query;
|
||||||
|
|
||||||
let name;
|
let name;
|
||||||
if(query.includes('twitter.com/')){
|
if (query.includes('twitter.com/')) {
|
||||||
console.log(query.replace('https://', '').replace('http://', '').split('/'));
|
console.log(query.replace('https://', '').replace('http://', '').split('/'));
|
||||||
name = query.replace('https://', '').replace('http://', '').split('/')[1];
|
name = query.replace('https://', '').replace('http://', '').split('/')[1];
|
||||||
}
|
}
|
||||||
if(query.includes('@twitter.com')){
|
if (query.includes('@twitter.com')) {
|
||||||
console.log(query.split('@'));
|
console.log(query.split('@'));
|
||||||
name = query.split('@')[0];
|
name = query.split('@')[0];
|
||||||
if(name === '' || name == null){
|
if (name === '' || name == null) {
|
||||||
name = query.split('@')[1];
|
name = query.split('@')[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -208,7 +208,7 @@ export class MastodonWrapperService {
|
||||||
}
|
}
|
||||||
|
|
||||||
searchAccount(account: AccountInfo, query: string, limit: number = 40, following: boolean = false, resolve = true): Promise<Account[]> {
|
searchAccount(account: AccountInfo, query: string, limit: number = 40, following: boolean = false, resolve = true): Promise<Account[]> {
|
||||||
if(query.includes('twitter.com')){
|
if (query.includes('twitter.com')) {
|
||||||
query = this.processTwitterQuery(query);
|
query = this.processTwitterQuery(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,6 +281,20 @@ export class MastodonWrapperService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hideBoosts(currentlyUsedAccount: AccountInfo, account: Account): Promise<Relationship> {
|
||||||
|
return this.refreshAccountIfNeeded(currentlyUsedAccount)
|
||||||
|
.then((refreshedAccount: AccountInfo) => {
|
||||||
|
return this.mastodonService.hideBoosts(refreshedAccount, account);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
unhideBoosts(currentlyUsedAccount: AccountInfo, account: Account): Promise<Relationship> {
|
||||||
|
return this.refreshAccountIfNeeded(currentlyUsedAccount)
|
||||||
|
.then((refreshedAccount: AccountInfo) => {
|
||||||
|
return this.mastodonService.unhideBoosts(refreshedAccount, account);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
followHashtag(currentlyUsedAccount: AccountInfo, hashtag: string): Promise<Tag> {
|
followHashtag(currentlyUsedAccount: AccountInfo, hashtag: string): Promise<Tag> {
|
||||||
return this.refreshAccountIfNeeded(currentlyUsedAccount)
|
return this.refreshAccountIfNeeded(currentlyUsedAccount)
|
||||||
.then((refreshedAccount: AccountInfo) => {
|
.then((refreshedAccount: AccountInfo) => {
|
||||||
|
@ -407,6 +421,20 @@ export class MastodonWrapperService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blockDomain(account: AccountInfo, domain: string): Promise<void> {
|
||||||
|
return this.refreshAccountIfNeeded(account)
|
||||||
|
.then((refreshedAccount: AccountInfo) => {
|
||||||
|
return this.mastodonService.blockDomain(refreshedAccount, domain);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
unblockDomain(account: AccountInfo, domain: string): Promise<void> {
|
||||||
|
return this.refreshAccountIfNeeded(account)
|
||||||
|
.then((refreshedAccount: AccountInfo) => {
|
||||||
|
return this.mastodonService.unblockDomain(refreshedAccount, domain);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pinOnProfile(account: AccountInfo, statusId: string): Promise<Status> {
|
pinOnProfile(account: AccountInfo, statusId: string): Promise<Status> {
|
||||||
return this.refreshAccountIfNeeded(account)
|
return this.refreshAccountIfNeeded(account)
|
||||||
.then((refreshedAccount: AccountInfo) => {
|
.then((refreshedAccount: AccountInfo) => {
|
||||||
|
@ -470,14 +498,14 @@ export class MastodonWrapperService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getFollowing(account: AccountInfo, accountId: number, maxId: string, sinceId: string, limit: number = 40): Promise<FollowingResult> {
|
getFollowing(account: AccountInfo, accountId: number, maxId: string, sinceId: string, limit: number = 40): Promise<FollowingResult> {
|
||||||
return this.refreshAccountIfNeeded(account)
|
return this.refreshAccountIfNeeded(account)
|
||||||
.then((refreshedAccount: AccountInfo) => {
|
.then((refreshedAccount: AccountInfo) => {
|
||||||
return this.mastodonService.getFollowing(refreshedAccount, accountId, maxId, sinceId, limit);
|
return this.mastodonService.getFollowing(refreshedAccount, accountId, maxId, sinceId, limit);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getFollowers(account: AccountInfo, accountId: number, maxId: string, sinceId: string, limit: number = 40): Promise<FollowingResult> {
|
getFollowers(account: AccountInfo, accountId: number, maxId: string, sinceId: string, limit: number = 40): Promise<FollowingResult> {
|
||||||
return this.refreshAccountIfNeeded(account)
|
return this.refreshAccountIfNeeded(account)
|
||||||
.then((refreshedAccount: AccountInfo) => {
|
.then((refreshedAccount: AccountInfo) => {
|
||||||
return this.mastodonService.getFollowers(refreshedAccount, accountId, maxId, sinceId, limit);
|
return this.mastodonService.getFollowers(refreshedAccount, accountId, maxId, sinceId, limit);
|
||||||
|
|
|
@ -357,6 +357,26 @@ export class MastodonService {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hideBoosts(currentlyUsedAccount: AccountInfo, account: Account): Promise<Relationship> {
|
||||||
|
const route = `https://${currentlyUsedAccount.instance}${this.apiRoutes.follow}`.replace('{0}', account.id.toString());
|
||||||
|
const headers = new HttpHeaders({ 'Authorization': `Bearer ${currentlyUsedAccount.token.access_token}` });
|
||||||
|
|
||||||
|
let input = new FormData();
|
||||||
|
input.append('reblogs', 'false');
|
||||||
|
|
||||||
|
return this.httpClient.post<Relationship>(route, input, { headers: headers }).toPromise();
|
||||||
|
}
|
||||||
|
|
||||||
|
unhideBoosts(currentlyUsedAccount: AccountInfo, account: Account): Promise<Relationship> {
|
||||||
|
const route = `https://${currentlyUsedAccount.instance}${this.apiRoutes.follow}`.replace('{0}', account.id.toString());
|
||||||
|
const headers = new HttpHeaders({ 'Authorization': `Bearer ${currentlyUsedAccount.token.access_token}` });
|
||||||
|
|
||||||
|
let input = new FormData();
|
||||||
|
input.append('reblogs', 'true');
|
||||||
|
|
||||||
|
return this.httpClient.post<Relationship>(route, input, { headers: headers }).toPromise();
|
||||||
|
}
|
||||||
|
|
||||||
followHashtag(currentlyUsedAccount: AccountInfo, hashtag: string): Promise<Tag> {
|
followHashtag(currentlyUsedAccount: AccountInfo, hashtag: string): Promise<Tag> {
|
||||||
const route = `https://${currentlyUsedAccount.instance}${this.apiRoutes.followHashtag}`.replace('{0}', hashtag);
|
const route = `https://${currentlyUsedAccount.instance}${this.apiRoutes.followHashtag}`.replace('{0}', hashtag);
|
||||||
const headers = new HttpHeaders({ 'Authorization': `Bearer ${currentlyUsedAccount.token.access_token}` });
|
const headers = new HttpHeaders({ 'Authorization': `Bearer ${currentlyUsedAccount.token.access_token}` });
|
||||||
|
@ -524,6 +544,23 @@ export class MastodonService {
|
||||||
return this.httpClient.post<Relationship>(route, null, { headers: headers }).toPromise();
|
return this.httpClient.post<Relationship>(route, null, { headers: headers }).toPromise();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blockDomain(account: AccountInfo, domain: string): Promise<void> {
|
||||||
|
let route = `https://${account.instance}${this.apiRoutes.blockDomain}`;
|
||||||
|
const headers = new HttpHeaders({ 'Authorization': `Bearer ${account.token.access_token}` });
|
||||||
|
|
||||||
|
let input = new FormData();
|
||||||
|
input.append('domain', domain);
|
||||||
|
|
||||||
|
return this.httpClient.post<void>(route, input, { headers: headers }).toPromise();
|
||||||
|
}
|
||||||
|
|
||||||
|
unblockDomain(account: AccountInfo, domain: string): Promise<void> {
|
||||||
|
let route = `https://${account.instance}${this.apiRoutes.blockDomain}?domain=${domain}`;
|
||||||
|
const headers = new HttpHeaders({ 'Authorization': `Bearer ${account.token.access_token}`});
|
||||||
|
|
||||||
|
return this.httpClient.delete<void>(route, { headers: headers }).toPromise();
|
||||||
|
}
|
||||||
|
|
||||||
pinOnProfile(account: AccountInfo, statusId: string): Promise<Status> {
|
pinOnProfile(account: AccountInfo, statusId: string): Promise<Status> {
|
||||||
let route = `https://${account.instance}${this.apiRoutes.pinStatus}`.replace('{0}', statusId.toString());
|
let route = `https://${account.instance}${this.apiRoutes.pinStatus}`.replace('{0}', statusId.toString());
|
||||||
const headers = new HttpHeaders({ 'Authorization': `Bearer ${account.token.access_token}` });
|
const headers = new HttpHeaders({ 'Authorization': `Bearer ${account.token.access_token}` });
|
||||||
|
|
|
@ -12,6 +12,7 @@ export class ApiRoutes {
|
||||||
unfollow = '/api/v1/accounts/{0}/unfollow';
|
unfollow = '/api/v1/accounts/{0}/unfollow';
|
||||||
block = '/api/v1/accounts/{0}/block';
|
block = '/api/v1/accounts/{0}/block';
|
||||||
unblock = '/api/v1/accounts/{0}/unblock';
|
unblock = '/api/v1/accounts/{0}/unblock';
|
||||||
|
blockDomain = '/api/v1/domain_blocks';
|
||||||
mute = '/api/v1/accounts/{0}/mute';
|
mute = '/api/v1/accounts/{0}/mute';
|
||||||
unmute = '/api/v1/accounts/{0}/unmute';
|
unmute = '/api/v1/accounts/{0}/unmute';
|
||||||
muteStatus = '/api/v1/statuses/{0}/mute';
|
muteStatus = '/api/v1/statuses/{0}/mute';
|
||||||
|
|
|
@ -10,6 +10,7 @@ export class NavigationService {
|
||||||
activatedPanelSubject = new BehaviorSubject<OpenLeftPanelEvent>(new OpenLeftPanelEvent(LeftPanelType.Closed));
|
activatedPanelSubject = new BehaviorSubject<OpenLeftPanelEvent>(new OpenLeftPanelEvent(LeftPanelType.Closed));
|
||||||
activatedMediaSubject: Subject<OpenMediaEvent> = new Subject<OpenMediaEvent>();
|
activatedMediaSubject: Subject<OpenMediaEvent> = new Subject<OpenMediaEvent>();
|
||||||
columnSelectedSubject = new BehaviorSubject<number>(-1);
|
columnSelectedSubject = new BehaviorSubject<number>(-1);
|
||||||
|
enableDraggableIconMenu = new BehaviorSubject<boolean>(false);
|
||||||
|
|
||||||
constructor() { }
|
constructor() { }
|
||||||
|
|
||||||
|
@ -19,6 +20,10 @@ export class NavigationService {
|
||||||
this.activatedPanelSubject.next(newEvent);
|
this.activatedPanelSubject.next(newEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changeIconMenuState(draggable: boolean) {
|
||||||
|
this.enableDraggableIconMenu.next(draggable);
|
||||||
|
}
|
||||||
|
|
||||||
openPanel(type: LeftPanelType){
|
openPanel(type: LeftPanelType){
|
||||||
const newEvent = new OpenLeftPanelEvent(type);
|
const newEvent = new OpenLeftPanelEvent(type);
|
||||||
this.activatedPanelSubject.next(newEvent);
|
this.activatedPanelSubject.next(newEvent);
|
||||||
|
|
|
@ -6,6 +6,11 @@ export class AddAccount {
|
||||||
constructor(public account: AccountInfo) {}
|
constructor(public account: AccountInfo) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ReorderAccounts {
|
||||||
|
static readonly type = '[Accounts] Reorder';
|
||||||
|
constructor(public accounts: AccountInfo[]) {}
|
||||||
|
}
|
||||||
|
|
||||||
export class SelectAccount {
|
export class SelectAccount {
|
||||||
static readonly type = '[Accounts] Select account';
|
static readonly type = '[Accounts] Select account';
|
||||||
constructor(public account: AccountInfo, public multiselection: boolean = false) {}
|
constructor(public account: AccountInfo, public multiselection: boolean = false) {}
|
||||||
|
@ -46,6 +51,16 @@ export class AccountsState {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Action(ReorderAccounts)
|
||||||
|
ReorderAccounts(ctx: StateContext<AccountsStateModel>, action: ReorderAccounts){
|
||||||
|
// const state = ctx.getState();
|
||||||
|
const reorderedAccounts = action.accounts;
|
||||||
|
|
||||||
|
ctx.patchState({
|
||||||
|
accounts: [...reorderedAccounts]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Action(UpdateAccount)
|
@Action(UpdateAccount)
|
||||||
UpdateAccount(ctx: StateContext<AccountsStateModel>, action: UpdateAccount){
|
UpdateAccount(ctx: StateContext<AccountsStateModel>, action: UpdateAccount){
|
||||||
const state = ctx.getState();
|
const state = ctx.getState();
|
||||||
|
|
|
@ -84,6 +84,10 @@ export class GlobalSettings {
|
||||||
|
|
||||||
configuredLanguages: ILanguage[] = [];
|
configuredLanguages: ILanguage[] = [];
|
||||||
selectedLanguage: ILanguage;
|
selectedLanguage: ILanguage;
|
||||||
|
disableLangAutodetec: boolean;
|
||||||
|
|
||||||
|
enableAltLabel: boolean;
|
||||||
|
enableFreezeAvatar: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ILanguage {
|
export interface ILanguage {
|
||||||
|
@ -181,6 +185,9 @@ export class SettingsState {
|
||||||
newSettings.twitterBridgeInstance = oldSettings.twitterBridgeInstance;
|
newSettings.twitterBridgeInstance = oldSettings.twitterBridgeInstance;
|
||||||
newSettings.configuredLanguages = oldSettings.configuredLanguages;
|
newSettings.configuredLanguages = oldSettings.configuredLanguages;
|
||||||
newSettings.selectedLanguage = oldSettings.selectedLanguage;
|
newSettings.selectedLanguage = oldSettings.selectedLanguage;
|
||||||
|
newSettings.disableLangAutodetec = oldSettings.disableLangAutodetec;
|
||||||
|
newSettings.enableAltLabel = oldSettings.enableAltLabel;
|
||||||
|
newSettings.enableFreezeAvatar = oldSettings.enableFreezeAvatar;
|
||||||
|
|
||||||
return newSettings;
|
return newSettings;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue