thedesk/app/js/tl/notification.js

420 lines
13 KiB
JavaScript
Raw Permalink Normal View History

2018-01-28 23:22:43 +11:00
//通知
//取得+Streaming接続
2019-05-19 17:39:30 +10:00
function notf(acct_id, tlid, sys) {
2019-11-09 00:52:54 +11:00
if (sys == 'direct') {
notfColumn(acct_id, tlid, sys)
2019-01-26 14:24:26 +11:00
} else {
2019-11-09 00:52:54 +11:00
notfCommon(acct_id, tlid, sys)
2019-01-26 14:24:26 +11:00
}
}
2019-05-19 17:39:30 +10:00
function notfColumn(acct_id, tlid, sys) {
2019-11-09 00:52:54 +11:00
todo('Notifications Loading...')
var native = localStorage.getItem('nativenotf')
var at = localStorage.getItem('acct_' + acct_id + '_at')
2019-05-19 17:39:30 +10:00
if (!native) {
2019-11-09 00:52:54 +11:00
native = 'yes'
2018-03-31 13:39:06 +11:00
}
2019-11-09 00:52:54 +11:00
var domain = localStorage.getItem('domain_' + acct_id)
var httpreq = new XMLHttpRequest()
if (localStorage.getItem('mode_' + domain) == 'misskey') {
var misskey = true
var start = 'https://' + domain + '/api/i/notifications'
httpreq.open('POST', start, true)
httpreq.setRequestHeader('Content-Type', 'application/json')
2019-05-19 17:39:30 +10:00
var body = JSON.stringify({
i: at
2019-11-09 00:52:54 +11:00
})
2019-05-19 17:39:30 +10:00
} else {
2019-11-09 00:52:54 +11:00
var misskey = false
if (localStorage.getItem('exclude-' + tlid)) {
var exc = localStorage.getItem('exclude-' + tlid)
2019-05-19 17:39:30 +10:00
} else {
2019-11-09 00:52:54 +11:00
var exc = ''
2019-01-26 14:24:26 +11:00
}
2019-11-09 00:52:54 +11:00
var start = 'https://' + domain + '/api/v1/notifications' + exc
httpreq.open('GET', start, true)
httpreq.setRequestHeader('Content-Type', 'application/json')
httpreq.setRequestHeader('Authorization', 'Bearer ' + at)
var body = ''
2018-07-30 21:03:49 +10:00
}
2019-05-19 17:39:30 +10:00
2019-11-09 00:52:54 +11:00
httpreq.responseType = 'json'
httpreq.send(body)
2019-11-04 03:10:06 +11:00
httpreq.onreadystatechange = function() {
2019-03-08 05:19:26 +11:00
if (httpreq.readyState === 4) {
2019-11-09 00:52:54 +11:00
var json = httpreq.response
2019-11-04 03:10:06 +11:00
if (this.status !== 200) {
2019-11-09 00:52:54 +11:00
setLog(start, this.status, this.response)
2019-11-04 03:10:06 +11:00
}
2019-11-09 00:52:54 +11:00
var max_id = httpreq.getResponseHeader('link')
2019-05-19 17:39:30 +10:00
if (max_id) {
2019-11-09 00:52:54 +11:00
max_id = max_id.match(/[?&]{1}max_id=([0-9]+)/)[1]
2019-05-08 01:48:59 +10:00
}
2019-05-19 17:39:30 +10:00
if (json[0]) {
2019-11-09 00:52:54 +11:00
var templete = ''
var lastnotf = localStorage.getItem('lastnotf_' + acct_id)
localStorage.setItem('lastnotf_' + acct_id, json[0].id)
2019-11-04 03:10:06 +11:00
Object.keys(json).forEach(function(key) {
2019-11-09 00:52:54 +11:00
var obj = json[key]
if (lastnotf == obj.id && key > 0 && native == 'yes') {
var ct = key
2019-05-19 17:39:30 +10:00
if (key > 14) {
2019-11-09 00:52:54 +11:00
ct = '15+'
2019-03-06 19:08:48 +11:00
}
2019-11-09 00:52:54 +11:00
var os = localStorage.getItem('platform')
2019-05-19 17:39:30 +10:00
var options = {
body: ct + lang.lang_notf_new,
2019-11-09 00:52:54 +11:00
icon: localStorage.getItem('prof_' + acct_id)
}
var n = new Notification('TheDesk:' + domain, options)
2019-03-06 19:08:48 +11:00
}
2019-11-09 04:05:15 +11:00
var mute = getFilterTypeByAcct(acct_id, 'notif')
//Pleromaにはmoveというtypeがあるらしい。何が互換APIじゃ
2019-12-17 03:11:12 +11:00
if (obj.type != 'follow' && obj.type != 'move' && obj.type != 'follow_request') {
2019-05-19 17:39:30 +10:00
if (misskey) {
2019-11-09 00:52:54 +11:00
templete = templete + misskeyParse([obj], 'notf', acct_id, tlid, -1, mute)
2019-05-19 17:39:30 +10:00
} else {
2019-11-09 00:52:54 +11:00
templete = templete + parse([obj], 'notf', acct_id, tlid, -1, mute)
2019-03-06 19:08:48 +11:00
}
2019-12-17 03:11:12 +11:00
} else if (obj.type == 'follow_request') {
templete = templete + userparse([obj.account], 'request', acct_id, tlid, -1)
2019-05-19 17:39:30 +10:00
} else {
if (misskey) {
2019-11-09 00:52:54 +11:00
templete = templete + misskeyUserparse([obj], 'notf', acct_id, tlid, -1, mute)
2019-05-19 17:39:30 +10:00
} else {
templete = templete + userparse([obj.account], obj.type, acct_id, tlid, -1)
2019-03-06 19:08:48 +11:00
}
}
2019-11-09 00:52:54 +11:00
})
templete = templete + '<div class="hide notif-marker" data-maxid="' + max_id + '"></div>'
$('#timeline_' + tlid).html(templete)
$('#landing_' + tlid).hide()
jQuery('time.timeago').timeago()
2019-05-19 17:39:30 +10:00
}
2019-11-09 00:52:54 +11:00
$('#notf-box').addClass('fetched')
todc()
2019-09-08 02:44:28 +10:00
//Markers
2019-11-09 00:52:54 +11:00
var markers = localStorage.getItem('markers')
if (markers == 'yes') {
markers = true
2019-09-08 02:44:28 +10:00
} else {
2019-11-09 00:52:54 +11:00
markers = false
2019-09-08 02:44:28 +10:00
}
if (markers) {
2019-11-09 00:52:54 +11:00
getMarker(tlid, 'notf', acct_id)
2019-09-08 02:44:28 +10:00
}
2019-01-26 14:24:26 +11:00
}
2019-11-09 00:52:54 +11:00
}
2019-05-19 17:39:30 +10:00
if (!misskey) {
2019-11-09 00:52:54 +11:00
if (localStorage.getItem('streaming_' + acct_id)) {
var wss = localStorage.getItem('streaming_' + acct_id)
2019-05-19 17:39:30 +10:00
} else {
2019-11-09 00:52:54 +11:00
var wss = 'wss://' + domain
2019-01-26 14:24:26 +11:00
}
2019-11-09 00:52:54 +11:00
var start = wss + '/api/v1/streaming/?stream=user&access_token=' + at
2019-05-19 17:39:30 +10:00
} else {
2019-11-09 00:52:54 +11:00
var start = 'wss://' + domain + '/?i=' + at
2019-01-26 14:24:26 +11:00
}
}
function notfCommon(acct_id, tlid, sys) {
2019-11-09 00:52:54 +11:00
todo('Notifications Loading...')
var native = localStorage.getItem('nativenotf')
var at = localStorage.getItem('acct_' + acct_id + '_at')
2019-05-19 17:39:30 +10:00
if (!native) {
2019-11-09 00:52:54 +11:00
native = 'yes'
2019-01-26 14:24:26 +11:00
}
2019-11-09 00:52:54 +11:00
var domain = localStorage.getItem('domain_' + acct_id)
if (localStorage.getItem('mode_' + domain) == 'misskey') {
var misskey = true
var start = 'https://' + domain + '/api/i/notifications'
2019-05-19 17:39:30 +10:00
var i = {
2019-11-09 00:52:54 +11:00
method: 'POST',
2019-01-26 14:24:26 +11:00
headers: {
2019-11-09 00:52:54 +11:00
'content-type': 'application/json'
2019-01-26 14:24:26 +11:00
},
2019-05-19 17:39:30 +10:00
body: JSON.stringify({
i: at
2019-01-26 14:24:26 +11:00
})
2019-11-09 00:52:54 +11:00
}
2019-05-19 17:39:30 +10:00
} else {
2019-11-09 00:52:54 +11:00
var misskey = false
var start = 'https://' + domain + '/api/v1/notifications'
2019-05-19 17:39:30 +10:00
var i = {
2019-11-09 00:52:54 +11:00
method: 'GET',
2019-01-26 14:24:26 +11:00
headers: {
2019-11-09 00:52:54 +11:00
'content-type': 'application/json',
Authorization: 'Bearer ' + at
2019-11-04 03:10:06 +11:00
}
2019-11-09 00:52:54 +11:00
}
2019-01-26 14:24:26 +11:00
}
2019-11-04 03:10:06 +11:00
fetch(start, i)
.then(function(response) {
2019-11-09 00:52:54 +11:00
console.log('header to get param:' + response.headers.get('link'))
2019-11-04 03:10:06 +11:00
if (!response.ok) {
response.text().then(function(text) {
2019-11-09 00:52:54 +11:00
setLog(response.url, response.status, text)
})
2019-11-04 03:10:06 +11:00
}
2019-11-09 00:52:54 +11:00
return response.json()
2019-11-04 03:10:06 +11:00
})
.catch(function(error) {
2019-11-09 00:52:54 +11:00
todo(error)
setLog(start, 'JSON', error)
console.error(error)
2019-11-04 03:10:06 +11:00
})
.then(function(json) {
if (json[0]) {
2019-11-09 00:52:54 +11:00
var templete = ''
var lastnotf = localStorage.getItem('lastnotf_' + acct_id)
localStorage.setItem('lastnotf_' + acct_id, json[0].id)
2019-11-04 03:10:06 +11:00
Object.keys(json).forEach(function(key) {
2019-11-09 00:52:54 +11:00
var obj = json[key]
if (lastnotf == obj.id && key > 0 && native == 'yes') {
var ct = key
2019-11-04 03:10:06 +11:00
if (key > 14) {
2019-11-09 00:52:54 +11:00
ct = '15+'
2019-11-04 03:10:06 +11:00
}
2019-11-09 00:52:54 +11:00
var os = localStorage.getItem('platform')
2019-11-04 03:10:06 +11:00
var options = {
body: ct + lang.lang_notf_new,
2019-11-09 00:52:54 +11:00
icon: localStorage.getItem('prof_' + acct_id)
}
var n = new Notification('TheDesk:' + domain, options)
2019-05-19 17:39:30 +10:00
}
2019-11-09 04:05:15 +11:00
var mute = getFilterTypeByAcct(acct_id, 'notif')
2019-12-12 02:06:12 +11:00
//Pleromaにはmoveというtypeがあるらしい。何が互換APIじゃ
if (obj.type != 'follow' && obj.type != 'move') {
2019-11-04 03:10:06 +11:00
if (misskey) {
2019-11-09 00:52:54 +11:00
templete = templete + misskeyParse([obj], 'notf', acct_id, 'notf', -1, mute)
2019-11-04 03:10:06 +11:00
} else {
2019-11-09 00:52:54 +11:00
templete = templete + parse([obj], 'notf', acct_id, 'notf', -1, mute)
2019-11-04 03:10:06 +11:00
}
2019-05-19 17:39:30 +10:00
} else {
2019-11-04 03:10:06 +11:00
if (misskey) {
2019-11-09 00:52:54 +11:00
templete = templete + misskeyUserparse([obj], 'notf', acct_id, 'notf', -1, mute)
2019-11-04 03:10:06 +11:00
} else {
templete = templete + userparse([obj.account], obj.type, acct_id, 'notf', -1)
2019-11-04 03:10:06 +11:00
}
2019-05-19 17:39:30 +10:00
}
2019-11-09 00:52:54 +11:00
})
$('div[data-notf=' + acct_id + ']').html(templete)
$('#landing_' + tlid).hide()
jQuery('time.timeago').timeago()
2019-11-04 03:10:06 +11:00
}
2019-11-09 00:52:54 +11:00
$('#notf-box').addClass('fetched')
todc()
notfWS(misskey, acct_id, tlid, domain, at)
})
2019-05-11 02:31:15 +10:00
}
2019-05-19 17:39:30 +10:00
function notfWS(misskey, acct_id, tlid, domain, at) {
if (!misskey) {
2019-11-09 00:52:54 +11:00
if (localStorage.getItem('streaming_' + acct_id)) {
var wss = localStorage.getItem('streaming_' + acct_id)
2019-05-19 17:39:30 +10:00
} else {
2019-11-09 00:52:54 +11:00
var wss = 'wss://' + domain
2018-09-17 21:55:00 +10:00
}
2019-11-09 00:52:54 +11:00
var start = wss + '/api/v1/streaming/?stream=user&access_token=' + at
2018-01-28 23:22:43 +11:00
2019-11-09 00:52:54 +11:00
var wsid = websocketNotf.length
websocketNotf[acct_id] = new WebSocket(start)
2019-11-04 03:10:06 +11:00
websocketNotf[acct_id].onopen = function(mess) {
2019-11-09 00:52:54 +11:00
console.table({
acct_id: acct_id,
type: 'Connect Streaming API(Notf)',
domain: domain,
message: [mess]
})
$('i[data-notf=' + acct_id + ']').removeClass('red-text')
}
2019-11-04 03:10:06 +11:00
websocketNotf[acct_id].onmessage = function(mess) {
2019-08-20 00:31:42 +10:00
//console.log(["Receive Streaming API(Notf):" + acct_id + "(" + domain + ")", JSON.parse(JSON.parse(mess.data).payload)]);
2019-11-09 00:52:54 +11:00
var popup = localStorage.getItem('popup')
2018-07-30 21:03:49 +10:00
if (!popup) {
2019-11-09 00:52:54 +11:00
popup = 0
2018-07-30 21:03:49 +10:00
}
2019-11-09 00:52:54 +11:00
var obj = JSON.parse(JSON.parse(mess.data).payload)
var type = JSON.parse(mess.data).event
if (type == 'notification') {
var templete = ''
localStorage.setItem('lastnotf_' + acct_id, obj.id)
if (!$('#unread_' + tlid + ' .material-icons').hasClass('teal-text')) {
2019-09-07 02:33:30 +10:00
//markers show中はダメ
2019-11-09 00:52:54 +11:00
if (obj.type != 'follow') {
templete = parse([obj], 'notf', acct_id, 'notf', popup)
2019-09-07 02:33:30 +10:00
} else {
templete = userparse([obj], obj.type, acct_id, 'notf', popup)
2019-09-07 02:33:30 +10:00
}
2019-11-09 00:52:54 +11:00
if (!$('div[data-notfIndv=' + acct_id + '_' + obj.id + ']').length) {
$('div[data-notf=' + acct_id + ']').prepend(templete)
$('div[data-const=notf_' + acct_id + ']').prepend(templete)
2019-09-07 02:33:30 +10:00
}
2019-11-09 00:52:54 +11:00
jQuery('time.timeago').timeago()
2019-05-19 17:39:30 +10:00
}
2019-11-09 00:52:54 +11:00
} else if (type == 'delete') {
$('[toot-id=' + obj + ']').hide()
$('[toot-id=' + obj + ']').remove()
2018-02-26 02:32:10 +11:00
}
2019-11-09 00:52:54 +11:00
}
2019-11-04 03:10:06 +11:00
websocketNotf[acct_id].onerror = function(error) {
2019-11-09 00:52:54 +11:00
console.error('WebSocket Error ' + error)
errorct++
console.log(errorct)
2019-10-05 01:21:52 +10:00
if (errorct < 3) {
2019-11-09 00:52:54 +11:00
notfWS(misskey, acct_id, tlid, domain, at)
2019-10-05 01:21:52 +10:00
}
2019-11-09 00:52:54 +11:00
}
2019-11-04 03:10:06 +11:00
websocketNotf[acct_id].onclose = function(error) {
2019-11-09 00:52:54 +11:00
console.error('WebSocket Close ' + error)
errorct++
console.log(errorct)
2019-10-05 01:21:52 +10:00
if (errorct < 3) {
2019-11-09 00:52:54 +11:00
notfWS(misskey, acct_id, tlid, domain, at)
2019-10-05 01:21:52 +10:00
}
2019-11-09 00:52:54 +11:00
}
2018-01-28 23:22:43 +11:00
}
2019-05-08 01:48:59 +10:00
}
2018-03-15 06:42:48 +11:00
//一定のスクロールで発火
function notfmore(tlid) {
2019-11-09 00:52:54 +11:00
console.log({ status: 'kicked', status: moreloading })
var multi = localStorage.getItem('column')
var obj = JSON.parse(multi)
var acct_id = obj[tlid].domain
2018-03-15 06:42:48 +11:00
if (!type) {
2019-11-09 00:52:54 +11:00
var type = obj[tlid].type
2019-05-19 17:39:30 +10:00
} else {
2019-11-09 00:52:54 +11:00
var data
2018-03-15 06:42:48 +11:00
}
2019-11-09 00:52:54 +11:00
var sid = $('#timeline_' + tlid + ' .notif-marker')
2019-11-04 03:10:06 +11:00
.last()
2019-11-09 00:52:54 +11:00
.attr('data-maxid')
var at = localStorage.getItem('acct_' + acct_id + '_at')
var domain = localStorage.getItem('domain_' + acct_id)
2019-03-06 19:08:48 +11:00
if (sid && !moreloading) {
2019-11-09 00:52:54 +11:00
moreloading = true
var httpreq = new XMLHttpRequest()
if (localStorage.getItem('mode_' + domain) == 'misskey') {
var misskey = true
var start = 'https://' + domain + '/api/i/notifications'
httpreq.open(POST, start, true)
httpreq.setRequestHeader('Content-Type', 'application/json')
2019-05-19 17:39:30 +10:00
var body = JSON.stringify({
i: at,
untilID: sid
2019-11-09 00:52:54 +11:00
})
2019-05-19 17:39:30 +10:00
} else {
2019-11-09 00:52:54 +11:00
var misskey = false
if (localStorage.getItem('exclude-' + tlid)) {
var exc = localStorage.getItem('exclude-' + tlid) + '&max_id=' + sid
2019-05-19 17:39:30 +10:00
} else {
2019-11-09 00:52:54 +11:00
var exc = '?max_id=' + sid
2019-05-19 17:39:30 +10:00
}
2019-11-09 00:52:54 +11:00
var start = 'https://' + domain + '/api/v1/notifications' + exc
httpreq.open('GET', start, true)
httpreq.setRequestHeader('Content-Type', 'application/json')
httpreq.setRequestHeader('Authorization', 'Bearer ' + at)
var body = ''
2019-03-06 19:08:48 +11:00
}
2019-05-19 17:39:30 +10:00
2019-11-09 00:52:54 +11:00
httpreq.responseType = 'json'
httpreq.send(body)
2019-11-04 03:10:06 +11:00
httpreq.onreadystatechange = function() {
2019-05-19 17:39:30 +10:00
if (httpreq.readyState === 4) {
2019-11-09 00:52:54 +11:00
var json = httpreq.response
2019-11-04 03:10:06 +11:00
if (this.status !== 200) {
2019-11-09 00:52:54 +11:00
setLog(start, this.status, this.response)
2019-11-04 03:10:06 +11:00
}
2019-11-09 00:52:54 +11:00
console.log(['More notifications on ' + tlid, json])
var max_id = httpreq.getResponseHeader('link').match(/[?&]{1}max_id=([0-9]+)/)[1]
2019-05-19 17:39:30 +10:00
if (json[0]) {
2019-11-09 00:52:54 +11:00
var templete = ''
var lastnotf = localStorage.getItem('lastnotf_' + acct_id)
localStorage.setItem('lastnotf_' + acct_id, json[0].id)
2019-11-04 03:10:06 +11:00
Object.keys(json).forEach(function(key) {
2019-11-09 00:52:54 +11:00
var obj = json[key]
2019-11-09 04:05:15 +11:00
var mute = getFilterTypeByAcct(acct_id, 'notif')
2019-11-09 00:52:54 +11:00
if (obj.type != 'follow') {
2019-05-19 17:39:30 +10:00
if (misskey) {
2019-11-09 00:52:54 +11:00
templete = templete + misskeyParse([obj], 'notf', acct_id, 'notf', -1, mute)
2019-05-19 17:39:30 +10:00
} else {
2019-11-09 00:52:54 +11:00
templete = templete + parse([obj], 'notf', acct_id, 'notf', -1, mute)
2019-05-19 17:39:30 +10:00
}
} else {
if (misskey) {
2019-11-09 00:52:54 +11:00
templete = templete + misskeyUserparse([obj], 'notf', acct_id, 'notf', -1, mute)
2019-05-19 17:39:30 +10:00
} else {
templete = templete + userparse([obj.account], obj.type, acct_id, 'notf', -1)
2019-05-19 17:39:30 +10:00
}
2019-03-06 19:08:48 +11:00
}
2019-11-09 00:52:54 +11:00
})
moreloading = false
templete = templete + '<div class="hide notif-marker" data-maxid="' + max_id + '"></div>'
$('#timeline_' + tlid).append(templete)
$('#landing_' + tlid).hide()
jQuery('time.timeago').timeago()
2018-03-15 06:42:48 +11:00
}
2019-11-09 00:52:54 +11:00
$('#notf-box').addClass('fetched')
todc()
2019-05-19 17:39:30 +10:00
}
2019-11-09 00:52:54 +11:00
}
2018-03-15 06:42:48 +11:00
}
}
2018-01-28 23:22:43 +11:00
//通知トグルボタン
function notfToggle(acct, tlid) {
2019-11-09 00:52:54 +11:00
if ($('#notf-box_' + tlid).hasClass('column-hide')) {
$('#notf-box_' + tlid).css('display', 'block')
$('#notf-box_' + tlid).animate(
2019-11-04 03:10:06 +11:00
{
2019-11-09 00:52:54 +11:00
height: '400px'
2019-11-04 03:10:06 +11:00
},
{
duration: 300,
complete: function() {
2019-11-09 00:52:54 +11:00
$('#notf-box_' + tlid).css('overflow-y', 'scroll')
$('#notf-box_' + tlid).removeClass('column-hide')
2019-11-04 03:10:06 +11:00
}
2019-10-05 01:21:52 +10:00
}
2019-11-09 00:52:54 +11:00
)
2019-05-19 17:39:30 +10:00
} else {
2019-11-09 00:52:54 +11:00
$('#notf-box_' + tlid).css('overflow-y', 'hidden')
$('#notf-box_' + tlid).animate(
2019-11-04 03:10:06 +11:00
{
2019-11-09 00:52:54 +11:00
height: '0'
2019-11-04 03:10:06 +11:00
},
{
duration: 300,
complete: function() {
2019-11-09 00:52:54 +11:00
$('#notf-box_' + tlid).addClass('column-hide')
$('#notf-box_' + tlid).css('display', 'none')
2019-11-04 03:10:06 +11:00
}
2019-10-05 01:21:52 +10:00
}
2019-11-09 00:52:54 +11:00
)
2018-08-10 01:18:35 +10:00
}
2019-11-09 00:52:54 +11:00
notfCanceler(acct)
2018-07-28 07:25:12 +10:00
}
2019-05-19 17:39:30 +10:00
function notfCanceler(acct) {
2019-11-09 00:52:54 +11:00
$('.notf-reply_' + acct).text(0)
localStorage.removeItem('notf-reply_' + acct)
$('.notf-reply_' + acct).addClass('hide')
$('.notf-fav_' + acct).text(0)
localStorage.removeItem('notf-fav_' + acct)
$('.notf-fav_' + acct).addClass('hide')
$('.notf-bt_' + acct).text(0)
localStorage.removeItem('notf-bt_' + acct)
$('.notf-bt_' + acct).addClass('hide')
$('.notf-follow_' + acct).text(0)
localStorage.removeItem('notf-follow_' + acct)
$('.notf-follow_' + acct).addClass('hide')
$('.notf-icon_' + acct).removeClass('red-text')
2018-01-28 23:22:43 +11:00
}
2019-05-19 17:39:30 +10:00
function allNotfRead() {
2019-11-09 00:52:54 +11:00
var multi = localStorage.getItem('multi')
2019-04-11 02:52:01 +10:00
if (multi) {
2019-11-09 00:52:54 +11:00
var obj = JSON.parse(multi)
2019-11-04 03:10:06 +11:00
Object.keys(obj).forEach(function(key) {
2019-11-09 00:52:54 +11:00
notfCanceler(key)
})
2019-05-19 17:39:30 +10:00
}
2019-04-11 02:52:01 +10:00
}
2019-11-09 00:52:54 +11:00
allNotfRead()