aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--changelog.d/quotes-count.add1
-rw-r--r--changelog.d/themes3-cache.add1
-rw-r--r--package.json1
-rw-r--r--src/boot/after_store.js26
-rw-r--r--src/boot/routes.js2
-rw-r--r--src/components/quotes_timeline/quotes_timeline.js26
-rw-r--r--src/components/quotes_timeline/quotes_timeline.vue10
-rw-r--r--src/components/settings_modal/tabs/general_tab.vue8
-rw-r--r--src/components/status/status.js3
-rw-r--r--src/components/status/status.scss1
-rw-r--r--src/components/status/status.vue15
-rw-r--r--src/components/timeline/timeline.js3
-rw-r--r--src/components/timeline_menu/timeline_menu.js3
-rw-r--r--src/i18n/cs.json4
-rw-r--r--src/i18n/en.json5
-rw-r--r--src/modules/api.js5
-rw-r--r--src/modules/config.js1
-rw-r--r--src/modules/instance.js3
-rw-r--r--src/services/api/api.service.js9
-rw-r--r--src/services/backend_interactor_service/backend_interactor_service.js4
-rw-r--r--src/services/entity_normalizer/entity_normalizer.service.js1
-rw-r--r--src/services/style_setter/style_setter.js37
-rw-r--r--src/services/theme_data/theme_data_3.service.js8
-rw-r--r--src/services/timeline_fetcher/timeline_fetcher.service.js8
24 files changed, 157 insertions, 28 deletions
diff --git a/changelog.d/quotes-count.add b/changelog.d/quotes-count.add
new file mode 100644
index 00000000..86779b96
--- /dev/null
+++ b/changelog.d/quotes-count.add
@@ -0,0 +1 @@
+Display quotes count on posts and add quotes list page \ No newline at end of file
diff --git a/changelog.d/themes3-cache.add b/changelog.d/themes3-cache.add
new file mode 100644
index 00000000..a275e44c
--- /dev/null
+++ b/changelog.d/themes3-cache.add
@@ -0,0 +1 @@
+Add caching system for themes3
diff --git a/package.json b/package.json
index cbbcb170..fb157fae 100644
--- a/package.json
+++ b/package.json
@@ -32,6 +32,7 @@
"click-outside-vue3": "4.0.1",
"cropperjs": "1.5.13",
"escape-html": "1.0.3",
+ "hash-sum": "^2.0.0",
"js-cookie": "3.0.5",
"localforage": "1.10.0",
"parse-link-header": "2.0.0",
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index bfb671ed..bcab7a66 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -14,7 +14,7 @@ import { windowWidth, windowHeight } from '../services/window_utils/window_utils
import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js'
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js'
-import { applyTheme, applyConfig } from '../services/style_setter/style_setter.js'
+import { applyTheme, applyConfig, tryLoadCache } from '../services/style_setter/style_setter.js'
import FaviconService from '../services/favicon_service/favicon_service.js'
import { initServiceWorker, updateFocus } from '../services/sw/sw.js'
@@ -353,21 +353,25 @@ const afterStoreSetup = async ({ store, i18n }) => {
await setConfig({ store })
- const { customTheme, customThemeSource } = store.state.config
+ const { customTheme, customThemeSource, forceThemeRecompilation } = store.state.config
const { theme } = store.state.instance
const customThemePresent = customThemeSource || customTheme
- if (customThemePresent) {
- if (customThemeSource && customThemeSource.themeEngineVersion === CURRENT_VERSION) {
- applyTheme(customThemeSource)
- } else {
- applyTheme(customTheme)
- }
+ if (!forceThemeRecompilation && tryLoadCache()) {
store.commit('setThemeApplied')
- } else if (theme) {
- // do nothing, it will load asynchronously
} else {
- console.error('Failed to load any theme!')
+ if (customThemePresent) {
+ if (customThemeSource && customThemeSource.themeEngineVersion === CURRENT_VERSION) {
+ applyTheme(customThemeSource)
+ } else {
+ applyTheme(customTheme)
+ }
+ store.commit('setThemeApplied')
+ } else if (theme) {
+ // do nothing, it will load asynchronously
+ } else {
+ console.error('Failed to load any theme!')
+ }
}
applyConfig(store.state.config)
diff --git a/src/boot/routes.js b/src/boot/routes.js
index 2dc900e7..31e3dbb0 100644
--- a/src/boot/routes.js
+++ b/src/boot/routes.js
@@ -25,6 +25,7 @@ import ListsTimeline from 'components/lists_timeline/lists_timeline.vue'
import ListsEdit from 'components/lists_edit/lists_edit.vue'
import NavPanel from 'src/components/nav_panel/nav_panel.vue'
import AnnouncementsPage from 'components/announcements_page/announcements_page.vue'
+import QuotesTimeline from '../components/quotes_timeline/quotes_timeline.vue'
export default (store) => {
const validateAuthenticatedRoute = (to, from, next) => {
@@ -51,6 +52,7 @@ export default (store) => {
{ name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline },
{ name: 'bookmarks', path: '/bookmarks', component: BookmarkTimeline },
{ name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
+ { name: 'quotes', path: '/notice/:id/quotes', component: QuotesTimeline },
{
name: 'remote-user-profile-acct',
path: '/remote-users/:_(@)?:username([^/@]+)@:hostname([^/@]+)',
diff --git a/src/components/quotes_timeline/quotes_timeline.js b/src/components/quotes_timeline/quotes_timeline.js
new file mode 100644
index 00000000..a5f42da5
--- /dev/null
+++ b/src/components/quotes_timeline/quotes_timeline.js
@@ -0,0 +1,26 @@
+import Timeline from '../timeline/timeline.vue'
+
+const QuotesTimeline = {
+ created () {
+ this.$store.commit('clearTimeline', { timeline: 'quotes' })
+ this.$store.dispatch('startFetchingTimeline', { timeline: 'quotes', statusId: this.statusId })
+ },
+ components: {
+ Timeline
+ },
+ computed: {
+ statusId () { return this.$route.params.id },
+ timeline () { return this.$store.state.statuses.timelines.quotes }
+ },
+ watch: {
+ statusId () {
+ this.$store.commit('clearTimeline', { timeline: 'quotes' })
+ this.$store.dispatch('startFetchingTimeline', { timeline: 'quotes', statusId: this.statusId })
+ }
+ },
+ unmounted () {
+ this.$store.dispatch('stopFetchingTimeline', 'quotes')
+ }
+}
+
+export default QuotesTimeline
diff --git a/src/components/quotes_timeline/quotes_timeline.vue b/src/components/quotes_timeline/quotes_timeline.vue
new file mode 100644
index 00000000..835abd12
--- /dev/null
+++ b/src/components/quotes_timeline/quotes_timeline.vue
@@ -0,0 +1,10 @@
+<template>
+ <Timeline
+ :title="$t('nav.quotes')"
+ :timeline="timeline"
+ :timeline-name="'quotes'"
+ :status-id="statusId"
+ />
+</template>
+
+<script src='./quotes_timeline.js'></script>
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index 05930e00..208c49ee 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -201,6 +201,14 @@
<h2>{{ $t('settings.post_look_feel') }}</h2>
<ul class="setting-list">
<li>
+ <BooleanSetting
+ path="forceThemeRecompilation"
+ :expert="1"
+ >
+ {{ $t('settings.force_theme_recompilation_debug') }}
+ </BooleanSetting>
+ </li>
+ <li>
<ChoiceSetting
id="conversationDisplay"
path="conversationDisplay"
diff --git a/src/components/status/status.js b/src/components/status/status.js
index e4fb1f51..bf4e4275 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -373,6 +373,9 @@ const Status = {
hidePostStats () {
return this.mergedConfig.hidePostStats
},
+ shouldDisplayFavsAndRepeats () {
+ return !this.hidePostStats && this.isFocused && (this.combinedFavsAndRepeatsUsers.length > 0 || this.statusFromGlobalRepository.quotes_count)
+ },
muteBotStatuses () {
return this.mergedConfig.muteBotStatuses
},
diff --git a/src/components/status/status.scss b/src/components/status/status.scss
index dfdc1189..63809ff2 100644
--- a/src/components/status/status.scss
+++ b/src/components/status/status.scss
@@ -374,6 +374,7 @@
font-weight: bolder;
font-size: 1.1em;
line-height: 1em;
+ color: var(--text);
}
&:hover .stat-title {
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 2a17bb13..61a58cda 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -484,7 +484,7 @@
<transition name="fade">
<div
- v-if="!hidePostStats && isFocused && combinedFavsAndRepeatsUsers.length > 0"
+ v-if="shouldDisplayFavsAndRepeats"
class="favs-repeated-users"
>
<div class="stats">
@@ -512,6 +512,19 @@
</div>
</div>
</UserListPopover>
+ <router-link
+ v-if="statusFromGlobalRepository.quotes_count > 0"
+ :to="{ name: 'quotes', params: { id: status.id } }"
+ >
+ <div
+ class="stat-count"
+ >
+ <a class="stat-title">{{ $t('status.quotes') }}</a>
+ <div class="stat-number">
+ {{ statusFromGlobalRepository.quotes_count }}
+ </div>
+ </div>
+ </router-link>
<div class="avatar-row">
<AvatarList :users="combinedFavsAndRepeatsUsers" />
</div>
diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js
index 47e4a45e..59170f49 100644
--- a/src/components/timeline/timeline.js
+++ b/src/components/timeline/timeline.js
@@ -25,6 +25,7 @@ const Timeline = {
'title',
'userId',
'listId',
+ 'statusId',
'tag',
'embedded',
'count',
@@ -121,6 +122,7 @@ const Timeline = {
showImmediately,
userId: this.userId,
listId: this.listId,
+ statusId: this.statusId,
tag: this.tag
})
},
@@ -183,6 +185,7 @@ const Timeline = {
showImmediately: true,
userId: this.userId,
listId: this.listId,
+ statusId: this.statusId,
tag: this.tag
}).then(({ statuses }) => {
if (statuses && statuses.length === 0) {
diff --git a/src/components/timeline_menu/timeline_menu.js b/src/components/timeline_menu/timeline_menu.js
index 5a2a86c2..c4586b32 100644
--- a/src/components/timeline_menu/timeline_menu.js
+++ b/src/components/timeline_menu/timeline_menu.js
@@ -19,7 +19,8 @@ export const timelineNames = () => {
bookmarks: 'nav.bookmarks',
dms: 'nav.dms',
'public-timeline': 'nav.public_tl',
- 'public-external-timeline': 'nav.twkn'
+ 'public-external-timeline': 'nav.twkn',
+ quotes: 'nav.quotes'
}
}
diff --git a/src/i18n/cs.json b/src/i18n/cs.json
index 9c04ede7..c3ba7ca4 100644
--- a/src/i18n/cs.json
+++ b/src/i18n/cs.json
@@ -678,7 +678,7 @@
"autohide_floating_post_button": "Automaticky skrýt tlačítko nového příspěvku (mobilní zařízení)",
"minimal_scopes_mode": "Minimalizovat možnosti rozsahu příspěvků",
"conversation_display": "Styl zobrazení konverzací",
- "conversation_display_tree": "Stromový styl",
+ "conversation_display_tree": "Stromové zobrazení",
"conversation_display_tree_quick": "Stromový styl",
"show_scrollbars": "Zobrazit posuvníky bočních sloupců",
"third_column_mode": "Pokud je volné místo, zobrazit třetí sloupec obsahující",
@@ -863,7 +863,7 @@
"favorites": "Oblíbené",
"follow": "Sledovat",
"follow_sent": "Požadavek odeslán!",
- "follow_progress": "Odeslílám požadavek…",
+ "follow_progress": "Odesílám požadavek…",
"follow_unfollow": "Přestat sledovat",
"followees": "Sledovaní",
"followers": "Sledující",
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 7a03b49d..f626e933 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -189,7 +189,8 @@
"mobile_notifications": "Open notifications (there are unread ones)",
"mobile_notifications_close": "Close notifications",
"mobile_notifications_mark_as_seen": "Mark all as seen",
- "announcements": "Announcements"
+ "announcements": "Announcements",
+ "quotes": "Quotes"
},
"notifications": {
"broken_favorite": "Unknown status, searching for it…",
@@ -644,6 +645,7 @@
"subject_line_email": "Like email: \"re: subject\"",
"subject_line_mastodon": "Like mastodon: copy as is",
"subject_line_noop": "Do not copy",
+ "force_theme_recompilation_debug": "Disable theme cahe, force recompile on each boot (DEBUG)",
"conversation_display": "Conversation display style",
"conversation_display_tree": "Tree-style",
"conversation_display_tree_quick": "Tree view",
@@ -1056,6 +1058,7 @@
"status": {
"favorites": "Favorites",
"repeats": "Repeats",
+ "quotes": "Quotes",
"repeat_confirm": "Do you really want to repeat this status?",
"repeat_confirm_title": "Repeat confirmation",
"repeat_confirm_accept_button": "Repeat",
diff --git a/src/modules/api.js b/src/modules/api.js
index fee584e8..3dbead5b 100644
--- a/src/modules/api.js
+++ b/src/modules/api.js
@@ -202,12 +202,13 @@ const api = {
timeline = 'friends',
tag = false,
userId = false,
- listId = false
+ listId = false,
+ statusId = false
}) {
if (store.state.fetchers[timeline]) return
const fetcher = store.state.backendInteractor.startFetchingTimeline({
- timeline, store, userId, listId, tag
+ timeline, store, userId, listId, statusId, tag
})
store.commit('addFetcher', { fetcherName: timeline, fetcher })
},
diff --git a/src/modules/config.js b/src/modules/config.js
index a59a80d8..8001b854 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -28,6 +28,7 @@ export const defaultState = {
theme: undefined,
customTheme: undefined,
customThemeSource: undefined,
+ forceThemeRecompilation: false,
hideISP: false,
hideInstanceWallpaper: false,
hideShoutbox: false,
diff --git a/src/modules/instance.js b/src/modules/instance.js
index f12cc735..0a5c1ae7 100644
--- a/src/modules/instance.js
+++ b/src/modules/instance.js
@@ -378,7 +378,8 @@ const instance = {
commit('setInstanceOption', { name: 'themeData', value: themeData })
// No need to apply theme if there's user theme already
const { customTheme } = rootState.config
- if (customTheme) return
+ const { themeApplied } = rootState.interface
+ if (customTheme || themeApplied) return
// New theme presets don't have 'theme' property, they use 'source'
const themeSource = themeData.source
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index a47c638c..fa417193 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -108,6 +108,7 @@ const PLEROMA_POST_ANNOUNCEMENT_URL = '/api/v1/pleroma/admin/announcements'
const PLEROMA_EDIT_ANNOUNCEMENT_URL = id => `/api/v1/pleroma/admin/announcements/${id}`
const PLEROMA_DELETE_ANNOUNCEMENT_URL = id => `/api/v1/pleroma/admin/announcements/${id}`
const PLEROMA_SCROBBLES_URL = id => `/api/v1/pleroma/accounts/${id}/scrobbles`
+const PLEROMA_STATUS_QUOTES_URL = id => `/api/v1/pleroma/statuses/${id}/quotes`
const PLEROMA_USER_FAVORITES_TIMELINE_URL = id => `/api/v1/pleroma/accounts/${id}/favourites`
const PLEROMA_ADMIN_CONFIG_URL = '/api/pleroma/admin/config'
@@ -685,6 +686,7 @@ const fetchTimeline = ({
until = false,
userId = false,
listId = false,
+ statusId = false,
tag = false,
withMuted = false,
replyVisibility = 'all',
@@ -702,7 +704,8 @@ const fetchTimeline = ({
favorites: MASTODON_USER_FAVORITES_TIMELINE_URL,
publicFavorites: PLEROMA_USER_FAVORITES_TIMELINE_URL,
tag: MASTODON_TAG_TIMELINE_URL,
- bookmarks: MASTODON_BOOKMARK_TIMELINE_URL
+ bookmarks: MASTODON_BOOKMARK_TIMELINE_URL,
+ quotes: PLEROMA_STATUS_QUOTES_URL
}
const isNotifications = timeline === 'notifications'
const params = []
@@ -721,6 +724,10 @@ const fetchTimeline = ({
url = url(listId)
}
+ if (timeline === 'quotes') {
+ url = url(statusId)
+ }
+
if (minId) {
params.push(['min_id', minId])
}
diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js
index 62ee8549..8ceb897d 100644
--- a/src/services/backend_interactor_service/backend_interactor_service.js
+++ b/src/services/backend_interactor_service/backend_interactor_service.js
@@ -5,8 +5,8 @@ import followRequestFetcher from '../../services/follow_request_fetcher/follow_r
import listsFetcher from '../../services/lists_fetcher/lists_fetcher.service.js'
const backendInteractorService = credentials => ({
- startFetchingTimeline ({ timeline, store, userId = false, listId = false, tag }) {
- return timelineFetcher.startFetching({ timeline, store, credentials, userId, listId, tag })
+ startFetchingTimeline ({ timeline, store, userId = false, listId = false, statusId = false, tag }) {
+ return timelineFetcher.startFetching({ timeline, store, credentials, userId, listId, statusId, tag })
},
fetchTimeline (args) {
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
index 21e67b67..e41e7125 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -331,6 +331,7 @@ export const parseStatus = (data) => {
output.quote_id = pleroma.quote_id ? pleroma.quote_id : (output.quote ? output.quote.id : undefined)
output.quote_url = pleroma.quote_url
output.quote_visible = pleroma.quote_visible
+ output.quotes_count = pleroma.quotes_count
} else {
output.text = data.content
output.summary = data.spoiler_text
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index 95198ec7..369d2c9f 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -1,6 +1,6 @@
import { hex2rgb } from '../color_convert/color_convert.js'
import { generatePreset } from '../theme_data/theme_data.service.js'
-import { init } from '../theme_data/theme_data_3.service.js'
+import { init, getEngineChecksum } from '../theme_data/theme_data_3.service.js'
import { convertTheme2To3 } from '../theme_data/theme2_to_theme3.js'
import { getCssRules } from '../theme_data/css_utils.js'
import { defaultState } from '../../modules/config.js'
@@ -87,9 +87,37 @@ export const generateTheme = async (input, callbacks) => {
return { lazyProcessFunc: processChunk }
}
-export const applyTheme = async (input) => {
+export const tryLoadCache = () => {
+ const json = localStorage.getItem('pleroma-fe-theme-cache')
+ if (!json) return null
+ let cache
+ try {
+ cache = JSON.parse(json)
+ } catch (e) {
+ console.error('Failed to decode theme cache:', e)
+ return false
+ }
+ if (cache.engineChecksum === getEngineChecksum()) {
+ const styleSheet = new CSSStyleSheet()
+ const lazyStyleSheet = new CSSStyleSheet()
+
+ cache.data[0].forEach(rule => styleSheet.insertRule(rule, 'index-max'))
+ cache.data[1].forEach(rule => lazyStyleSheet.insertRule(rule, 'index-max'))
+
+ document.adoptedStyleSheets = [styleSheet, lazyStyleSheet]
+
+ return true
+ } else {
+ console.warn('Engine checksum doesn\'t match, cache not usable, clearing')
+ localStorage.removeItem('pleroma-fe-theme-cache')
+ }
+}
+
+export const applyTheme = async (input, onFinish = (data) => {}) => {
const styleSheet = new CSSStyleSheet()
+ const styleArray = []
const lazyStyleSheet = new CSSStyleSheet()
+ const lazyStyleArray = []
const { lazyProcessFunc } = await generateTheme(
input,
@@ -97,8 +125,10 @@ export const applyTheme = async (input) => {
onNewRule (rule, isLazy) {
if (isLazy) {
lazyStyleSheet.insertRule(rule, 'index-max')
+ lazyStyleArray.push(rule)
} else {
styleSheet.insertRule(rule, 'index-max')
+ styleArray.push(rule)
}
},
onEagerFinished () {
@@ -106,6 +136,9 @@ export const applyTheme = async (input) => {
},
onLazyFinished () {
document.adoptedStyleSheets = [styleSheet, lazyStyleSheet]
+ const cache = { engineChecksum: getEngineChecksum(), data: [styleArray, lazyStyleArray] }
+ onFinish(cache)
+ localStorage.setItem('pleroma-fe-theme-cache', JSON.stringify(cache))
}
}
)
diff --git a/src/services/theme_data/theme_data_3.service.js b/src/services/theme_data/theme_data_3.service.js
index 7457ab99..15b4493e 100644
--- a/src/services/theme_data/theme_data_3.service.js
+++ b/src/services/theme_data/theme_data_3.service.js
@@ -1,4 +1,5 @@
import { convert, brightness } from 'chromatism'
+import sum from 'hash-sum'
import { flattenDeep } from 'lodash'
import {
alphaBlend,
@@ -142,8 +143,12 @@ componentsContext.keys().forEach(key => {
components[component.name] = component
})
+const engineChecksum = sum(components)
+
const ruleToSelector = genericRuleToSelector(components)
+export const getEngineChecksum = () => engineChecksum
+
export const init = (extraRuleset, ultimateBackgroundColor) => {
const staticVars = {}
const stacked = {}
@@ -463,6 +468,7 @@ export const init = (extraRuleset, ultimateBackgroundColor) => {
return {
lazy: result.filter(x => typeof x === 'function'),
eager: result.filter(x => typeof x !== 'function'),
- staticVars
+ staticVars,
+ engineChecksum
}
}
diff --git a/src/services/timeline_fetcher/timeline_fetcher.service.js b/src/services/timeline_fetcher/timeline_fetcher.service.js
index 8501907e..2fed14bc 100644
--- a/src/services/timeline_fetcher/timeline_fetcher.service.js
+++ b/src/services/timeline_fetcher/timeline_fetcher.service.js
@@ -24,6 +24,7 @@ const fetchAndUpdate = ({
showImmediately = false,
userId = false,
listId = false,
+ statusId = false,
tag = false,
until,
since
@@ -47,6 +48,7 @@ const fetchAndUpdate = ({
args.userId = userId
args.listId = listId
+ args.statusId = statusId
args.tag = tag
args.withMuted = !hideMutedPosts
if (loggedIn && ['friends', 'public', 'publicAndExternal'].includes(timeline)) {
@@ -78,15 +80,15 @@ const fetchAndUpdate = ({
})
}
-const startFetching = ({ timeline = 'friends', credentials, store, userId = false, listId = false, tag = false }) => {
+const startFetching = ({ timeline = 'friends', credentials, store, userId = false, listId = false, statusId = false, tag = false }) => {
const rootState = store.rootState || store.state
const timelineData = rootState.statuses.timelines[camelCase(timeline)]
const showImmediately = timelineData.visibleStatuses.length === 0
timelineData.userId = userId
timelineData.listId = listId
- fetchAndUpdate({ timeline, credentials, store, showImmediately, userId, listId, tag })
+ fetchAndUpdate({ timeline, credentials, store, showImmediately, userId, listId, statusId, tag })
const boundFetchAndUpdate = () =>
- fetchAndUpdate({ timeline, credentials, store, userId, listId, tag })
+ fetchAndUpdate({ timeline, credentials, store, userId, listId, statusId, tag })
return promiseInterval(boundFetchAndUpdate, 10000)
}
const timelineFetcher = {