mirror of
https://github.com/yang991178/fluent-reader.git
synced 2025-02-07 23:38:41 +01:00
keep items until switching feeds
This commit is contained in:
parent
110be62694
commit
1d8863922f
5
dist/styles/cards.css
vendored
5
dist/styles/cards.css
vendored
@ -119,7 +119,7 @@
|
||||
}
|
||||
.default-card img.bg {
|
||||
object-fit: cover;
|
||||
filter: saturate(150%) blur(20px);
|
||||
filter: var(--blur);
|
||||
}
|
||||
.default-card div.bg {
|
||||
background-color: #fffb;
|
||||
@ -230,6 +230,9 @@
|
||||
height: 100%;
|
||||
border-left: 2px solid var(--primary);
|
||||
}
|
||||
.list-card.read, .list-card.read p.snippet {
|
||||
color: var(--neutralSecondaryAlt);
|
||||
}
|
||||
|
||||
.magazine-card {
|
||||
width: 700px;
|
||||
|
4
dist/styles/feeds.css
vendored
4
dist/styles/feeds.css
vendored
@ -173,9 +173,11 @@
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-around;
|
||||
padding: 12px;
|
||||
height: calc(100% - 56px);
|
||||
height: calc(100% - 32px);
|
||||
overflow: hidden scroll;
|
||||
margin-top: var(--navHeight);
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.cards-feed-container .ms-List-page {
|
||||
display: flex;
|
||||
|
12
dist/styles/global.css
vendored
12
dist/styles/global.css
vendored
@ -1,5 +1,5 @@
|
||||
:root {
|
||||
--neutralLighterAltOpacity: rgba(250, 249, 248, 0.8);
|
||||
--neutralLighterAltOpacity: #faf9f8cc;
|
||||
--neutralLighterAlt: #faf9f8;
|
||||
--neutralLighter: #f3f2f1;
|
||||
--neutralLight: #edebe9;
|
||||
@ -18,13 +18,12 @@
|
||||
--whiteConstant: #fff;
|
||||
--primary: #0078d4;
|
||||
--navHeight: 32px;
|
||||
|
||||
--blur-0: saturate(150%) blur(16px);
|
||||
--blur-1: saturate(150%) blur(32px);
|
||||
--transition-timing: cubic-bezier(0.1, 0.9, 0.2, 1);
|
||||
--blur: saturate(150%) blur(20px);
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--neutralLighterAltOpacity: rgba(40, 40, 40, 0.8);
|
||||
--neutralLighterAltOpacity: #282828cc;
|
||||
--neutralLighterAlt: #282828;
|
||||
--neutralLighter: #313131;
|
||||
--neutralLight: #3f3f3f;
|
||||
@ -54,6 +53,9 @@ html, body {
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
}
|
||||
body.win32, body.linux {
|
||||
background-color: var(--neutralLighterAlt);
|
||||
}
|
||||
#root {
|
||||
height: 100%;
|
||||
}
|
||||
|
16
dist/styles/main.css
vendored
16
dist/styles/main.css
vendored
@ -18,13 +18,13 @@
|
||||
height: 100%;
|
||||
}
|
||||
.article-container {
|
||||
backdrop-filter: saturate(150%) blur(20px);
|
||||
backdrop-filter: var(--blur);
|
||||
animation-name: fade;
|
||||
background-color: #0008;
|
||||
}
|
||||
.menu-container, .article-container, .article-wrapper {
|
||||
animation-duration: 0.5s;
|
||||
animation-timing-function: cubic-bezier(0.1, 0.9, 0.2, 1);
|
||||
animation-timing-function: var(--transition-timing);
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
.menu-container {
|
||||
@ -43,13 +43,15 @@
|
||||
width: 280px;
|
||||
height: 100%;
|
||||
background-color: var(--neutralLighterAltOpacity);
|
||||
backdrop-filter: var(--blur-1);
|
||||
backdrop-filter: var(--blur);
|
||||
box-shadow: 5px 0 25px #0004;
|
||||
transition: clip-path cubic-bezier(0.1, 0.9, 0.2, 1) .367s;
|
||||
clip-path: inset(0 100% 0 0);;
|
||||
transition: clip-path var(--transition-timing) .367s, opacity cubic-bezier(0, 0, 0.2, 1) .367s;
|
||||
clip-path: inset(0 100% 0 0);
|
||||
opacity: 0;
|
||||
}
|
||||
.menu-container.show .menu {
|
||||
clip-path: inset(0 -50px 0 0);;
|
||||
clip-path: inset(0 -50px 0 0);
|
||||
opacity: 1;
|
||||
}
|
||||
body.blur .menu .btn-group {
|
||||
--black: var(--neutralSecondaryAlt);
|
||||
@ -235,7 +237,7 @@ body.darwin .list-main .article-search {
|
||||
margin: 0 10px;
|
||||
}
|
||||
.main, .list-main {
|
||||
transition: margin-left cubic-bezier(0.1, 0.9, 0.2, 1) .367s;
|
||||
transition: margin-left var(--transition-timing) .367s;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
|
@ -132,6 +132,9 @@ class Article extends React.Component<ArticleProps, ArticleState> {
|
||||
case "w": case "W":
|
||||
this.toggleFull()
|
||||
break
|
||||
case "H": case "h":
|
||||
this.props.toggleHidden(this.props.item)
|
||||
break
|
||||
default:
|
||||
const keyboardEvent = new KeyboardEvent("keydown", {
|
||||
code: input.code,
|
||||
|
@ -8,6 +8,7 @@ const className = (props: Card.Props) => {
|
||||
let cn = ["card", "list-card"]
|
||||
if (props.item.hidden) cn.push("hidden")
|
||||
if (props.selected) cn.push("selected")
|
||||
if ((props.viewConfigs & ViewConfigs.FadeRead) && props.item.hasRead) cn.push("read")
|
||||
return cn.join(" ")
|
||||
}
|
||||
|
||||
|
@ -170,6 +170,13 @@ export class ContextMenu extends React.Component<ContextMenuProps> {
|
||||
checked: Boolean(this.props.viewConfigs & ViewConfigs.ShowSnippet),
|
||||
onClick: () => this.props.setViewConfigs(this.props.viewConfigs ^ ViewConfigs.ShowSnippet)
|
||||
},
|
||||
{
|
||||
key: "fadeRead",
|
||||
text: intl.get("context.fadeRead"),
|
||||
canCheck: true,
|
||||
checked: Boolean(this.props.viewConfigs & ViewConfigs.FadeRead),
|
||||
onClick: () => this.props.setViewConfigs(this.props.viewConfigs ^ ViewConfigs.FadeRead)
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
@ -16,7 +16,7 @@ export type MenuProps = {
|
||||
searchOn: boolean,
|
||||
itemOn: boolean,
|
||||
toggleMenu: () => void,
|
||||
allArticles: () => void,
|
||||
allArticles: (init?: boolean) => void,
|
||||
selectSourceGroup: (group: SourceGroup, menuKey: string) => void,
|
||||
selectSource: (source: RSSSource) => void,
|
||||
groupContextMenu: (sids: number[], event: React.MouseEvent) => void,
|
||||
@ -43,7 +43,7 @@ export class Menu extends React.Component<MenuProps> {
|
||||
ariaLabel: this.countOverflow(Object.values(this.props.sources).map(s => s.unreadCount).reduce((a, b) => a + b, 0)),
|
||||
key: ALL,
|
||||
icon: "TextDocument",
|
||||
onClick: this.props.allArticles,
|
||||
onClick: () => this.props.allArticles(this.props.selected !== ALL),
|
||||
url: null
|
||||
}
|
||||
]
|
||||
|
@ -36,6 +36,8 @@ class FeedbinConfigsTab extends React.Component<ServiceConfigsTabProps, FeedbinC
|
||||
{ key: 500, text: intl.get("service.fetchLimitNum", { count: 500 }) },
|
||||
{ key: 750, text: intl.get("service.fetchLimitNum", { count: 750 }) },
|
||||
{ key: 1000, text: intl.get("service.fetchLimitNum", { count: 1000 }) },
|
||||
{ key: 1500, text: intl.get("service.fetchLimitNum", { count: 1500 }) },
|
||||
{ key: Number.MAX_SAFE_INTEGER, text: intl.get("service.fetchUnlimited") },
|
||||
]
|
||||
onFetchLimitOptionChange = (_, option: IDropdownOption) => {
|
||||
this.setState({ fetchLimit: option.key as number })
|
||||
|
@ -37,6 +37,8 @@ class FeverConfigsTab extends React.Component<ServiceConfigsTabProps, FeverConfi
|
||||
{ key: 500, text: intl.get("service.fetchLimitNum", { count: 500 }) },
|
||||
{ key: 750, text: intl.get("service.fetchLimitNum", { count: 750 }) },
|
||||
{ key: 1000, text: intl.get("service.fetchLimitNum", { count: 1000 }) },
|
||||
{ key: 1500, text: intl.get("service.fetchLimitNum", { count: 1500 }) },
|
||||
{ key: Number.MAX_SAFE_INTEGER, text: intl.get("service.fetchUnlimited") },
|
||||
]
|
||||
onFetchLimitOptionChange = (_, option: IDropdownOption) => {
|
||||
this.setState({ fetchLimit: option.key as number })
|
||||
|
@ -33,7 +33,10 @@ const mapDispatchToProps = (dispatch: AppDispatch) => {
|
||||
offsetItem: (offset: number) => dispatch(showOffsetItem(offset)),
|
||||
toggleHasRead: (item: RSSItem) => dispatch(item.hasRead ? markUnread(item) : markRead(item)),
|
||||
toggleStarred: (item: RSSItem) => dispatch(toggleStarred(item)),
|
||||
toggleHidden: (item: RSSItem) => dispatch(toggleHidden(item)),
|
||||
toggleHidden: (item: RSSItem) => {
|
||||
if (!item.hidden) dispatch(dismissItem())
|
||||
dispatch(toggleHidden(item))
|
||||
},
|
||||
textMenu: (position: [number, number], text: string, url: string) => dispatch(openTextMenu(position, text, url)),
|
||||
imageMenu: (position: [number, number]) => dispatch(openImageMenu(position)),
|
||||
dismissContextMenu: () => dispatch(closeContextMenu())
|
||||
|
@ -31,8 +31,8 @@ const mapStateToProps = createSelector(
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
toggleMenu: () => dispatch(toggleMenu()),
|
||||
allArticles: () => {
|
||||
dispatch(selectAllArticles()),
|
||||
allArticles: (init = false) => {
|
||||
dispatch(selectAllArticles(init)),
|
||||
dispatch(initFeeds())
|
||||
},
|
||||
selectSourceGroup: (group: SourceGroup, menuKey: string) => {
|
||||
|
@ -9,11 +9,7 @@ export default function performUpdate(store: Store<SchemaTypes>) {
|
||||
|
||||
if (useNeDB === undefined && version !== null) {
|
||||
const revs = version.split(".").map(s => parseInt(s))
|
||||
if ((revs[0] === 0 && revs[1] < 8) || !app.isPackaged) {
|
||||
store.set("useNeDB", true)
|
||||
} else {
|
||||
store.set("useNeDB", false)
|
||||
}
|
||||
store.set("useNeDB", (revs[0] === 0 && revs[1] < 8) || !app.isPackaged)
|
||||
}
|
||||
if (version != currentVersion) {
|
||||
store.set("version", currentVersion)
|
||||
|
@ -25,6 +25,7 @@ export const enum ViewType {
|
||||
export const enum ViewConfigs {
|
||||
ShowCover = 1 << 0,
|
||||
ShowSnippet = 1 << 1,
|
||||
FadeRead = 1 << 2,
|
||||
}
|
||||
|
||||
export const enum ThemeSettings {
|
||||
|
@ -91,7 +91,8 @@
|
||||
"copyImageURL": "Copy image link",
|
||||
"caseSensitive": "Case sensitive",
|
||||
"showCover": "Show cover",
|
||||
"showSnippet": "Show snippet"
|
||||
"showSnippet": "Show snippet",
|
||||
"fadeRead": "Fade read articles"
|
||||
},
|
||||
"searchEngine": {
|
||||
"name": "Search engine",
|
||||
@ -198,7 +199,8 @@
|
||||
"fetchLimitNum": "{count} latest articles",
|
||||
"importGroups": "Import groups",
|
||||
"failure": "Cannot connect to service",
|
||||
"failureHint": "Please check the service configuration or network status."
|
||||
"failureHint": "Please check the service configuration or network status.",
|
||||
"fetchUnlimited": "Unlimited (not recommended)"
|
||||
},
|
||||
"app": {
|
||||
"cleanup": "Clean up",
|
||||
|
@ -91,7 +91,8 @@
|
||||
"copyImageURL": "复制图像链接",
|
||||
"caseSensitive": "区分大小写",
|
||||
"showCover": "显示封面",
|
||||
"showSnippet": "显示摘要"
|
||||
"showSnippet": "显示摘要",
|
||||
"fadeRead": "淡化已读文章"
|
||||
},
|
||||
"searchEngine": {
|
||||
"name": "搜索引擎",
|
||||
@ -196,7 +197,8 @@
|
||||
"fetchLimitNum": "最近 {count} 篇文章",
|
||||
"importGroups": "导入分组",
|
||||
"failure": "连接到服务时出错",
|
||||
"failureHint": "请检查服务配置或网络连接"
|
||||
"failureHint": "请检查服务配置或网络连接",
|
||||
"fetchUnlimited": "无限制(不建议)"
|
||||
},
|
||||
"app": {
|
||||
"cleanup": "清理",
|
||||
|
@ -136,6 +136,7 @@ export interface MenuActionTypes {
|
||||
|
||||
export const TOGGLE_SETTINGS = "TOGGLE_SETTINGS"
|
||||
export const SAVE_SETTINGS = "SAVE_SETTINGS"
|
||||
export const FREE_MEMORY = "FREE_MEMORY"
|
||||
|
||||
interface ToggleSettingsAction {
|
||||
type: typeof TOGGLE_SETTINGS
|
||||
@ -145,7 +146,11 @@ interface ToggleSettingsAction {
|
||||
interface SaveSettingsAction {
|
||||
type: typeof SAVE_SETTINGS
|
||||
}
|
||||
export type SettingsActionTypes = ToggleSettingsAction | SaveSettingsAction
|
||||
interface FreeMemoryAction {
|
||||
type: typeof FREE_MEMORY
|
||||
iids: Set<number>
|
||||
}
|
||||
export type SettingsActionTypes = ToggleSettingsAction | SaveSettingsAction | FreeMemoryAction
|
||||
|
||||
export function closeContextMenu(): AppThunk {
|
||||
return (dispatch, getState) => {
|
||||
@ -205,15 +210,15 @@ export const toggleSettings = (open = true, sids = new Array<number>()) => ({
|
||||
sids: sids,
|
||||
})
|
||||
|
||||
export function exitSettings(): AppThunk {
|
||||
return (dispatch, getState) => {
|
||||
export function exitSettings(): AppThunk<Promise<void>> {
|
||||
return async (dispatch, getState) => {
|
||||
if (!getState().app.settings.saving) {
|
||||
if (getState().app.settings.changed) {
|
||||
dispatch(saveSettings())
|
||||
dispatch(selectAllArticles(true))
|
||||
dispatch(initFeeds(true)).then(() =>
|
||||
dispatch(toggleSettings(false))
|
||||
)
|
||||
await dispatch(initFeeds(true))
|
||||
dispatch(toggleSettings(false))
|
||||
freeMemory()
|
||||
} else {
|
||||
dispatch(toggleSettings(false))
|
||||
}
|
||||
@ -221,6 +226,19 @@ export function exitSettings(): AppThunk {
|
||||
}
|
||||
}
|
||||
|
||||
function freeMemory(): AppThunk {
|
||||
return (dispatch, getState) => {
|
||||
const iids = new Set<number>()
|
||||
for (let feed of Object.values(getState().feeds)) {
|
||||
if (feed.loaded) feed.iids.forEach(iids.add, iids)
|
||||
}
|
||||
dispatch({
|
||||
type: FREE_MEMORY,
|
||||
iids: iids
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let fetchTimeout: NodeJS.Timeout
|
||||
export function setupAutoFetch(): AppThunk {
|
||||
return (dispatch, getState) => {
|
||||
|
@ -96,13 +96,13 @@ export class RSSFeed {
|
||||
this.filter = filter === null ? new FeedFilter() : filter
|
||||
}
|
||||
|
||||
static async loadFeed(feed: RSSFeed, init = false): Promise<RSSItem[]> {
|
||||
static async loadFeed(feed: RSSFeed, skip = 0): Promise<RSSItem[]> {
|
||||
const predicates = FeedFilter.toPredicates(feed.filter)
|
||||
predicates.push(db.items.source.in(feed.sids))
|
||||
return (await db.itemsDB.select().from(db.items).where(
|
||||
lf.op.and.apply(null, predicates)
|
||||
).orderBy(db.items.date, lf.Order.DESC)
|
||||
.skip(init ? 0 : feed.iids.length)
|
||||
.skip(skip)
|
||||
.limit(LOAD_QUANTITY)
|
||||
.exec()) as RSSItem[]
|
||||
}
|
||||
@ -175,7 +175,7 @@ export function initFeeds(force = false): AppThunk<Promise<void>> {
|
||||
let promises = new Array<Promise<void>>()
|
||||
for (let feed of Object.values(getState().feeds)) {
|
||||
if (!feed.loaded || force) {
|
||||
let p = RSSFeed.loadFeed(feed, force).then(items => {
|
||||
let p = RSSFeed.loadFeed(feed).then(items => {
|
||||
dispatch(initFeedSuccess(feed, items))
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
@ -217,10 +217,12 @@ export function loadMoreFailure(feed: RSSFeed, err): FeedActionTypes {
|
||||
}
|
||||
|
||||
export function loadMore(feed: RSSFeed): AppThunk<Promise<void>> {
|
||||
return (dispatch) => {
|
||||
return (dispatch, getState) => {
|
||||
if (feed.loaded && !feed.loading && !feed.allLoaded) {
|
||||
dispatch(loadMoreRequest(feed))
|
||||
return RSSFeed.loadFeed(feed).then(items => {
|
||||
const state = getState()
|
||||
const skipNum = feed.iids.filter(i => FeedFilter.testItem(feed.filter, state.items[i])).length
|
||||
return RSSFeed.loadFeed(feed, skipNum).then(items => {
|
||||
dispatch(loadMoreSuccess(feed, items))
|
||||
}).catch(e => {
|
||||
console.log(e)
|
||||
@ -331,9 +333,6 @@ export function feedReducer(
|
||||
}
|
||||
default: return state
|
||||
}
|
||||
case MARK_READ:
|
||||
case MARK_UNREAD:
|
||||
case TOGGLE_STARRED:
|
||||
case TOGGLE_HIDDEN: {
|
||||
let nextItem = applyItemReduction(action.item, action.type)
|
||||
let filteredFeeds = Object.values(state).filter(feed => feed.loaded && !FeedFilter.testItem(feed.filter, nextItem))
|
||||
|
@ -5,7 +5,7 @@ import { domParser, htmlDecode, ActionStatus, AppThunk, platformCtrl } from "../
|
||||
import { RSSSource, updateSource, updateUnreadCounts } from "./source"
|
||||
import { FeedActionTypes, INIT_FEED, LOAD_MORE, FilterType, initFeeds } from "./feed"
|
||||
import Parser from "@yang991178/rss-parser"
|
||||
import { pushNotification, setupAutoFetch } from "./app"
|
||||
import { pushNotification, setupAutoFetch, SettingsActionTypes, FREE_MEMORY } from "./app"
|
||||
import { getServiceHooks, syncWithService, ServiceActionTypes, SYNC_LOCAL_ITEMS } from "./service"
|
||||
|
||||
export class RSSItem {
|
||||
@ -281,9 +281,6 @@ export function markAllRead(sids: number[] = null, date: Date = null, before = t
|
||||
sids: sids
|
||||
})
|
||||
}
|
||||
if (!(state.page.filter.type & FilterType.ShowRead)) {
|
||||
dispatch(initFeeds(true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -380,7 +377,7 @@ export function applyItemReduction(item: RSSItem, type: string) {
|
||||
|
||||
export function itemReducer(
|
||||
state: ItemState = {},
|
||||
action: ItemActionTypes | FeedActionTypes | ServiceActionTypes
|
||||
action: ItemActionTypes | FeedActionTypes | ServiceActionTypes | SettingsActionTypes
|
||||
): ItemState {
|
||||
switch (action.type) {
|
||||
case FETCH_ITEMS:
|
||||
@ -446,6 +443,13 @@ export function itemReducer(
|
||||
}
|
||||
return nextState
|
||||
}
|
||||
case FREE_MEMORY: {
|
||||
const nextState: ItemState = {}
|
||||
for (let item of Object.values(state)) {
|
||||
if (action.iids.has(item._id)) nextState[item._id] = item
|
||||
}
|
||||
return nextState
|
||||
}
|
||||
default: return state
|
||||
}
|
||||
}
|
@ -166,9 +166,6 @@ function syncItems(hook: ServiceHooks["syncItems"]): AppThunk<Promise<void>> {
|
||||
await db.itemsDB.createTransaction().exec(updates)
|
||||
await dispatch(updateUnreadCounts())
|
||||
dispatch(syncLocalItems(unreadCopy, starredCopy))
|
||||
if (!(state.page.filter.type & FilterType.ShowRead) || !(state.page.filter.type & FilterType.ShowNotStarred)) {
|
||||
dispatch(initFeeds(true))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -107,12 +107,16 @@ export const feedbinServiceHooks: ServiceHooks = {
|
||||
let min = Number.MAX_SAFE_INTEGER
|
||||
let lastFetched: any[]
|
||||
do {
|
||||
const response = await fetchAPI(configs, "entries.json?mode=extended&per_page=125&page=" + page)
|
||||
if (response.status !== 200) throw APIError()
|
||||
lastFetched = await response.json()
|
||||
items.push(...lastFetched.filter(i => i.id > configs.lastId && i.id < min))
|
||||
min = lastFetched.reduce((m, n) => Math.min(m, n.id), min)
|
||||
page += 1
|
||||
try {
|
||||
const response = await fetchAPI(configs, "entries.json?mode=extended&per_page=125&page=" + page)
|
||||
if (response.status !== 200) throw APIError()
|
||||
lastFetched = await response.json()
|
||||
items.push(...lastFetched.filter(i => i.id > configs.lastId && i.id < min))
|
||||
min = lastFetched.reduce((m, n) => Math.min(m, n.id), min)
|
||||
page += 1
|
||||
} catch {
|
||||
break
|
||||
}
|
||||
} while (
|
||||
min > configs.lastId &&
|
||||
lastFetched && lastFetched.length >= 125 &&
|
||||
@ -133,7 +137,9 @@ export const feedbinServiceHooks: ServiceHooks = {
|
||||
if (unreadResponse.status !== 200 || starredResponse.status !== 200) throw APIError()
|
||||
const unread: Set<number> = new Set(await unreadResponse.json())
|
||||
const starred: Set<number> = new Set(await starredResponse.json())
|
||||
const parsedItems = items.map(i => {
|
||||
const parsedItems = new Array<RSSItem>()
|
||||
items.forEach(i => {
|
||||
if (i.content === null) return
|
||||
const source = fidMap.get(String(i.feed_id))
|
||||
const dom = domParser.parseFromString(i.content, "text/html")
|
||||
const item = {
|
||||
@ -166,7 +172,7 @@ export const feedbinServiceHooks: ServiceHooks = {
|
||||
markItems(configs, "unread", item.hasRead ? "DELETE" : "POST", [i.id])
|
||||
if (starred.has(i.id) !== Boolean(item.starred))
|
||||
markItems(configs, "starred", item.starred ? "POST" : "DELETE", [i.id])
|
||||
return item
|
||||
parsedItems.push(item)
|
||||
})
|
||||
return [parsedItems, configs]
|
||||
} else {
|
||||
|
@ -181,8 +181,8 @@ export function initSources(): AppThunk<Promise<void>> {
|
||||
source.unreadCount = 0
|
||||
state[source.sid] = source
|
||||
}
|
||||
await unreadCount(sources)
|
||||
dispatch(initSourcesSuccess(sources))
|
||||
await unreadCount(state)
|
||||
dispatch(initSourcesSuccess(state))
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user