Files: 3451510316992d414ec76ba5b29681fe359b7428 / lib / depject / contact / html / follow-toggle.js
6585 bytesRaw
1 | const nest = require('depnest') |
2 | const electron = require('electron') |
3 | const { h, when, computed } = require('mutant') |
4 | |
5 | exports.gives = nest('contact.html.followToggle') |
6 | exports.needs = nest({ |
7 | 'intl.sync.i18n': 'first', |
8 | 'keys.sync.id': 'first', |
9 | 'message.async.publish': 'first', |
10 | 'sbot.async.publish': 'first', |
11 | 'contact.obs.states': 'first', |
12 | 'contact.obs.followers': 'first', |
13 | 'contact.obs.ignores': 'first' |
14 | }) |
15 | |
16 | exports.create = function (api) { |
17 | const i18n = api.intl.sync.i18n |
18 | return nest('contact.html.followToggle', function (id, opts) { |
19 | const yourId = api.keys.sync.id() |
20 | |
21 | const states = api.contact.obs.states(yourId) |
22 | const yourFollowers = api.contact.obs.followers(yourId) |
23 | const ignores = api.contact.obs.ignores() |
24 | |
25 | const followsYou = computed([yourFollowers], function (yourFollowers) { |
26 | return yourFollowers.includes(id) |
27 | }) |
28 | |
29 | const youIgnore = computed([ignores], function (ignores) { |
30 | return !!ignores[id] |
31 | }) |
32 | |
33 | const youListening = computed([ignores], function (ignores) { |
34 | return ignores[id] === false |
35 | }) |
36 | |
37 | const youFollow = computed([states], function (states) { |
38 | return states[id] === true |
39 | }) |
40 | |
41 | const youBlock = computed([states], function (states) { |
42 | return states[id] === false |
43 | }) |
44 | |
45 | const isFriends = computed([followsYou, youFollow], function (a, b) { |
46 | return a && b |
47 | }) |
48 | |
49 | const ignoreText = when(youIgnore, ' ' + i18n('(ignored)')) |
50 | const listeningText = when(youListening, ' ' + i18n('(listening)')) |
51 | |
52 | const showBlockButton = computed([opts && opts.block], (block) => block !== false) |
53 | |
54 | if (id !== yourId) { |
55 | return [ |
56 | when(youBlock, [ |
57 | h('a ToggleButton -unblocking', { |
58 | href: '#', |
59 | title: i18n('Click to unblock'), |
60 | 'ev-click': () => setStatus(id, null, { states, ignores }) |
61 | }, [i18n('Blocked'), listeningText]) |
62 | ], [ |
63 | when(youFollow, |
64 | h('a ToggleButton -unsubscribe', { |
65 | href: '#', |
66 | title: i18n('Click to unfollow'), |
67 | 'ev-click': () => setStatus(id, null, { states, ignores }) |
68 | }, [when(isFriends, i18n('Friends'), i18n('Following')), ignoreText]), |
69 | h('a ToggleButton -subscribe', { |
70 | href: '#', |
71 | 'ev-click': () => setStatus(id, true, { states, ignores }) |
72 | }, [when(followsYou, i18n('Follow Back'), i18n('Follow')), ignoreText]) |
73 | ) |
74 | ]), |
75 | when(showBlockButton, h('a ToggleButton -drop -options', { |
76 | href: '#', |
77 | title: i18n('Click for options to block syncing with this person and/or hide their posts'), |
78 | 'ev-click': (ev) => popupContactMenu(ev.currentTarget, id, { states, ignores }) |
79 | }, i18n('Options'))) |
80 | ] |
81 | } else { |
82 | return [] |
83 | } |
84 | }) |
85 | |
86 | function popupContactMenu (element, id, { states, ignores }) { |
87 | const rects = element.getBoundingClientRect() |
88 | const status = states()[id] |
89 | const ignoring = ignores()[id] |
90 | |
91 | // the actual listening state (use the explicit ignore if available, otherwise depends if blocking) |
92 | const resolvedIgnoring = ignoring != null |
93 | ? ignoring |
94 | : status === false |
95 | |
96 | const factor = electron.remote.getCurrentWindow().webContents.getZoomFactor() |
97 | const menu = electron.remote.Menu.buildFromTemplate([ |
98 | { |
99 | type: 'radio', |
100 | label: i18n('Neutral'), |
101 | checked: status == null, |
102 | click: () => setStatus(id, null, { states, ignores }) |
103 | }, |
104 | { |
105 | type: 'radio', |
106 | label: i18n('Follow'), |
107 | checked: status === true, |
108 | click: () => setStatus(id, true, { states, ignores }) |
109 | }, |
110 | { |
111 | type: 'radio', |
112 | label: i18n('Block'), |
113 | checked: status === false, |
114 | click: () => setStatus(id, false, { states, ignores }) |
115 | }, |
116 | { type: 'separator' }, |
117 | { |
118 | type: 'radio', |
119 | label: i18n('Listen'), |
120 | checked: !resolvedIgnoring, |
121 | click: () => setIgnore(id, false, { states, ignores }) |
122 | }, |
123 | { |
124 | type: 'radio', |
125 | label: i18n('Ignore'), |
126 | checked: resolvedIgnoring, |
127 | click: () => setIgnore(id, true, { states, ignores }) |
128 | } |
129 | ]) |
130 | menu.popup({ |
131 | window: electron.remote.getCurrentWindow(), |
132 | x: Math.round(rects.left * factor), |
133 | y: Math.round(rects.bottom * factor) + 4 |
134 | }) |
135 | } |
136 | |
137 | function setStatus (id, status, { states, ignores }) { |
138 | const currentStatus = states()[id] |
139 | const currentIgnoring = ignores()[id] |
140 | |
141 | if (!looseMatch(status, currentStatus)) { |
142 | const message = { |
143 | type: 'contact', |
144 | contact: id |
145 | } |
146 | |
147 | if (status === true) { // FOLLOW |
148 | message.following = true |
149 | } else if (status === false) { // BLOCK |
150 | message.blocking = true |
151 | } else if (currentStatus === true) { // UNFOLLOW |
152 | message.following = false |
153 | } else if (currentStatus === false) { // UNBLOCK |
154 | message.blocking = false |
155 | } |
156 | |
157 | api.message.async.publish(message, (err) => { |
158 | if (!err && currentIgnoring && status !== false) { |
159 | // if we are currently ignoring (private blocking) |
160 | // renew the action for ssb-friends compatibility |
161 | // unless this is a block action |
162 | api.sbot.async.publish({ |
163 | recps: [api.keys.sync.id()], |
164 | type: 'contact', |
165 | contact: id, |
166 | blocking: true |
167 | }) |
168 | } |
169 | }) |
170 | } |
171 | } |
172 | |
173 | function setIgnore (id, ignoring, { states, ignores }) { |
174 | const currentStatus = states()[id] |
175 | const currentIgnoring = ignores()[id] |
176 | const yourId = api.keys.sync.id() |
177 | |
178 | if (!looseMatch(ignoring, currentIgnoring)) { |
179 | if (ignoring === false && currentStatus === false) { |
180 | // user is publicly blocking, but wants to still see this feed |
181 | api.sbot.async.publish({ |
182 | recps: [yourId], |
183 | type: 'contact', |
184 | blocking: false, |
185 | following: false, |
186 | contact: id |
187 | }) |
188 | } else if (ignoring === true) { |
189 | // user wants to ignore (privately block) this feed |
190 | api.sbot.async.publish({ |
191 | recps: [yourId], |
192 | type: 'contact', |
193 | blocking: true, |
194 | contact: id |
195 | }) |
196 | } else { |
197 | // user wants to stop ignoring this feed (remove ignore) |
198 | api.sbot.async.publish({ |
199 | recps: [yourId], |
200 | type: 'contact', |
201 | contact: id, |
202 | following: currentStatus === true |
203 | }) |
204 | } |
205 | } |
206 | } |
207 | } |
208 | |
209 | function looseMatch (a, b) { |
210 | return a === b || (a == null && b == null) |
211 | } |
212 |
Built with git-ssb-web