From 143a29502464550dc70d257f9547112e6b5be754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B5=A9=E8=BF=9C?= Date: Sat, 6 Jun 2020 09:33:59 +0800 Subject: [PATCH] split source groups into model --- dist/styles.css | 8 +- src/components/menu.tsx | 2 +- src/components/settings/groups.tsx | 12 +- src/containers/menu-container.tsx | 5 +- src/containers/settings/groups-container.tsx | 4 +- src/containers/settings/sources-container.tsx | 2 +- src/scripts/models/app.ts | 3 +- src/scripts/models/group.ts | 271 ++++++++++++++++ src/scripts/models/page.ts | 291 +----------------- src/scripts/models/source.ts | 9 +- src/scripts/reducer.ts | 2 + 11 files changed, 303 insertions(+), 306 deletions(-) create mode 100644 src/scripts/models/group.ts diff --git a/dist/styles.css b/dist/styles.css index e90d109..d491afd 100644 --- a/dist/styles.css +++ b/dist/styles.css @@ -1,6 +1,6 @@ html, body { background-color: #faf9f8; - font-family: "Source Han Sans SC Regular", "Microsoft YaHei", sans-serif; + font-family: "Segoe UI Regular", "Source Han Sans SC Regular", "Microsoft YaHei", sans-serif; height: 100%; overflow: hidden; margin: 0; @@ -236,6 +236,10 @@ img.favicon { overflow-y: auto; margin-bottom: 16px; } +.settings-hint { + font-size: 12px; + color: #605e5c; +} .main { height: calc(100% - 32px); @@ -409,7 +413,7 @@ img.favicon { .card h3.title { font-size: 16px; line-height: 22px; - font-weight: 700; + font-weight: 600; margin: 10px 12px; position: relative; -webkit-line-clamp: 3; diff --git a/src/components/menu.tsx b/src/components/menu.tsx index 8de8028..be6e08d 100644 --- a/src/components/menu.tsx +++ b/src/components/menu.tsx @@ -1,7 +1,7 @@ import * as React from "react" import { Icon } from "@fluentui/react/lib/Icon" import { Nav, INavLink, INavLinkGroup } from "office-ui-fabric-react/lib/Nav" -import { SourceGroup } from "../scripts/models/page" +import { SourceGroup } from "../scripts/models/group" import { SourceState, RSSSource } from "../scripts/models/source" import { ALL } from "../scripts/models/feed" import { AnimationClassNames } from "@fluentui/react" diff --git a/src/components/settings/groups.tsx b/src/components/settings/groups.tsx index 629f0ef..9fba0b9 100644 --- a/src/components/settings/groups.tsx +++ b/src/components/settings/groups.tsx @@ -1,5 +1,5 @@ import * as React from "react" -import { SourceGroup } from "../../scripts/models/page" +import { SourceGroup } from "../../scripts/models/group" import { SourceState, RSSSource } from "../../scripts/models/source" import { IColumn, Selection, SelectionMode, DetailsList, Label, Stack, TextField, PrimaryButton, DefaultButton, Dropdown, IDropdownOption, CommandBarButton, MarqueeSelection, IDragDropEvents, IDragDropContext } from "@fluentui/react" @@ -261,7 +261,7 @@ class GroupsTab extends React.Component { iconProps={{iconName: "RemoveFromShoppingList", style: {color: "#d13438"}}} />} - + this.props.sources[sid])} @@ -307,8 +307,8 @@ class GroupsTab extends React.Component { selection={this.groupSelection} selectionMode={SelectionMode.single} /> - {this.state.selectedGroup && ( - this.state.selectedGroup.isMultiple + {this.state.selectedGroup + ? ( this.state.selectedGroup.isMultiple ?<> @@ -353,7 +353,9 @@ class GroupsTab extends React.Component { - )} + ) + :

双击分组以修改订阅源,可通过拖拽排序

+ } : null} ) diff --git a/src/containers/menu-container.tsx b/src/containers/menu-container.tsx index ddefc54..bf2ffe0 100644 --- a/src/containers/menu-container.tsx +++ b/src/containers/menu-container.tsx @@ -3,14 +3,15 @@ import { createSelector } from "reselect" import { RootState } from "../scripts/reducer" import { Menu } from "../components/menu" import { toggleMenu } from "../scripts/models/app" -import { selectAllArticles, selectSources, SourceGroup } from "../scripts/models/page" +import { SourceGroup } from "../scripts/models/group" +import { selectAllArticles, selectSources } from "../scripts/models/page" import { initFeeds } from "../scripts/models/feed" import { RSSSource } from "../scripts/models/source" const getStatus = (state: RootState) => state.app.menu && state.app.sourceInit const getKey = (state: RootState) => state.app.menuKey const getSources = (state: RootState) => state.sources -const getGroups = (state: RootState) => state.page.sourceGroups +const getGroups = (state: RootState) => state.groups const mapStateToProps = createSelector( [getStatus, getKey, getSources, getGroups], diff --git a/src/containers/settings/groups-container.tsx b/src/containers/settings/groups-container.tsx index 90ffcbe..d7ed689 100644 --- a/src/containers/settings/groups-container.tsx +++ b/src/containers/settings/groups-container.tsx @@ -4,10 +4,10 @@ import { createSelector } from "reselect" import { RootState } from "../../scripts/reducer" import GroupsTab from "../../components/settings/groups" import { createSourceGroup, SourceGroup, updateSourceGroup, addSourceToGroup, - deleteSourceGroup, removeSourceFromGroup, reorderSourceGroups } from "../../scripts/models/page" + deleteSourceGroup, removeSourceFromGroup, reorderSourceGroups } from "../../scripts/models/group" const getSources = (state: RootState) => state.sources -const getGroups = (state: RootState) => state.page.sourceGroups +const getGroups = (state: RootState) => state.groups const mapStateToProps = createSelector( [getSources, getGroups], diff --git a/src/containers/settings/sources-container.tsx b/src/containers/settings/sources-container.tsx index 46f6b79..a6e1ad3 100644 --- a/src/containers/settings/sources-container.tsx +++ b/src/containers/settings/sources-container.tsx @@ -4,7 +4,7 @@ import { createSelector } from "reselect" import { RootState } from "../../scripts/reducer" import SourcesTab from "../../components/settings/sources" import { addSource, RSSSource, updateSource, deleteSource } from "../../scripts/models/source" -import { importOPML } from "../../scripts/models/page" +import { importOPML } from "../../scripts/models/group" const getSources = (state: RootState) => state.sources diff --git a/src/scripts/models/app.ts b/src/scripts/models/app.ts index 61ee9a6..bfc7490 100644 --- a/src/scripts/models/app.ts +++ b/src/scripts/models/app.ts @@ -2,7 +2,8 @@ import { RSSSource, INIT_SOURCES, SourceActionTypes, ADD_SOURCE, UPDATE_SOURCE, import { RSSItem, ItemActionTypes, FETCH_ITEMS } from "./item" import { ActionStatus, AppThunk, getWindowBreakpoint } from "../utils" import { INIT_FEEDS, FeedActionTypes, ALL, initFeeds } from "./feed" -import { PageActionTypes, SELECT_PAGE, PageType, selectAllArticles, SourceGroupActionTypes, UPDATE_SOURCE_GROUP, ADD_SOURCE_TO_GROUP, DELETE_SOURCE_GROUP, REMOVE_SOURCE_FROM_GROUP } from "./page" +import { SourceGroupActionTypes, UPDATE_SOURCE_GROUP, ADD_SOURCE_TO_GROUP, DELETE_SOURCE_GROUP, REMOVE_SOURCE_FROM_GROUP } from "./group" +import { PageActionTypes, SELECT_PAGE, PageType, selectAllArticles } from "./page" export enum ContextMenuType { Hidden, Item diff --git a/src/scripts/models/group.ts b/src/scripts/models/group.ts new file mode 100644 index 0000000..ced4acf --- /dev/null +++ b/src/scripts/models/group.ts @@ -0,0 +1,271 @@ +import fs = require("fs") +import { SourceActionTypes, ADD_SOURCE, DELETE_SOURCE, addSource } from "./source" + +import { ActionStatus, AppThunk, domParser, AppDispatch, getWindowBreakpoint } from "../utils" +import { saveSettings } from "./app" + +const GROUPS_STORE_KEY = "sourceGroups" + +export class SourceGroup { + isMultiple: boolean + sids: number[] + name?: string + index?: number // available only from groups tab container + + constructor(sids: number[], name: string = null) { + name = (name && name.trim()) || "订阅源组" + if (sids.length == 1) { + this.isMultiple = false + } else { + this.isMultiple = true + this.name = name + } + this.sids = sids + } + + static save(groups: SourceGroup[]) { + localStorage.setItem(GROUPS_STORE_KEY, JSON.stringify(groups)) + } + + static load(): SourceGroup[] { + let stored = localStorage.getItem(GROUPS_STORE_KEY) + return stored ? JSON.parse(stored) : [] + } +} + +export const CREATE_SOURCE_GROUP = "CREATE_SOURCE_GROUP" +export const ADD_SOURCE_TO_GROUP = "ADD_SOURCE_TO_GROUP" +export const REMOVE_SOURCE_FROM_GROUP = "REMOVE_SOURCE_FROM_GROUP" +export const UPDATE_SOURCE_GROUP = "UPDATE_SOURCE_GROUP" +export const REORDER_SOURCE_GROUPS = "REORDER_SOURCE_GROUPS" +export const DELETE_SOURCE_GROUP = "DELETE_SOURCE_GROUP" + +interface CreateSourceGroupAction { + type: typeof CREATE_SOURCE_GROUP, + group: SourceGroup +} + +interface AddSourceToGroupAction { + type: typeof ADD_SOURCE_TO_GROUP, + groupIndex: number, + sid: number +} + +interface RemoveSourceFromGroupAction { + type: typeof REMOVE_SOURCE_FROM_GROUP, + groupIndex: number, + sids: number[] +} + +interface UpdateSourceGroupAction { + type: typeof UPDATE_SOURCE_GROUP, + groupIndex: number, + group: SourceGroup +} + +interface ReorderSourceGroupsAction { + type: typeof REORDER_SOURCE_GROUPS, + groups: SourceGroup[] +} + +interface DeleteSourceGroupAction { + type: typeof DELETE_SOURCE_GROUP, + groupIndex: number +} + +export type SourceGroupActionTypes = CreateSourceGroupAction | AddSourceToGroupAction + | RemoveSourceFromGroupAction | UpdateSourceGroupAction | ReorderSourceGroupsAction + | DeleteSourceGroupAction + +export function createSourceGroupDone(group: SourceGroup): SourceGroupActionTypes { + return { + type: CREATE_SOURCE_GROUP, + group: group + } +} + +export function createSourceGroup(name: string): AppThunk { + return (dispatch, getState) => { + let group = new SourceGroup([], name) + dispatch(createSourceGroupDone(group)) + let groups = getState().groups + SourceGroup.save(groups) + return groups.length - 1 + } +} + +function addSourceToGroupDone(groupIndex: number, sid: number): SourceGroupActionTypes { + return { + type: ADD_SOURCE_TO_GROUP, + groupIndex: groupIndex, + sid: sid + } +} + +export function addSourceToGroup(groupIndex: number, sid: number): AppThunk { + return (dispatch, getState) => { + dispatch(addSourceToGroupDone(groupIndex, sid)) + SourceGroup.save(getState().groups) + } +} + +function removeSourceFromGroupDone(groupIndex: number, sids: number[]): SourceGroupActionTypes { + return { + type: REMOVE_SOURCE_FROM_GROUP, + groupIndex: groupIndex, + sids: sids + } +} + +export function removeSourceFromGroup(groupIndex: number, sids: number[]): AppThunk { + return (dispatch, getState) => { + dispatch(removeSourceFromGroupDone(groupIndex, sids)) + SourceGroup.save(getState().groups) + } +} + +function deleteSourceGroupDone(groupIndex: number): SourceGroupActionTypes { + return { + type: DELETE_SOURCE_GROUP, + groupIndex: groupIndex + } +} + +export function deleteSourceGroup(groupIndex: number): AppThunk { + return (dispatch, getState) => { + dispatch(deleteSourceGroupDone(groupIndex)) + SourceGroup.save(getState().groups) + } +} + +function updateSourceGroupDone(group: SourceGroup): SourceGroupActionTypes { + return { + type: UPDATE_SOURCE_GROUP, + groupIndex: group.index, + group: group + } +} + +export function updateSourceGroup(group: SourceGroup): AppThunk { + return (dispatch, getState) => { + dispatch(updateSourceGroupDone(group)) + SourceGroup.save(getState().groups) + } +} + +function reorderSourceGroupsDone(groups: SourceGroup[]): SourceGroupActionTypes { + return { + type: REORDER_SOURCE_GROUPS, + groups: groups + } +} + +export function reorderSourceGroups(groups: SourceGroup[]): AppThunk { + return (dispatch, getState) => { + dispatch(reorderSourceGroupsDone(groups)) + SourceGroup.save(getState().groups) + } +} + +async function outlineToSource(dispatch: AppDispatch, outline: Element): Promise { + let url = outline.getAttribute("xmlUrl") + let name = outline.getAttribute("text") || outline.getAttribute("name") + if (url) { + try { + return await dispatch(addSource(url.trim(), name, true)) + } catch (e) { + return null + } + } else { + return null + } +} + +export function importOPML(path: string): AppThunk { + return async (dispatch) => { + fs.readFile(path, "utf-8", async (err, data) => { + if (err) { + console.log(err) + } else { + dispatch(saveSettings()) + let successes: number = 0, failures: number = 0 + let doc = domParser.parseFromString(data, "text/xml").getElementsByTagName("body") + if (doc.length == 0) { + dispatch(saveSettings()) + return + } + for (let el of doc[0].children) { + if (el.getAttribute("type") === "rss") { + let sid = await outlineToSource(dispatch, el) + if (sid === null) failures += 1 + else successes += 1 + } else if (el.hasAttribute("text") || el.hasAttribute("title")) { + let groupName = el.getAttribute("text") || el.getAttribute("title") + let gid = dispatch(createSourceGroup(groupName)) + for (let child of el.children) { + let sid = await outlineToSource(dispatch, child) + if (sid === null) { + failures += 1 + } else { + successes += 1 + dispatch(addSourceToGroup(gid, sid)) + } + } + } + } + console.log(failures, successes) + dispatch(saveSettings()) + } + }) + } +} + +export type GroupState = SourceGroup[] + +export function groupReducer( + state = SourceGroup.load(), + action: SourceActionTypes | SourceGroupActionTypes +): GroupState { + switch(action.type) { + case ADD_SOURCE: + switch (action.status) { + case ActionStatus.Success: return [ + ...state, + new SourceGroup([action.source.sid]) + ] + default: return state + } + case DELETE_SOURCE: return [ + ...state.map(group => ({ + ...group, + sids: group.sids.filter(sid => sid != action.source.sid) + })).filter(g => g.isMultiple || g.sids.length == 1) + ] + case CREATE_SOURCE_GROUP: return [ ...state, action.group ] + case ADD_SOURCE_TO_GROUP: return state.map((g, i) => i == action.groupIndex ? ({ + ...g, + sids: [ ...g.sids, action.sid ] + }) : g).filter(g => g.isMultiple || !g.sids.includes(action.sid)) + case REMOVE_SOURCE_FROM_GROUP: return [ + ...state.slice(0, action.groupIndex), + { + ...state[action.groupIndex], + sids: state[action.groupIndex].sids.filter(sid => !action.sids.includes(sid)) + }, + ...action.sids.map(sid => new SourceGroup([sid])), + ...state.slice(action.groupIndex + 1) + ] + case UPDATE_SOURCE_GROUP: return [ + ...state.slice(0, action.groupIndex), + action.group, + ...state.slice(action.groupIndex + 1) + ] + case REORDER_SOURCE_GROUPS: return action.groups + case DELETE_SOURCE_GROUP: return [ + ...state.slice(0, action.groupIndex), + ...state[action.groupIndex].sids.map(sid => new SourceGroup([sid])), + ...state.slice(action.groupIndex + 1) + ] + default: return state + } +} \ No newline at end of file diff --git a/src/scripts/models/page.ts b/src/scripts/models/page.ts index 176c22d..ea49ff3 100644 --- a/src/scripts/models/page.ts +++ b/src/scripts/models/page.ts @@ -1,37 +1,5 @@ -import fs = require("fs") -import { SourceActionTypes, ADD_SOURCE, DELETE_SOURCE, addSource } from "./source" -import { ALL, SOURCE } from "./feed" -import { ActionStatus, AppThunk, domParser, AppDispatch, getWindowBreakpoint } from "../utils" -import { saveSettings } from "./app" - -const GROUPS_STORE_KEY = "sourceGroups" - -export class SourceGroup { - isMultiple: boolean - sids: number[] - name?: string - index?: number // available only from groups tab container - - constructor(sids: number[], name: string = null) { - name = (name && name.trim()) || "订阅源组" - if (sids.length == 1) { - this.isMultiple = false - } else { - this.isMultiple = true - this.name = name - } - this.sids = sids - } - - static save(groups: SourceGroup[]) { - localStorage.setItem(GROUPS_STORE_KEY, JSON.stringify(groups)) - } - - static load(): SourceGroup[] { - let stored = localStorage.getItem(GROUPS_STORE_KEY) - return stored ? JSON.parse(stored) : [] - } -} +import { ALL, SOURCE, FeedIdType } from "./feed" +import { getWindowBreakpoint } from "../utils" export const SELECT_PAGE = "SELECT_PAGE" @@ -72,223 +40,15 @@ export function selectSources(sids: number[], menuKey: string, title: string) { } } -export const CREATE_SOURCE_GROUP = "CREATE_SOURCE_GROUP" -export const ADD_SOURCE_TO_GROUP = "ADD_SOURCE_TO_GROUP" -export const REMOVE_SOURCE_FROM_GROUP = "REMOVE_SOURCE_FROM_GROUP" -export const UPDATE_SOURCE_GROUP = "UPDATE_SOURCE_GROUP" -export const REORDER_SOURCE_GROUPS = "REORDER_SOURCE_GROUPS" -export const DELETE_SOURCE_GROUP = "DELETE_SOURCE_GROUP" - -interface CreateSourceGroupAction { - type: typeof CREATE_SOURCE_GROUP, - group: SourceGroup -} - -interface AddSourceToGroupAction { - type: typeof ADD_SOURCE_TO_GROUP, - groupIndex: number, - sid: number -} - -interface RemoveSourceFromGroupAction { - type: typeof REMOVE_SOURCE_FROM_GROUP, - groupIndex: number, - sids: number[] -} - -interface UpdateSourceGroupAction { - type: typeof UPDATE_SOURCE_GROUP, - groupIndex: number, - group: SourceGroup -} - -interface ReorderSourceGroupsAction { - type: typeof REORDER_SOURCE_GROUPS, - groups: SourceGroup[] -} - -interface DeleteSourceGroupAction { - type: typeof DELETE_SOURCE_GROUP, - groupIndex: number -} - -export type SourceGroupActionTypes = CreateSourceGroupAction | AddSourceToGroupAction - | RemoveSourceFromGroupAction | UpdateSourceGroupAction | ReorderSourceGroupsAction - | DeleteSourceGroupAction - -export function createSourceGroupDone(group: SourceGroup): SourceGroupActionTypes { - return { - type: CREATE_SOURCE_GROUP, - group: group - } -} - -export function createSourceGroup(name: string): AppThunk { - return (dispatch, getState) => { - let group = new SourceGroup([], name) - dispatch(createSourceGroupDone(group)) - let groups = getState().page.sourceGroups - SourceGroup.save(groups) - return groups.length - 1 - } -} - -function addSourceToGroupDone(groupIndex: number, sid: number): SourceGroupActionTypes { - return { - type: ADD_SOURCE_TO_GROUP, - groupIndex: groupIndex, - sid: sid - } -} - -export function addSourceToGroup(groupIndex: number, sid: number): AppThunk { - return (dispatch, getState) => { - dispatch(addSourceToGroupDone(groupIndex, sid)) - SourceGroup.save(getState().page.sourceGroups) - } -} - -function removeSourceFromGroupDone(groupIndex: number, sids: number[]): SourceGroupActionTypes { - return { - type: REMOVE_SOURCE_FROM_GROUP, - groupIndex: groupIndex, - sids: sids - } -} - -export function removeSourceFromGroup(groupIndex: number, sids: number[]): AppThunk { - return (dispatch, getState) => { - dispatch(removeSourceFromGroupDone(groupIndex, sids)) - SourceGroup.save(getState().page.sourceGroups) - } -} - -function deleteSourceGroupDone(groupIndex: number): SourceGroupActionTypes { - return { - type: DELETE_SOURCE_GROUP, - groupIndex: groupIndex - } -} - -export function deleteSourceGroup(groupIndex: number): AppThunk { - return (dispatch, getState) => { - dispatch(deleteSourceGroupDone(groupIndex)) - SourceGroup.save(getState().page.sourceGroups) - } -} - -function updateSourceGroupDone(group: SourceGroup): SourceGroupActionTypes { - return { - type: UPDATE_SOURCE_GROUP, - groupIndex: group.index, - group: group - } -} - -export function updateSourceGroup(group: SourceGroup): AppThunk { - return (dispatch, getState) => { - dispatch(updateSourceGroupDone(group)) - SourceGroup.save(getState().page.sourceGroups) - } -} - -function reorderSourceGroupsDone(groups: SourceGroup[]): SourceGroupActionTypes { - return { - type: REORDER_SOURCE_GROUPS, - groups: groups - } -} - -export function reorderSourceGroups(groups: SourceGroup[]): AppThunk { - return (dispatch, getState) => { - dispatch(reorderSourceGroupsDone(groups)) - SourceGroup.save(getState().page.sourceGroups) - } -} - -async function outlineToSource(dispatch: AppDispatch, outline: Element): Promise { - let url = outline.getAttribute("xmlUrl") - let name = outline.getAttribute("text") || outline.getAttribute("name") - if (url) { - try { - return await dispatch(addSource(url.trim(), name, true)) - } catch (e) { - return null - } - } else { - return null - } -} - -export function importOPML(path: string): AppThunk { - return async (dispatch) => { - fs.readFile(path, "utf-8", async (err, data) => { - if (err) { - console.log(err) - } else { - dispatch(saveSettings()) - let successes: number = 0, failures: number = 0 - let doc = domParser.parseFromString(data, "text/xml").getElementsByTagName("body") - if (doc.length == 0) { - dispatch(saveSettings()) - return - } - for (let el of doc[0].children) { - if (el.getAttribute("type") === "rss") { - let sid = await outlineToSource(dispatch, el) - if (sid === null) failures += 1 - else successes += 1 - } else if (el.hasAttribute("text") || el.hasAttribute("title")) { - let groupName = el.getAttribute("text") || el.getAttribute("title") - let gid = dispatch(createSourceGroup(groupName)) - for (let child of el.children) { - let sid = await outlineToSource(dispatch, child) - if (sid === null) { - failures += 1 - } else { - successes += 1 - dispatch(addSourceToGroup(gid, sid)) - } - } - } - } - console.log(failures, successes) - dispatch(saveSettings()) - } - }) - } -} - export class PageState { feedId = ALL - sourceGroups = SourceGroup.load() } export function pageReducer( state = new PageState(), - action: PageActionTypes | SourceActionTypes | SourceGroupActionTypes + action: PageActionTypes ): PageState { - switch(action.type) { - case ADD_SOURCE: - switch (action.status) { - case ActionStatus.Success: return { - ...state, - sourceGroups: [ - ...state.sourceGroups, - new SourceGroup([action.source.sid]) - ] - } - default: return state - } - case DELETE_SOURCE: return { - ...state, - sourceGroups: [ - ...state.sourceGroups.map(group => ({ - ...group, - sids: group.sids.filter(sid => sid != action.source.sid) - })).filter(g => g.isMultiple || g.sids.length == 1) - ] - } + switch (action.type) { case SELECT_PAGE: switch (action.pageType) { case PageType.AllArticles: return { @@ -301,49 +61,6 @@ export function pageReducer( } default: return state } - case CREATE_SOURCE_GROUP: return { - ...state, - sourceGroups: [ ...state.sourceGroups, action.group ] - } - case ADD_SOURCE_TO_GROUP: return { - ...state, - sourceGroups: state.sourceGroups.map((g, i) => i == action.groupIndex ? ({ - ...g, - sids: [ ...g.sids, action.sid ] - }) : g).filter(g => g.isMultiple || !g.sids.includes(action.sid) ) - } - case REMOVE_SOURCE_FROM_GROUP: return { - ...state, - sourceGroups: [ - ...state.sourceGroups.slice(0, action.groupIndex), - { - ...state.sourceGroups[action.groupIndex], - sids: state.sourceGroups[action.groupIndex].sids.filter(sid => !action.sids.includes(sid)) - }, - ...action.sids.map(sid => new SourceGroup([sid])), - ...state.sourceGroups.slice(action.groupIndex + 1) - ] - } - case UPDATE_SOURCE_GROUP: return { - ...state, - sourceGroups: [ - ...state.sourceGroups.slice(0, action.groupIndex), - action.group, - ...state.sourceGroups.slice(action.groupIndex + 1) - ] - } - case REORDER_SOURCE_GROUPS: return { - ...state, - sourceGroups: action.groups - } - case DELETE_SOURCE_GROUP: return { - ...state, - sourceGroups: [ - ...state.sourceGroups.slice(0, action.groupIndex), - ...state.sourceGroups[action.groupIndex].sids.map(sid => new SourceGroup([sid])), - ...state.sourceGroups.slice(action.groupIndex + 1) - ] - } default: return state } } \ No newline at end of file diff --git a/src/scripts/models/source.ts b/src/scripts/models/source.ts index bcbbe61..fbf4921 100644 --- a/src/scripts/models/source.ts +++ b/src/scripts/models/source.ts @@ -1,9 +1,8 @@ import Parser = require("@yang991178/rss-parser") import * as db from "../db" import { rssParser, faviconPromise, ActionStatus, AppThunk } from "../utils" -import { RSSItem, fetchItemsSuccess, insertItems } from "./item" -import { SourceGroup } from "./page" -import { initFeeds } from "./feed" +import { RSSItem, insertItems } from "./item" +import { SourceGroup } from "./group" import { saveSettings } from "./app" export class RSSSource { @@ -199,7 +198,7 @@ export function addSource(url: string, name: string = null, batch = false): AppT .then(items => insertItems(items)) .then(items => { //dispatch(fetchItemsSuccess(items)) - SourceGroup.save(getState().page.sourceGroups) + SourceGroup.save(getState().groups) resolve(source.sid) }) } @@ -254,7 +253,7 @@ export function deleteSource(source: RSSSource): AppThunk { dispatch(saveSettings()) } else { dispatch(deleteSourceDone(source)) - SourceGroup.save(getState().page.sourceGroups) + SourceGroup.save(getState().groups) dispatch(saveSettings()) } }) diff --git a/src/scripts/reducer.ts b/src/scripts/reducer.ts index 263f307..57763c9 100644 --- a/src/scripts/reducer.ts +++ b/src/scripts/reducer.ts @@ -4,12 +4,14 @@ import { sourceReducer } from "./models/source" import { itemReducer } from "./models/item" import { feedReducer } from "./models/feed" import { appReducer } from "./models/app" +import { groupReducer } from "./models/group" import { pageReducer } from "./models/page" export const rootReducer = combineReducers({ sources: sourceReducer, items: itemReducer, feeds: feedReducer, + groups: groupReducer, page: pageReducer, app: appReducer })