Permalink
Browse files

preserve unread flags on messages after refresh (if haven't scrolled …

…past)

also match unread flag appearance in light and dark themes
  • Loading branch information...
mmckegg committed Dec 4, 2017
1 parent 3ce9f27 commit cff270be8e13b929bbb91731f12bf29dfa001197
View
@@ -6,9 +6,15 @@ var computed = require('mutant/computed')
module.exports = Scroller
function Scroller (scroller, content, render, cb) {
function Scroller (scroller, content, render, opts) {
if (typeof opts === 'function') {
opts = {onDone: opts}
} else if (!opts) {
opts = {}
}
var toRenderCount = Value(0)
var toAppendCount = Value(0)
var pendingVisible = new Set()
var queueLength = computed([toRenderCount, toAppendCount], (a, b) => a + b)
@@ -20,7 +26,9 @@ function Scroller (scroller, content, render, cb) {
var distanceFromBottom = scroller.scrollHeight - (scroller.scrollTop + scroller.clientHeight)
if (distanceFromBottom < scroller.clientHeight) {
while (appendQueue.length) {
content.appendChild(appendQueue.shift())
var element = appendQueue.shift()
content.appendChild(element)
pendingVisible.add(element)
}
}
@@ -33,6 +41,7 @@ function Scroller (scroller, content, render, cb) {
if (running || queueLength()) {
window.requestAnimationFrame(appendLoop)
}
}
var stream = pull(
@@ -51,12 +60,29 @@ function Scroller (scroller, content, render, cb) {
}
}, function (err) {
running = false
cb ? cb(err) : console.error(err)
clearInterval(visibleInterval)
opts.onDone ? opts.onDone(err) : console.error(err)
})
)
var visibleInterval = setInterval(() => {
// check for visible items every 2 seconds
Array.from(pendingVisible).forEach(checkVisible)
}, 2000)
stream.queue = queueLength
appendLoop()
return stream
function checkVisible (element) {
var height = scroller.clientHeight
var rect = element.getBoundingClientRect()
if (height > 50 && rect.bottom < height) {
pendingVisible.delete(element)
if (opts.onItemVisible) {
onceIdle(() => opts.onItemVisible(element))
}
}
}
}
View
@@ -184,5 +184,6 @@
"See less": "See less",
"See more": "See more",
"(missing message)": "(missing message)",
"assigned a description to ": "assigned a description to "
"assigned a description to ": "assigned a description to ",
"Unread Message": "Unread Message"
}
@@ -61,6 +61,7 @@ exports.create = function (api) {
var abortLastFeed = null
var content = Value()
var loading = Proxy(true)
var unreadIds = new Set()
var newSinceRefresh = new Set()
var highlightItems = new Set()
@@ -107,6 +108,7 @@ exports.create = function (api) {
// shown on new messages that patchwork cannot render
if (canRenderMessage(msg) && (!msg.root || canRenderMessage(msg.root))) {
newSinceRefresh.add(msg.key)
unreadIds.add(msg.key)
}
if (updates() === 0 && msg.value.author === yourId && container.scrollTop < 20) {
@@ -144,9 +146,20 @@ exports.create = function (api) {
highlightItems = newSinceRefresh
newSinceRefresh = new Set()
window.thing = unreadIds
var done = Value(false)
var stream = nextStepper(getStream, {reverse: true, limit: 50})
var scroller = Scroller(container, content(), renderItem, () => done.set(true))
var scroller = Scroller(container, content(), renderItem, {
onDone: () => done.set(true),
onItemVisible: (item) => {
if (Array.isArray(item.msgIds)) {
item.msgIds.forEach(id => {
unreadIds.delete(id)
})
}
}
})
// track loading state
loading.set(computed([done, scroller.queue], (done, queue) => {
@@ -193,14 +206,15 @@ exports.create = function (api) {
})
var replies = item.replies.filter(isReply).sort(byAssertedTime)
var highlightedReplies = replies.filter(isHighlighted)
var highlightedReplies = replies.filter(getPriority)
var replyElements = replies.filter(displayFilter).slice(-3).map((msg) => {
var result = api.message.html.render(msg, {
previousId,
compact: compactFilter(msg, item),
priority: highlightItems.has(msg.key) ? 2 : 0
priority: getPriority(msg)
})
previousId = msg.key
return [
// insert missing message marker (if can't be found)
api.message.html.missing(last(msg.value.content.branch), msg),
@@ -211,9 +225,11 @@ exports.create = function (api) {
var renderedMessage = api.message.html.render(item, {
compact: compactFilter(item),
includeForks: false, // this is a root message, so forks are already displayed as replies
priority: highlightItems.has(item.key) ? 2 : 0
priority: getPriority(item)
})
unreadIds.delete(item.key)
if (!renderedMessage) return h('div')
if (lastBumpType) {
var bumps = lastBumpType === 'vote'
@@ -229,7 +245,7 @@ exports.create = function (api) {
// if there are new messages, view full thread goes to the top of those, otherwise to very first reply
var anchorReply = highlightedReplies.length >= 3 ? highlightedReplies[0] : replies[0]
return h('FeedEvent -post', {
var result = h('FeedEvent -post', {
attributes: {
'data-root-id': item.key
}
@@ -241,10 +257,20 @@ exports.create = function (api) {
),
h('div.replies', replyElements)
])
result.msgIds = [item.key].concat(item.replies.map(x => x.key))
return result
}
function isHighlighted (msg) {
return highlightItems.has(msg.key)
function getPriority (msg) {
if (highlightItems.has(msg.key)) {
return 2
} else if (unreadIds.has(msg.key)) {
return 1
} else {
return 0
}
}
})
@@ -54,6 +54,10 @@ exports.create = function (api) {
classList.push('-new')
}
if (priority === 1) {
classList.push('-unread')
}
return h('div', {
classList
}, [
@@ -86,8 +90,10 @@ exports.create = function (api) {
function messageHeader (msg, {replyInfo, priority}) {
var additionalMeta = []
if (priority >= 2) {
if (priority === 2) {
additionalMeta.push(h('span.flag -new', {title: i18n('New Message')}))
} else if (priority === 1) {
additionalMeta.push(h('span.flag -unread', {title: i18n('Unread Message')}))
}
return h('header', [
h('div.main', [
@@ -10,7 +10,7 @@ FeedEvent {
margin-bottom: -25px
}
-new {
-new, -unread {
box-shadow: 0px 0px 2px #ffc800;
background: #fffdf7;
}
View
@@ -93,7 +93,7 @@ Message {
}
}
-new {
-new, -unread {
box-shadow: 0 0 1px #efef00;
z-index: 1;
}
@@ -159,22 +159,29 @@ Message {
display: inline-block
vertical-align: middle;
-unread {
:after {
content: ' unread'
color: #757474
}
}
-new {
:after {
content: ' new'
color: #757474
}
}
-new, -unread {
width: auto
height: auto
color: #757474
font-size: 75%
:before {
content: '✸ new'
font-size: 75%
}
:hover {
color: #efef00
}
:first-letter {
color: #efef00
content: '✸'
}
}
}
@@ -11,7 +11,7 @@ FeedEvent {
margin-bottom: -25px
}
-new {
-new, -unread {
box-shadow: 0px 0px 2px #ffc800;
background: #fffdf7;
}
View
@@ -93,7 +93,7 @@ Message {
}
}
-new {
-new, -unread {
box-shadow: 0 0 1px #ffc600;
z-index: 1;
}
@@ -148,14 +148,34 @@ Message {
vertical-align: middle;
margin-top: -3px;
-unread {
:after {
content: ' unread'
font-size: 75%
color: #b7b7b7
}
}
-new {
background-image: svg(new)
:after {
content: ' new'
font-size: 75%
color: #b7b7b7
}
}
@svg new {
width: 12px
height: 12px
content: "<circle cx='6' stroke='none' fill='#ffcf04' cy='6' r='5' />"
-new, -unread {
width: auto
height: auto
:before {
color: #ffcf04
content: '✸'
}
:first-letter {
font-size: 100%
}
}
}

0 comments on commit cff270b

Please sign in to comment.