git ssb

1+

Daan Patchwork / patchwork



Tree: f50400a95d8c5a977f0f39ee8b857c5ee9cdd630

Files: f50400a95d8c5a977f0f39ee8b857c5ee9cdd630 / lib / depject / contact / html / follow-toggle.js

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

Built with git-ssb-web