...
 
Commits (2)
......@@ -7,7 +7,7 @@ import {
} from '@angular/core';
import { UniqueId } from '../../../helpers/unique-id.helper';
export type FileUploadSelectEvent = File | File[];
export type FileUploadSelectEvent = File | File[] | null;
@Component({
selector: 'm-file-upload',
......
<div class="m-composer__toolbar">
<m-file-upload
[hidden]="attachment || inProgress"
wrapperClass="m-composerToolbar__item"
accept="image/*,video/*"
(onSelect)="onAttachmentSelect($event)"
>
<m-icon from="ion" iconId="image"></m-icon>
<span i18n>Upload</span>
</m-file-upload>
<a
*ngIf="attachment || inProgress"
class="m-composerToolbar__item m-composerToolbar__item--active"
(click)="onDeleteAttachmentClick($event)"
>
<m-icon iconId="delete_forever"></m-icon>
<span i18n>Media</span>
</a>
<a class="m-composerToolbar__item" (click)="onNsfwClick($event)">
<m-icon iconId="explicit"></m-icon>
<span i18n>NSFW</span>
</a>
<a class="m-composerToolbar__item" (click)="onMonetizationClick($event)">
<m-icon from="ion" iconId="cash"></m-icon>
<span i18n>Monetize</span>
</a>
<a class="m-composerToolbar__item" (click)="onTagsClick($event)">
<m-icon from="ion" iconId="pound"></m-icon>
<span i18n>Tags</span>
</a>
<m-button
class="m-composerToolbar__item m-composerToolbarItem--container"
[disabled]="inProgress"
[dropdown]="postButtonDropdown"
(onAction)="onPost($event)"
i18n
>
Post
</m-button>
<ng-template #postButtonDropdown>
<ul class="m-composerPost__dropdown">
<li (click)="onSchedulerClick()">Set time and date</li>
</ul>
</ng-template>
</div>
.m-composer {
.m-composer__toolbar {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 26px 20px 0;
border-top: 1px solid;
user-select: none;
@include m-theme() {
border-color: themed($m-borderColor--primary);
}
.m-composerToolbar__item {
display: flex;
flex-direction: row;
align-items: center;
padding: 8px 16px;
cursor: pointer;
&.m-composerToolbar__item--active {
@include m-theme() {
color: themed($m-btn--primary);
}
}
&.m-composerToolbarItem--container {
align-items: stretch;
padding: 0;
}
@include m-theme() {
color: themed($m-textColor--secondary);
}
> m-icon + span {
display: inline-block;
margin-left: 8px;
}
}
}
.m-composerPost__dropdown {
width: 100%;
list-style: none;
margin: 0;
padding: 0;
@include m-theme() {
color: themed($m-textColor--primary);
background: themed($m-bgColor--primary);
box-shadow: 3px 3px 4px rgba(themed($m-textColor--primary), 0.2);
}
> li {
padding: 8px;
border-bottom: 1px solid;
cursor: pointer;
white-space: nowrap;
&:last-child {
border-bottom: none;
}
@include m-theme() {
border-color: themed($m-borderColor--primary);
}
}
}
}
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
Input,
Output,
} from '@angular/core';
import { FileUploadSelectEvent } from '../../../common/components/file-upload/file-upload.component';
import { ButtonComponentAction } from '../../../common/components/button-v2/button.component';
@Component({
selector: 'm-composer__toolbar',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: 'composer-toolbar.component.html',
})
export class ComposerToolbarComponent {
@Input() attachment: any;
@Input() inProgress: boolean = false;
@Output('onAttachmentSelect') onAttachmentSelectEmitter: EventEmitter<
FileUploadSelectEvent
> = new EventEmitter<FileUploadSelectEvent>();
@Output('onDeleteAttachment') onDeleteAttachmentEmitter: EventEmitter<
void
> = new EventEmitter<void>();
@Output('onPost') onPostEmitter: EventEmitter<
ButtonComponentAction
> = new EventEmitter<ButtonComponentAction>();
onAttachmentSelect(file: FileUploadSelectEvent): void {
this.onAttachmentSelectEmitter.emit(file);
}
onDeleteAttachmentClick(event?: MouseEvent): void {
this.onDeleteAttachmentEmitter.emit();
}
onNsfwClick(event?: MouseEvent): void {
// TODO: NSFW popup
}
onMonetizationClick(event?: MouseEvent): void {
// TODO: Monetization popup
}
onTagsClick(event?: MouseEvent): void {
// TODO: Tags popup
}
onPost(buttonComponentAction: ButtonComponentAction): void {
this.onPostEmitter.emit(buttonComponentAction);
}
onSchedulerClick(event?: MouseEvent): void {
// TODO: Scheduler popup
}
}
......@@ -16,49 +16,17 @@
i18n-placeholder
[id]="id"
(focus)="popOut()"
[ngModel]="service.message$ | async"
(ngModelChange)="setMessage($event)"
[ngModel]="message$ | async"
(ngModelChange)="onMessageChange($event)"
></textarea>
</div>
<div class="m-composer__toolBar">
<m-file-upload
wrapperClass="m-composerToolbar__item"
accept="image/*,video/*"
(onSelect)="setAttachment($event)"
>
<m-icon from="ion" iconId="image"></m-icon>
<span i18n>Upload</span>
</m-file-upload>
<a class="m-composerToolbar__item" (click)="setNsfw()">
<m-icon iconId="explicit"></m-icon>
<span i18n>NSFW</span>
</a>
<a class="m-composerToolbar__item" (click)="setMonetization()">
<m-icon from="ion" iconId="cash"></m-icon>
<span i18n>Monetize</span>
</a>
<a class="m-composerToolbar__item" (click)="setTags()">
<m-icon from="ion" iconId="pound"></m-icon>
<span i18n>Tag</span>
</a>
<m-button
class="m-composerToolbar__item m-composerToolbarItem--container"
[dropdown]="postButtonDropdown"
(onAction)="onPost($event)"
i18n
>
Post
</m-button>
<ng-template #postButtonDropdown>
<ul class="m-composerPost__dropdown">
<li (click)="setScheduler()">Set time and date</li>
</ul>
</ng-template>
</div>
<m-composer__toolbar
[attachment]="attachment$ | async"
[inProgress]="inProgress$ | async"
(onAttachmentSelect)="onAttachmentSelect($event)"
(onDeleteAttachment)="onDeleteAttachment()"
(onPost)="onPost($event)"
></m-composer__toolbar>
</div>
</div>
......@@ -118,67 +118,4 @@ m-composer {
}
}
}
.m-composer__toolBar {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 26px 20px 0;
border-top: 1px solid;
user-select: none;
@include m-theme() {
border-color: themed($m-borderColor--primary);
}
.m-composerToolbar__item {
display: flex;
flex-direction: row;
align-items: center;
padding: 8px 16px;
&.m-composerToolbarItem--container {
align-items: stretch;
padding: 0;
}
@include m-theme() {
color: themed($m-textColor--secondary);
}
> m-icon + span {
display: inline-block;
margin-left: 8px;
}
}
}
.m-composerPost__dropdown {
width: 100%;
list-style: none;
margin: 0;
padding: 0;
@include m-theme() {
color: themed($m-textColor--primary);
background: themed($m-bgColor--primary);
box-shadow: 3px 3px 4px rgba(themed($m-textColor--primary), 0.2);
}
> li {
padding: 8px;
border-bottom: 1px solid;
cursor: pointer;
white-space: nowrap;
&:last-child {
border-bottom: none;
}
@include m-theme() {
border-color: themed($m-borderColor--primary);
}
}
}
}
......@@ -22,49 +22,101 @@ export class ComposerComponent implements OnInit, OnDestroy {
constructor(public service: ComposerService) {}
ngOnInit(): void {
// TODO: Initialize based on bindings
get message$() {
return this.service.message$;
}
this.service.message$.next('');
this.service.attachment$.next(null);
this.service.nsfw$.next(null);
this.service.monetization$.next(null);
this.service.scheduler$.next(null);
set message(message: string) {
this.service.message$.next(message);
}
ngOnDestroy(): void {
// TODO: Destroy subscriptions
// TODO: GC
get attachment$() {
return this.service.attachment$;
}
setMessage(message: string) {
this.service.message$.next(message);
set attachment(attachment: File | null) {
this.service.attachment$.next(attachment);
}
get nsfw$() {
return this.service.nsfw$;
}
set nsfw(nsfw: number[]) {
this.service.nsfw$.next(nsfw);
}
get monetization$() {
return this.service.monetization$;
}
set monetization(monetization: any) {
this.service.monetization$.next(monetization);
}
setAttachment(file) {
this.service.attachment$.next(file);
get tags$() {
return this.service.tags$;
}
setNsfw() {
// TODO: Set NSFW flags
this.service.nsfw$.next([+Date.now()]);
set tags(tags: string[]) {
this.service.tags$.next(tags);
}
setMonetization() {
// TODO: Set Monetization attributes
this.service.monetization$.next({ monetization: +Date.now() });
get scheduler$() {
return this.service.scheduler$;
}
setTags() {
this.service.alterMessageTags(/* Tags */);
set scheduler(scheduler: any) {
this.service.scheduler$.next(scheduler);
}
setScheduler() {
// TODO: Set Scheduler attributes
this.service.scheduler$.next({ scheduler: +Date.now() });
get inProgress$() {
return this.service.inProgress$;
}
async onPost($event: ButtonComponentAction) {
get progress$() {
return this.service.progress$;
}
ngOnInit(): void {
// TODO: Initialize based on bindings
this.message = '';
this.attachment = null;
this.nsfw = null;
this.monetization = null;
this.scheduler = null;
}
ngOnDestroy(): void {
// TODO: Destroy subscriptions, if any
// TODO: Delete unused attachment
}
onMessageChange(message: string) {
this.message = message;
}
onAttachmentSelect(file: File | null): void {
if (!file) {
return;
}
this.attachment = file;
}
onDeleteAttachment(): void {
// TODO: Use themed async modals
if (!confirm('Are you sure?')) {
return;
}
// TODO: Delete unused attachment
this.attachment = null;
}
async onPost(event: ButtonComponentAction) {
// TODO: Check event.type, etc
try {
const response = await this.service.post();
} catch (e) {
......@@ -77,5 +129,3 @@ export class ComposerComponent implements OnInit, OnDestroy {
// this.poppedOut = true;
}
}
// use combineLatest with
......@@ -3,6 +3,7 @@ import { CommonModule as NgCommonModule } from '@angular/common';
import { ComposerComponent } from './composer.component';
import { CommonModule } from '../../common/common.module';
import { FormsModule } from '@angular/forms';
import { ComposerToolbarComponent } from './components/composer-toolbar.component';
/**
* Exported components
......@@ -12,7 +13,7 @@ const COMPONENTS = [ComposerComponent];
/**
* Components used internally
*/
const INTERNAL_COMPONENTS = [];
const INTERNAL_COMPONENTS = [ComposerToolbarComponent];
/**
* Module definition
......
......@@ -7,27 +7,56 @@ import {
UploadEventType,
} from '../../common/api/attachment-api.service';
export type MessageSubjectValue = string;
export type AttachmentSubjectValue = File | null;
export type NsfwSubjectValue = Array<number>;
export type MonetizationSubjectValue = any;
export type TagsSubjectValue = Array<string>;
export type SchedulerSubjectValue = any;
@Injectable()
export class ComposerService implements OnDestroy {
// TODO: TYPES!!!
readonly message$: BehaviorSubject<any> = new BehaviorSubject<any>(null);
readonly attachment$: BehaviorSubject<any> = new BehaviorSubject<any>(null);
readonly nsfw$: BehaviorSubject<any> = new BehaviorSubject<any>(null);
readonly monetization$: BehaviorSubject<any> = new BehaviorSubject<any>(null);
readonly scheduler$: BehaviorSubject<any> = new BehaviorSubject<any>(null);
readonly message$: BehaviorSubject<MessageSubjectValue> = new BehaviorSubject<
MessageSubjectValue
>('');
readonly attachment$: BehaviorSubject<
AttachmentSubjectValue
> = new BehaviorSubject<AttachmentSubjectValue>(null);
readonly nsfw$: BehaviorSubject<NsfwSubjectValue> = new BehaviorSubject<
NsfwSubjectValue
>([]);
readonly monetization$: BehaviorSubject<
MonetizationSubjectValue
> = new BehaviorSubject<MonetizationSubjectValue>(null);
readonly tags$: BehaviorSubject<TagsSubjectValue> = new BehaviorSubject<
TagsSubjectValue
>([]);
readonly scheduler$: BehaviorSubject<
SchedulerSubjectValue
> = new BehaviorSubject<SchedulerSubjectValue>(null);
readonly inProgress$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(
false
);
readonly progress$: BehaviorSubject<number> = new BehaviorSubject<number>(0);
readonly dataStream$: Observable<any>;
protected data: any = null;
protected readonly dataStreamSubscription: Subscription;
protected data: any = null;
constructor(protected attachmentApi: AttachmentApiService) {
this.dataStream$ = combineLatest([
this.dataStreamSubscription = combineLatest([
this.message$,
this.attachment$.pipe(
map(file =>
......@@ -40,20 +69,20 @@ export class ComposerService implements OnDestroy {
),
this.nsfw$,
this.monetization$,
this.tags$,
this.scheduler$,
]).pipe(
map(([message, attachment, nsfw, monetization, scheduler]) => ({
message,
attachment,
nsfw,
monetization,
scheduler,
}))
);
this.dataStreamSubscription = this.dataStream$.subscribe(
data => (this.data = data)
);
])
.pipe(
map(([message, attachment, nsfw, monetization, tags, scheduler]) => ({
message,
attachment,
nsfw,
monetization,
tags,
scheduler,
}))
)
.subscribe(data => (this.data = data));
}
ngOnDestroy(): void {
......@@ -81,13 +110,6 @@ export class ComposerService implements OnDestroy {
}
}
alterMessageTags() {
// TODO: Parse message to add and delete passed tags
this.message$.next(
`${this.message$.getValue() || ''} #tag${+Date.now()}`.trim()
);
}
async post(): Promise<any> {
// TODO: Return type!
......@@ -95,11 +117,3 @@ export class ComposerService implements OnDestroy {
console.log(this.data);
}
}
/*
<pre>
Progress: {{ service.progress$ | async }}
In Progress: {{ service.inProgress$ | async }}
Data: {{ service.dataStream$ | async | json }}
</pre>
*/