]>
Commit | Line | Data |
---|---|---|
67ed6552 C |
1 | import { concat, forkJoin, merge } from 'rxjs' |
2 | import { Component, Input, OnChanges, OnInit } from '@angular/core' | |
660d11e9 | 3 | import { Router } from '@angular/router' |
f8b2c1b4 | 4 | import { AuthService, Notifier } from '@app/core' |
67ed6552 | 5 | import { Account, VideoChannel, VideoService } from '@app/shared/shared-main' |
67ed6552 C |
6 | import { FeedFormat } from '@shared/models' |
7 | import { UserSubscriptionService } from './user-subscription.service' | |
22a16e36 C |
8 | |
9 | @Component({ | |
10 | selector: 'my-subscribe-button', | |
11 | templateUrl: './subscribe-button.component.html', | |
12 | styleUrls: [ './subscribe-button.component.scss' ] | |
13 | }) | |
f8b65c22 | 14 | export class SubscribeButtonComponent implements OnInit, OnChanges { |
b061c8ed RK |
15 | /** |
16 | * SubscribeButtonComponent can be used with a single VideoChannel passed as [VideoChannel], | |
17 | * or with an account and a full list of that account's videoChannels. The latter is intended | |
18 | * to allow mass un/subscription from an account's page, while keeping the channel-centric | |
19 | * subscription model. | |
20 | */ | |
41eb700f RK |
21 | @Input() account: Account |
22 | @Input() videoChannels: VideoChannel[] | |
22a16e36 | 23 | @Input() displayFollowers = false |
f37dc0dd | 24 | @Input() size: 'small' | 'normal' = 'normal' |
22a16e36 | 25 | |
9270ccf6 | 26 | subscribed = new Map<string, boolean>() |
22a16e36 C |
27 | |
28 | constructor ( | |
660d11e9 RK |
29 | private authService: AuthService, |
30 | private router: Router, | |
f8b2c1b4 | 31 | private notifier: Notifier, |
22a16e36 | 32 | private userSubscriptionService: UserSubscriptionService, |
39ba2e8e | 33 | private videoService: VideoService |
9270ccf6 | 34 | ) { } |
41eb700f RK |
35 | |
36 | get handle () { | |
37 | return this.account | |
38 | ? this.account.nameWithHost | |
db84cf89 | 39 | : this.videoChannel.name + '@' + this.videoChannel.host |
41eb700f | 40 | } |
22a16e36 | 41 | |
3ddb1ec5 | 42 | get channelHandle () { |
db84cf89 | 43 | return this.getChannelHandler(this.videoChannel) |
22a16e36 C |
44 | } |
45 | ||
41eb700f RK |
46 | get uri () { |
47 | return this.account | |
48 | ? this.account.url | |
49 | : this.videoChannels[0].url | |
660d11e9 RK |
50 | } |
51 | ||
405ec98b | 52 | get rssUri () { |
41eb700f RK |
53 | const rssFeed = this.account |
54 | ? this.videoService | |
55 | .getAccountFeedUrls(this.account.id) | |
56 | .find(i => i.format === FeedFormat.RSS) | |
57 | : this.videoService | |
58 | .getVideoChannelFeedUrls(this.videoChannels[0].id) | |
59 | .find(i => i.format === FeedFormat.RSS) | |
405ec98b FS |
60 | |
61 | return rssFeed.url | |
62 | } | |
63 | ||
db84cf89 C |
64 | get videoChannel () { |
65 | return this.videoChannels[0] | |
66 | } | |
67 | ||
f8b65c22 RK |
68 | get isAllChannelsSubscribed () { |
69 | return this.subscribeStatus(true).length === this.videoChannels.length | |
70 | } | |
71 | ||
72 | get isAtLeastOneChannelSubscribed () { | |
73 | return this.subscribeStatus(true).length > 0 | |
74 | } | |
75 | ||
76 | get isBigButton () { | |
77 | return this.isUserLoggedIn() && this.videoChannels.length > 1 && this.isAtLeastOneChannelSubscribed | |
78 | } | |
79 | ||
22a16e36 | 80 | ngOnInit () { |
9270ccf6 | 81 | this.loadSubscribedStatus() |
22a16e36 C |
82 | } |
83 | ||
f8b65c22 RK |
84 | ngOnChanges () { |
85 | this.ngOnInit() | |
86 | } | |
87 | ||
22a16e36 | 88 | subscribe () { |
660d11e9 | 89 | if (this.isUserLoggedIn()) { |
dae5ca24 | 90 | return this.localSubscribe() |
660d11e9 | 91 | } |
dae5ca24 C |
92 | |
93 | return this.gotoLogin() | |
660d11e9 RK |
94 | } |
95 | ||
96 | localSubscribe () { | |
ab4d4db4 C |
97 | const subscribedStatus = this.subscribeStatus(false) |
98 | ||
9270ccf6 RK |
99 | const observableBatch = this.videoChannels |
100 | .map(videoChannel => this.getChannelHandler(videoChannel)) | |
ab4d4db4 | 101 | .filter(handle => subscribedStatus.includes(handle)) |
9270ccf6 | 102 | .map(handle => this.userSubscriptionService.addSubscription(handle)) |
41eb700f | 103 | |
ab4d4db4 | 104 | forkJoin(observableBatch) |
22a16e36 C |
105 | .subscribe( |
106 | () => { | |
f8b2c1b4 | 107 | this.notifier.success( |
41eb700f | 108 | this.account |
66357162 C |
109 | ? $localize`Subscribed to all current channels of ${this.account.displayName}. You will be notified of all their new videos.` |
110 | : $localize`Subscribed to ${this.videoChannels[0].displayName}. You will be notified of all their new videos.`, | |
111 | ||
112 | $localize`Subscribed` | |
22a16e36 C |
113 | ) |
114 | }, | |
115 | ||
66357162 | 116 | err => this.notifier.error(err.message) |
22a16e36 C |
117 | ) |
118 | } | |
119 | ||
120 | unsubscribe () { | |
660d11e9 RK |
121 | if (this.isUserLoggedIn()) { |
122 | this.localUnsubscribe() | |
123 | } | |
124 | } | |
125 | ||
126 | localUnsubscribe () { | |
ab4d4db4 C |
127 | const subscribeStatus = this.subscribeStatus(true) |
128 | ||
9270ccf6 | 129 | const observableBatch = this.videoChannels |
ab4d4db4 C |
130 | .map(videoChannel => this.getChannelHandler(videoChannel)) |
131 | .filter(handle => subscribeStatus.includes(handle)) | |
132 | .map(handle => this.userSubscriptionService.deleteSubscription(handle)) | |
41eb700f | 133 | |
ab4d4db4 C |
134 | concat(...observableBatch) |
135 | .subscribe({ | |
136 | complete: () => { | |
137 | this.notifier.success( | |
138 | this.account | |
66357162 C |
139 | ? $localize`Unsubscribed from all channels of ${this.account.nameWithHost}` |
140 | : $localize`Unsubscribed from ${this.videoChannels[ 0 ].nameWithHost}`, | |
141 | ||
142 | $localize`Unsubscribed` | |
ab4d4db4 C |
143 | ) |
144 | }, | |
22a16e36 | 145 | |
ab4d4db4 C |
146 | error: err => this.notifier.error(err.message) |
147 | }) | |
22a16e36 | 148 | } |
660d11e9 RK |
149 | |
150 | isUserLoggedIn () { | |
151 | return this.authService.isLoggedIn() | |
152 | } | |
153 | ||
154 | gotoLogin () { | |
155 | this.router.navigate([ '/login' ]) | |
156 | } | |
41eb700f | 157 | |
db84cf89 | 158 | subscribeStatus (subscribed: boolean) { |
9270ccf6 | 159 | const accumulator: string[] = [] |
41eb700f RK |
160 | for (const [key, value] of this.subscribed.entries()) { |
161 | if (value === subscribed) accumulator.push(key) | |
162 | } | |
db84cf89 | 163 | |
41eb700f RK |
164 | return accumulator |
165 | } | |
9270ccf6 | 166 | |
77d873c5 C |
167 | isSubscribedToAll () { |
168 | return Array.from(this.subscribed.values()).every(v => v === true) | |
169 | } | |
170 | ||
db84cf89 C |
171 | private getChannelHandler (videoChannel: VideoChannel) { |
172 | return videoChannel.name + '@' + videoChannel.host | |
173 | } | |
174 | ||
9270ccf6 RK |
175 | private loadSubscribedStatus () { |
176 | if (!this.isUserLoggedIn()) return | |
177 | ||
178 | for (const videoChannel of this.videoChannels) { | |
179 | const handle = this.getChannelHandler(videoChannel) | |
180 | this.subscribed.set(handle, false) | |
ab4d4db4 | 181 | |
9270ccf6 RK |
182 | merge( |
183 | this.userSubscriptionService.listenToSubscriptionCacheChange(handle), | |
184 | this.userSubscriptionService.doesSubscriptionExist(handle) | |
ab4d4db4 C |
185 | ).subscribe( |
186 | res => this.subscribed.set(handle, res), | |
9270ccf6 | 187 | |
ab4d4db4 C |
188 | err => this.notifier.error(err.message) |
189 | ) | |
9270ccf6 RK |
190 | } |
191 | } | |
22a16e36 | 192 | } |