git ssb

1+

Daan Patchwork / patchwork



Tree: 06ded70b47c2b7b6dbd436a59f532f6caff0e67c

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

6585 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.ignores': 'first'
14})
15
16exports.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
209function looseMatch (a, b) {
210 return a === b || (a == null && b == null)
211}
212

Built with git-ssb-web