git ssb

2+

mixmix / ticktack



Commit 587259f06bdc6df8de5db46b20722a8402b644dd

Merge pull request #50 from ticktackim/cache_scroller

Cache scrollers
mix irving authored on 11/21/2017, 5:22:04 AM
GitHub committed on 11/21/2017, 5:22:04 AM
Parent: 88efa57edc6f7800ae827d2a28a7aab3065c1159
Parent: 8abd634c8aeca8b334b166fabf63622e73d71996

Files changed

app/html/context.jschanged
app/html/context.mcsschanged
app/html/scroller.jschanged
package-lock.jsonchanged
package.jsonchanged
app/html/context.jsView
@@ -1,6 +1,6 @@
11 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')
33 const pull = require('pull-stream')
44 const next = require('pull-next-step')
55 const get = require('lodash/get')
66 const isEmpty = require('lodash/isEmpty')
@@ -19,35 +19,20 @@
1919 'sbot.obs.localPeers': 'first',
2020 'translations.sync.strings': 'first',
2121 })
2222
23-
2423 exports.create = (api) => {
25- return nest('app.html.context', (location) => {
24+ var recentMsgCache = MutantArray()
25+ var usersMsgCache = Dict() // { id: [ msgs ] }
2626
27+ return nest('app.html.context', context)
28+
29+ function context (location) {
2730 const strings = api.translations.sync.strings()
2831 const myKey = api.keys.sync.id()
2932
3033 var nearby = api.sbot.obs.localPeers()
31- var recentMsgLog = Dict ()
32- function updateRecentMsgLog (msg) {
33- const { author, timestamp } = msg.value
3434
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-
5035 return h('Context -feed', [
5136 LevelOneContext(),
5237 LevelTwoContext()
5338 ])
@@ -67,10 +52,10 @@
6752 notifications: Math.random() > 0.7 ? Math.floor(Math.random()*9+1) : 0, // TODO
6853 imageEl: api.about.html.avatar(feedId, 'small'),
6954 label: api.about.obs.name(feedId),
7055 selected: location.feed === feedId,
71- location: computed(recentMsgLog, recent => {
72- const lastMsg = recent[feedId]
56+ location: computed(recentMsgCache, recent => {
57+ const lastMsg = recent.find(msg => msg.value.author === feedId)
7358 return lastMsg
7459 ? Object.assign(lastMsg, { feed: feedId })
7560 : { page: 'threadNew', feed: feedId }
7661 }),
@@ -95,14 +80,15 @@
9580 stream: api.feed.pull.private,
9681 filter: () => pull(
9782 pull.filter(msg => msg.value.content.type === 'post'), // TODO is this the best way to protect against votes?
9883 pull.filter(msg => msg.value.author != myKey),
99- pull.filter(msg => msg.value.content.recps),
100- pull.through(updateRecentMsgLog),
101- pull.filter(isLatestMsg)
102- //pull.through( // trim exisiting from content up Top case) // do this with new updateTop in mutant-scroll
84+ pull.filter(msg => msg.value.content.recps)
10385 ),
104- render: (msg) => {
86+ store: recentMsgCache,
87+ updateTop: updateRecentMsgCache,
88+ updateBottom: updateRecentMsgCache,
89+ render: (msgObs) => {
90+ const msg = resolve(msgObs)
10591 const { author } = msg.value
10692 if (nearby.has(author)) return
10793
10894 return Option({
@@ -113,43 +99,101 @@
11399 location: Object.assign({}, msg, { feed: author }) // TODO make obs?
114100 })
115101 }
116102 })
103+
104+ function updateRecentMsgCache (soFar, newMsg) {
105+ soFar.transaction(() => {
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+ // reference already exists, lets use this instead!
112+ const existingMsg = soFar.get(index)
113+
114+ if (resolve(existingMsg).value.timestamp > timestamp) return
115+ // but abort if the existing reference is newer
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+
117132 }
118133
119134 function LevelTwoContext () {
120135 const { key, value, feed: targetUser, page } = location
121136 const root = get(value, 'content.root', key)
122137 if (!targetUser) return
123138
124- var threads = MutantArray()
125139
126140 const prepend = Option({
127141 selected: page === 'threadNew',
128142 location: {page: 'threadNew', feed: targetUser},
129143 label: h('Button', strings.threadNew.action.new),
130144 })
131145
146+ var userMsgCache = usersMsgCache.get(targetUser)
147+ if (!userMsgCache) {
148+ userMsgCache = MutantArray()
149+ usersMsgCache.put(targetUser, userMsgCache)
150+ }
151+
132152 return api.app.html.scroller({
133153 classList: [ 'level', '-two' ],
134154 prepend,
135155 stream: api.feed.pull.private,
136156 filter: () => pull(
157+ pull.filter(msg => !msg.value.content.root), // only show the root message??? - check this still works with lastmessage
158+ pull.filter(msg => msg.value.content.type === 'post'), // TODO is this the best way to protect against votes?
137159 pull.filter(msg => msg.value.content.recps),
138160 pull.filter(msg => msg.value.content.recps
139161 .map(recp => typeof recp === 'object' ? recp.link : recp)
140162 .some(recp => recp === targetUser)
141- ),
142- api.feed.pull.rollup() // TODO - not technically a filter ...?
163+ )
143164 ),
144- render: (thread) => {
165+ store: userMsgCache,
166+ updateTop: updateUserMsgCache,
167+ updateBottom: updateUserMsgCache,
168+ render: (rootMsgObs) => {
169+ const rootMsg = resolve(rootMsgObs)
145170 return Option({
146- label: api.message.html.subject(thread),
147- selected: thread.key === root,
148- location: Object.assign(thread, { feed: targetUser }),
171+ label: api.message.html.subject(rootMsg),
172+ selected: rootMsg.key === root,
173+ location: Object.assign(rootMsg, { feed: targetUser }),
149174 })
150175 }
151176 })
177+
178+ function updateUserMsgCache (soFar, newMsg) {
179+ soFar.transaction(() => {
180+ const { timestamp } = newMsg.value
181+ const index = indexOf(soFar, (msg) => timestamp === resolve(msg).value.timestamp)
182+
183+ if (index >= 0) return
184+ // if reference already exists, abort
185+
186+ var object = Value(newMsg)
187+
188+ const justOlderPosition = indexOf(soFar, (msg) => timestamp > resolve(msg).value.timestamp)
189+ if (justOlderPosition > -1) {
190+ soFar.insert(object, justOlderPosition)
191+ } else {
192+ soFar.push(object)
193+ }
194+ })
195+ }
152196 }
153197
154198 function Option ({ notifications = 0, imageEl, label, location, selected }) {
155199 const className = selected ? '-selected' : ''
@@ -172,7 +216,15 @@
172216 ]),
173217 h('div.label', { 'ev-click': goToLocation }, label)
174218 ])
175219 }
176- })
220+ }
177221 }
178222
223+function indexOf (array, fn) {
224+ for (var i = 0; i < array.getLength(); i++) {
225+ if (fn(array.get(i))) {
226+ return i
227+ }
228+ }
229+ return -1
230+}
app/html/context.mcssView
@@ -12,25 +12,33 @@
1212 overflow-x: hidden
1313
1414 border-right: 1px gainsboro solid
1515
16- div.Option {}
16+ div.wrapper {
17+ section {
18+ header {
19+ $colorSubtle
20+ padding: .5rem 1rem
21+ }
1722
18- header {
19- $colorSubtle
20- padding: .5rem 1rem
21- }
23+ div.Option {}
2224
23- hr {
24- border: 1px solid gainsboro
25- border-bottom: none
26- margin: 0
25+ hr {
26+ border: 1px solid gainsboro
27+ border-bottom: none
28+ margin: 0
29+ }
30+ }
2731 }
2832
2933 -one {}
3034 -two {
31- div.Option {
32- padding: 0 1rem
35+ div.wrapper {
36+ section {
37+ div.Option {
38+ padding: 0 1rem
39+ }
40+ }
3341 }
3442 }
3543 }
3644 }
app/html/scroller.jsView
@@ -16,12 +16,9 @@
1616 function createScroller (opts = {}) {
1717 const {
1818 stream,
1919 filter = () => pull.filter((msg) => true),
20- // render,
21- // classList = [],
22- // prepend = [],
23- // append = []
20+
2421 } = opts
2522
2623 const streamToTop = pull(
2724 next(stream, {old: false, limit: 100}, ['value', 'timestamp']),
@@ -33,8 +30,19 @@
3330 filter()
3431 )
3532
3633 return Scroller(Object.assign({}, opts, { streamToTop, streamToBottom }))
34+ // valid Scroller opts : see github.com/mixmix/mutant-scroll
35+ // classList = [],
36+ // prepend = [],
37+ // append = [],
38+ // streamToTop,
39+ // streamToBottom,
40+ // render,
41+ // updateTop = updateTopDefault,
42+ // updateBottom = updateBottomDefault,
43+ // store = MutantArray(),
44+ // cb = (err) => { if (err) throw err }
3745 }
3846 }
3947
4048 function keyscroll (content) {
package-lock.jsonView
The diff is too large to show. Use a local git client to view these changes.
Old file size: 203359 bytes
New file size: 203359 bytes
package.jsonView
@@ -33,9 +33,9 @@
3333 "markdown-summary": "^1.0.3",
3434 "micro-css": "^2.0.1",
3535 "morphdom": "^2.3.3",
3636 "mutant": "^3.21.2",
37- "mutant-scroll": "0.0.1",
37+ "mutant-scroll": "0.0.3",
3838 "obv-debounce": "^1.0.2",
3939 "open-external": "^0.1.1",
4040 "patch-profile": "^1.0.2",
4141 "patch-settings": "^1.0.0",

Built with git-ssb-web