app/html/context.jsView |
---|
1 | 1 | const nest = require('depnest') |
2 | | -const { h, computed, map, when, Dict, dictToCollection, Array: MutantArray, resolve } = require('mutant') |
| 2 | +const { h, computed, map, when, Dict, dictToCollection, Array: MutantArray, Value, resolve } = require('mutant') |
3 | 3 | const pull = require('pull-stream') |
4 | 4 | const next = require('pull-next-step') |
5 | 5 | const get = require('lodash/get') |
6 | 6 | const isEmpty = require('lodash/isEmpty') |
19 | 19 | 'sbot.obs.localPeers': 'first', |
20 | 20 | 'translations.sync.strings': 'first', |
21 | 21 | }) |
22 | 22 | |
23 | | - |
24 | 23 | exports.create = (api) => { |
25 | | - return nest('app.html.context', (location) => { |
| 24 | + var recentMsgCache = MutantArray() |
| 25 | + var userMsgCache = Dict() |
26 | 26 | |
| 27 | + return nest('app.html.context', context) |
| 28 | + |
| 29 | + function context (location) { |
27 | 30 | const strings = api.translations.sync.strings() |
28 | 31 | const myKey = api.keys.sync.id() |
29 | 32 | |
30 | 33 | var nearby = api.sbot.obs.localPeers() |
31 | | - var recentMsgLog = Dict () |
32 | | - function updateRecentMsgLog (msg) { |
33 | | - const { author, timestamp } = msg.value |
34 | 34 | |
35 | | - if (!recentMsgLog.has(author)) { |
36 | | - recentMsgLog.put(author, msg) |
37 | | - return |
38 | | - } |
39 | | - |
40 | | - const currentWinner = recentMsgLog.get(author) |
41 | | - if (timestamp > currentWinner.value.timestamp) { |
42 | | - recentMsgLog.put(author, msg) |
43 | | - } |
44 | | - } |
45 | | - function isLatestMsg (msg) { |
46 | | - const { author, timestamp } = msg.value |
47 | | - return recentMsgLog.get(author).value.timestamp === timestamp |
48 | | - } |
49 | | - |
50 | 35 | return h('Context -feed', [ |
51 | 36 | LevelOneContext(), |
52 | 37 | LevelTwoContext() |
53 | 38 | ]) |
67 | 52 | notifications: Math.random() > 0.7 ? Math.floor(Math.random()*9+1) : 0, |
68 | 53 | imageEl: api.about.html.avatar(feedId, 'small'), |
69 | 54 | label: api.about.obs.name(feedId), |
70 | 55 | selected: location.feed === feedId, |
71 | | - location: computed(recentMsgLog, recent => { |
| 56 | + location: computed(recentMsgCache, recent => { |
72 | 57 | const lastMsg = recent[feedId] |
73 | 58 | return lastMsg |
74 | 59 | ? Object.assign(lastMsg, { feed: feedId }) |
75 | 60 | : { page: 'threadNew', feed: feedId } |
95 | 80 | stream: api.feed.pull.private, |
96 | 81 | filter: () => pull( |
97 | 82 | pull.filter(msg => msg.value.content.type === 'post'), |
98 | 83 | pull.filter(msg => msg.value.author != myKey), |
99 | | - pull.filter(msg => msg.value.content.recps), |
100 | | - pull.through(updateRecentMsgLog), |
101 | | - pull.filter(isLatestMsg) |
102 | | - |
| 84 | + pull.filter(msg => msg.value.content.recps) |
103 | 85 | ), |
104 | | - render: (msg) => { |
| 86 | + store: recentMsgCache, |
| 87 | + updateTop: updateRecentMsgCache, |
| 88 | + updateBottom: updateRecentMsgCache, |
| 89 | + render: (msgObs) => { |
| 90 | + const msg = resolve(msgObs) |
105 | 91 | const { author } = msg.value |
106 | 92 | if (nearby.has(author)) return |
107 | 93 | |
108 | 94 | return Option({ |
113 | 99 | location: Object.assign({}, msg, { feed: author }) |
114 | 100 | }) |
115 | 101 | } |
116 | 102 | }) |
| 103 | + |
| 104 | + function updateRecentMsgCache (soFar, newMsg) { |
| 105 | + soFar.transaction(function () { |
| 106 | + const { author, timestamp } = newMsg.value |
| 107 | + const index = indexOf(soFar, (msg) => author === resolve(msg).value.author) |
| 108 | + var object = Value() |
| 109 | + |
| 110 | + if (index >= 0) { |
| 111 | + |
| 112 | + const existingMsg = soFar.get(index) |
| 113 | + |
| 114 | + if (resolve(existingMsg).value.timestamp > timestamp) return |
| 115 | + |
| 116 | + |
| 117 | + object = existingMsg |
| 118 | + soFar.deleteAt(index) |
| 119 | + } |
| 120 | + |
| 121 | + object.set(newMsg) |
| 122 | + |
| 123 | + const justOlderPosition = indexOf(soFar, (msg) => timestamp > resolve(msg).value.timestamp) |
| 124 | + if (justOlderPosition > -1) { |
| 125 | + soFar.insert(object, justOlderPosition) |
| 126 | + } else { |
| 127 | + soFar.push(object) |
| 128 | + } |
| 129 | + }) |
| 130 | + } |
| 131 | + |
| 132 | + function indexOf (array, fn) { |
| 133 | + for (var i = 0; i < array.getLength(); i++) { |
| 134 | + if (fn(array.get(i))) { |
| 135 | + return i |
| 136 | + } |
| 137 | + } |
| 138 | + return -1 |
| 139 | + } |
117 | 140 | } |
118 | 141 | |
119 | 142 | function LevelTwoContext () { |
120 | 143 | const { key, value, feed: targetUser, page } = location |
172 | 195 | ]), |
173 | 196 | h('div.label', { 'ev-click': goToLocation }, label) |
174 | 197 | ]) |
175 | 198 | } |
176 | | - }) |
| 199 | + } |
177 | 200 | } |
178 | 201 | |