commit
e6c6fdbb2d
|
@ -1,10 +0,0 @@
|
|||
const { makeUniversalApp } = require('@electron/universal');
|
||||
|
||||
const path = '/Users/bruce/Documents/repos/fluent-reader/bin/'
|
||||
|
||||
makeUniversalApp({
|
||||
x64AppPath: path + '/darwin/x64/mas/Fluent Reader.app',
|
||||
arm64AppPath: path + '/darwin/arm64/mas/Fluent Reader.app',
|
||||
outAppPath: path + '/Fluent Reader.app',
|
||||
force: true
|
||||
});
|
|
@ -1,4 +1,7 @@
|
|||
#TODO: add "<key>ElectronTeamID</key><string>EM8VE646TZ</string>" to Info.plist
|
||||
# Build the MAS app
|
||||
CSC_IDENTITY_AUTO_DISCOVERY=false npx electron-builder -c electron-builder-mas.yml --mac mas:universal
|
||||
# Add ElectronTeamID to Info.plist
|
||||
sed -i '' -e 's/<\/dict>/<key>ElectronTeamID<\/key><string>EM8VE646TZ<\/string><\/dict>/g' "bin/darwin/universal/mas-universal/Fluent Reader.app/Contents/Info.plist"
|
||||
|
||||
printf "......................\nresignAndPackage start\n\n"
|
||||
|
||||
|
@ -7,11 +10,11 @@ APP="Fluent Reader"
|
|||
# Your Certificate name.
|
||||
CERT="Jieyu Yan (EM8VE646TZ)"
|
||||
# The path of your app to sign.
|
||||
APP_PATH="/Users/bruce/Documents/repos/fluent-reader/bin/$APP.app"
|
||||
APP_PATH="bin/darwin/universal/mas-universal/Fluent Reader.app"
|
||||
# The path to the location you want to put the signed package.
|
||||
RESULT_PATH="/Users/bruce/Documents/repos/fluent-reader/bin/$APP-mac_store.pkg"
|
||||
RESULT_PATH="bin/$APP-mac_store.pkg"
|
||||
# The name of certificates you requested.
|
||||
APP_KEY="3rd Party Mac Developer Application: $CERT"
|
||||
APP_KEY="Apple Distribution: $CERT"
|
||||
INSTALLER_KEY="3rd Party Mac Developer Installer: $CERT"
|
||||
# The path of your plist files.
|
||||
PARENT_PLIST="build/entitlements.mas.plist"
|
||||
|
|
|
@ -207,7 +207,7 @@ body.darwin .btn-group .seperator {
|
|||
height: var(--navHeight);
|
||||
line-height: var(--navHeight);
|
||||
}
|
||||
body.darwin #root > nav .btn-group .btn:first-of-type {
|
||||
body.darwin.not-fullscreen #root > nav .btn-group .btn:first-of-type {
|
||||
margin-left: 72px;
|
||||
}
|
||||
#root > nav .btn-group .btn.system {
|
||||
|
|
|
@ -222,7 +222,7 @@ img.favicon.dropdown {
|
|||
height: calc(var(--navHeight) - 4px);
|
||||
box-shadow: 0 1.6px 3.6px 0 rgba(0,0,0,.132), 0 0.3px 0.9px 0 rgba(0,0,0,.108);
|
||||
}
|
||||
body.darwin .article-search {
|
||||
body.darwin.not-fullscreen .article-search {
|
||||
left: 108px;
|
||||
max-width: calc(100% - 384px);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
appId: DevHYLiu.FluentReader
|
||||
buildVersion: 24
|
||||
productName: Fluent Reader
|
||||
copyright: Copyright © 2020 Haoyuan Liu
|
||||
files:
|
||||
- "./dist/**/*"
|
||||
- "!**/*.js.map"
|
||||
directories:
|
||||
output: "./bin/${platform}/${arch}/"
|
||||
mac:
|
||||
darkModeSupport: true
|
||||
target:
|
||||
- dmg
|
||||
category: public.app-category.news
|
||||
electronLanguages:
|
||||
- zh_CN
|
||||
- zh_TW
|
||||
- en
|
||||
- fr
|
||||
- es
|
||||
- de
|
||||
- tr
|
||||
- ja
|
||||
- sv
|
||||
- uk
|
||||
- it
|
||||
- nl
|
||||
minimumSystemVersion: 10.14.0
|
||||
mas:
|
||||
entitlements: build/entitlements.mas.plist
|
||||
entitlementsInherit: build/entitlements.mas.inherit.plist
|
||||
provisioningProfile: build/embedded.provisionprofile
|
||||
hardenedRuntime: false
|
||||
gatekeeperAssess: false
|
||||
asarUnpack: []
|
|
@ -0,0 +1,62 @@
|
|||
appId: me.hyliu.fluentreader
|
||||
productName: Fluent Reader
|
||||
copyright: Copyright © 2020 Haoyuan Liu
|
||||
files:
|
||||
- "./dist/**/*"
|
||||
- "!**/*.js.map"
|
||||
directories:
|
||||
output: "./bin/${platform}/${arch}/"
|
||||
mac:
|
||||
darkModeSupport: true
|
||||
target:
|
||||
- dmg
|
||||
category: public.app-category.news
|
||||
electronLanguages:
|
||||
- zh_CN
|
||||
- zh_TW
|
||||
- en
|
||||
- fr
|
||||
- es
|
||||
- de
|
||||
- tr
|
||||
- ja
|
||||
- sv
|
||||
- uk
|
||||
- it
|
||||
- nl
|
||||
win:
|
||||
target:
|
||||
- nsis
|
||||
- zip
|
||||
appx:
|
||||
applicationId: FluentReader
|
||||
identityName: 25286HaoyuanLiu.FluentReader
|
||||
publisher: CN=FD70E7FA-E5AC-41C4-B9C4-6E8708A6616A
|
||||
backgroundColor: transparent
|
||||
languages:
|
||||
- zh-CN
|
||||
- zh-TW
|
||||
- en-US
|
||||
- fr-FR
|
||||
- es
|
||||
- de
|
||||
- tr
|
||||
- ja
|
||||
- sv
|
||||
- uk
|
||||
- it
|
||||
- nl
|
||||
showNameOnTiles: true
|
||||
setBuildNumber: true
|
||||
nsis:
|
||||
oneClick: false
|
||||
perMachine: true
|
||||
allowToChangeInstallationDirectory: true
|
||||
deleteAppDataOnUninstall: true
|
||||
linux:
|
||||
target:
|
||||
- AppImage
|
||||
icon: build/icons
|
||||
category: Utility
|
||||
desktop:
|
||||
StartupWMClass: fluent-reader
|
File diff suppressed because it is too large
Load Diff
95
package.json
95
package.json
|
@ -1,103 +1,23 @@
|
|||
{
|
||||
"name": "fluent-reader",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.2",
|
||||
"description": "Modern desktop RSS reader",
|
||||
"main": "./dist/electron.js",
|
||||
"scripts": {
|
||||
"build": "webpack --config ./webpack.config.js",
|
||||
"electron": "electron ./dist/electron.js",
|
||||
"start": "npm run build && npm run electron",
|
||||
"package-win": "electron-builder -w --x64 && electron-builder -w --ia32 && electron-builder -w appx:arm64",
|
||||
"package-win": "electron-builder -w appx:x64 && electron-builder -w appx:ia32 && electron-builder -w appx:arm64",
|
||||
"package-win-ci": "electron-builder -w --x64 -p never && electron-builder -w --ia32 -p never",
|
||||
"package-mac": "sudo electron-builder --mac",
|
||||
"package-mas": "sudo CSC_IDENTITY_AUTO_DISCOVERY=false electron-builder --mac mas",
|
||||
"package-mas-arm": "sudo CSC_IDENTITY_AUTO_DISCOVERY=false electron-builder --mac mas:arm64",
|
||||
"package-mas-sign": "node build/buildUniversalPkg.js && sudo vim \"bin/Fluent Reader.app/Contents/Info.plist\" && sudo bash build/resignAndPackage.sh",
|
||||
"package-mac": "electron-builder --mac --x64",
|
||||
"package-mas": "bash build/resignAndPackage.sh",
|
||||
"package-linux": "electron-builder --linux -p never"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Haoyuan Liu",
|
||||
"license": "BSD-3-Clause",
|
||||
"repository": "github:yang991178/fluent-reader",
|
||||
"build": {
|
||||
"appId": "me.hyliu.fluentreader",
|
||||
"productName": "Fluent Reader",
|
||||
"copyright": "Copyright © 2020 Haoyuan Liu",
|
||||
"files": [
|
||||
"./dist/**/*",
|
||||
"!**/*.js.map"
|
||||
],
|
||||
"directories": {
|
||||
"output": "./bin/${platform}/${arch}/"
|
||||
},
|
||||
"win": {
|
||||
"target": [
|
||||
"nsis",
|
||||
"appx",
|
||||
"zip"
|
||||
]
|
||||
},
|
||||
"appx": {
|
||||
"applicationId": "FluentReader",
|
||||
"identityName": "25286HaoyuanLiu.FluentReader",
|
||||
"publisher": "CN=FD70E7FA-E5AC-41C4-B9C4-6E8708A6616A",
|
||||
"backgroundColor": "transparent",
|
||||
"languages": [
|
||||
"zh-CN",
|
||||
"zh-TW",
|
||||
"en-US",
|
||||
"fr-FR",
|
||||
"es",
|
||||
"de",
|
||||
"tr"
|
||||
],
|
||||
"showNameOnTiles": true,
|
||||
"setBuildNumber": true
|
||||
},
|
||||
"nsis": {
|
||||
"oneClick": false,
|
||||
"perMachine": true,
|
||||
"allowToChangeInstallationDirectory": true,
|
||||
"deleteAppDataOnUninstall": true
|
||||
},
|
||||
"mac": {
|
||||
"darkModeSupport": true,
|
||||
"target": [
|
||||
"dmg"
|
||||
],
|
||||
"category": "public.app-category.news",
|
||||
"electronLanguages": [
|
||||
"zh_CN",
|
||||
"zh_TW",
|
||||
"en",
|
||||
"fr",
|
||||
"es",
|
||||
"de",
|
||||
"tr"
|
||||
]
|
||||
},
|
||||
"mas": {
|
||||
"appId": "DevHYLiu.FluentReader",
|
||||
"entitlements": "build/entitlements.mas.plist",
|
||||
"entitlementsInherit": "build/entitlements.mas.inherit.plist",
|
||||
"provisioningProfile": "build/embedded.provisionprofile",
|
||||
"hardenedRuntime": false,
|
||||
"gatekeeperAssess": false,
|
||||
"asarUnpack": []
|
||||
},
|
||||
"linux": {
|
||||
"target": [
|
||||
"AppImage"
|
||||
],
|
||||
"icon": "build/icons",
|
||||
"category": "Utility",
|
||||
"desktop": {
|
||||
"StartupWMClass": "fluent-reader"
|
||||
}
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron/universal": "^1.0.4",
|
||||
"@fluentui/react": "^7.126.2",
|
||||
"@types/lovefield": "^2.1.3",
|
||||
"@types/nedb": "^1.8.9",
|
||||
|
@ -105,8 +25,8 @@
|
|||
"@types/react-dom": "^16.9.8",
|
||||
"@types/react-redux": "^7.1.9",
|
||||
"@yang991178/rss-parser": "^3.8.1",
|
||||
"electron": "^11.0.3",
|
||||
"electron-builder": "^22.9.1",
|
||||
"electron": "^13.1.4",
|
||||
"electron-builder": "^22.11.3",
|
||||
"electron-react-devtools": "^0.5.3",
|
||||
"electron-store": "^5.2.0",
|
||||
"electron-window-state": "^5.0.3",
|
||||
|
@ -128,6 +48,5 @@
|
|||
"typescript": "^3.9.2",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.11"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,6 +90,9 @@ const utilsBridge = {
|
|||
isMaximized: () => {
|
||||
return ipcRenderer.sendSync("is-maximized") as boolean
|
||||
},
|
||||
isFullscreen: () => {
|
||||
return ipcRenderer.sendSync("is-fullscreen") as boolean
|
||||
},
|
||||
isFocused: () => {
|
||||
return ipcRenderer.sendSync("is-focused") as boolean
|
||||
},
|
||||
|
@ -108,6 +111,14 @@ const utilsBridge = {
|
|||
ipcRenderer.on("unmaximized", () => {
|
||||
callback(WindowStateListenerType.Maximized, false)
|
||||
})
|
||||
ipcRenderer.removeAllListeners("enter-fullscreen")
|
||||
ipcRenderer.on("enter-fullscreen", () => {
|
||||
callback(WindowStateListenerType.Fullscreen, true)
|
||||
})
|
||||
ipcRenderer.removeAllListeners("leave-fullscreen")
|
||||
ipcRenderer.on("leave-fullscreen", () => {
|
||||
callback(WindowStateListenerType.Fullscreen, false)
|
||||
})
|
||||
ipcRenderer.removeAllListeners("window-focus")
|
||||
ipcRenderer.on("window-focus", () => {
|
||||
callback(WindowStateListenerType.Focused, true)
|
||||
|
|
|
@ -26,6 +26,7 @@ class Nav extends React.Component<NavProps, NavState> {
|
|||
constructor(props) {
|
||||
super(props)
|
||||
this.setBodyFocusState(window.utils.isFocused())
|
||||
this.setBodyFullscreenState(window.utils.isFullscreen())
|
||||
window.utils.addWindowStateListener(this.windowStateListener)
|
||||
this.state = {
|
||||
maximized: window.utils.isMaximized()
|
||||
|
@ -37,11 +38,19 @@ class Nav extends React.Component<NavProps, NavState> {
|
|||
else document.body.classList.add("blur")
|
||||
}
|
||||
|
||||
setBodyFullscreenState = (fullscreen: boolean) => {
|
||||
if (fullscreen) document.body.classList.remove("not-fullscreen")
|
||||
else document.body.classList.add("not-fullscreen")
|
||||
}
|
||||
|
||||
windowStateListener = (type: WindowStateListenerType, state: boolean) => {
|
||||
switch (type) {
|
||||
case WindowStateListenerType.Maximized:
|
||||
this.setState({ maximized: state })
|
||||
break
|
||||
case WindowStateListenerType.Fullscreen:
|
||||
this.setBodyFullscreenState(state)
|
||||
break
|
||||
case WindowStateListenerType.Focused:
|
||||
this.setBodyFocusState(state)
|
||||
break
|
||||
|
|
|
@ -107,7 +107,12 @@ class AppTab extends React.Component<AppTabProps, AppTabState> {
|
|||
{ key: "en-US", text: "English" },
|
||||
{ key: "es", text: "Español" },
|
||||
{ key: "fr-FR", text: "Français" },
|
||||
{ key: "it", text: "Italiano" },
|
||||
{ key: "nl", text: "Nederlands" },
|
||||
{ key: "sv", text: "Svenska" },
|
||||
{ key: "tr", text: "Türkçe" },
|
||||
{ key: "uk", text: "Українська" },
|
||||
{ key: "ja", text: "日本語" },
|
||||
{ key: "zh-CN", text: "中文(简体)" },
|
||||
{ key: "zh-TW", text: "中文(繁體)" },
|
||||
]
|
||||
|
|
|
@ -184,6 +184,10 @@ export function setUtilsListeners(manager: WindowManager) {
|
|||
event.returnValue = manager.hasWindow() && manager.mainWindow.isFocused()
|
||||
})
|
||||
|
||||
ipcMain.on("is-fullscreen", (event) => {
|
||||
event.returnValue = manager.hasWindow() && manager.mainWindow.isFullScreen()
|
||||
})
|
||||
|
||||
ipcMain.handle("request-focus", () => {
|
||||
if (manager.hasWindow()) {
|
||||
const win = manager.mainWindow
|
||||
|
|
|
@ -54,7 +54,7 @@ export class WindowManager {
|
|||
minHeight: 600,
|
||||
frame: process.platform === "darwin",
|
||||
titleBarStyle: "hiddenInset",
|
||||
fullscreenable: false,
|
||||
fullscreenable: process.platform === "darwin",
|
||||
show: false,
|
||||
webPreferences: {
|
||||
webviewTag: true,
|
||||
|
@ -79,6 +79,12 @@ export class WindowManager {
|
|||
this.mainWindow.on("unmaximize", () => {
|
||||
this.mainWindow.webContents.send("unmaximized")
|
||||
})
|
||||
this.mainWindow.on("enter-full-screen", () => {
|
||||
this.mainWindow.webContents.send("enter-fullscreen")
|
||||
})
|
||||
this.mainWindow.on("leave-full-screen", () => {
|
||||
this.mainWindow.webContents.send("leave-fullscreen")
|
||||
})
|
||||
this.mainWindow.on("focus", () => {
|
||||
this.mainWindow.webContents.send("window-focus")
|
||||
})
|
||||
|
|
|
@ -51,7 +51,7 @@ export interface ServiceConfigs {
|
|||
}
|
||||
|
||||
export const enum WindowStateListenerType {
|
||||
Maximized, Focused
|
||||
Maximized, Focused, Fullscreen
|
||||
}
|
||||
|
||||
export interface TouchBarTexts {
|
||||
|
|
|
@ -8,10 +8,13 @@ Currently, Fluent Reader supports the following languages.
|
|||
| es | Español | [@kant](https://github.com/kant) |
|
||||
| fr-FR | Français | [@Toinane](https://github.com/Toinane) |
|
||||
| zh-CN | 中文(简体) | [@yang991178](https://github.com/yang991178) |
|
||||
| zh-TW | 中文(繁體) | [@jerryc127](https://github.com/jerryc127) |
|
||||
| ja | 日本語 | [@tiancheng2000](https://github.com/tiancheng2000) |
|
||||
| de | Deutsch | [@NoNamePro0](https://github.com/NoNamePro0) |
|
||||
| sv | Svenska | [@eson57](https://github.com/eson57) |
|
||||
| tr | Türkçe | [@mustafagenc](https://github.com/mustafagenc) |
|
||||
| ua | Ukrainian | [@thevllad](https://github.com/thevllad) |
|
||||
| uk | Ukrainian | [@thevllad](https://github.com/thevllad) |
|
||||
| nl | Nederlands | [@Vistaus](https://github.com/Vistaus) |
|
||||
| it | Italiano | [@andrewasd](https://github.com/andrewasd) |
|
||||
|
||||
Refer to the repo of [react-intl-universal](https://github.com/alibaba/react-intl-universal) to get started on internationalization.
|
||||
|
|
|
@ -9,7 +9,7 @@ import es from "./es.json"
|
|||
import sv from "./sv.json"
|
||||
import tr from "./tr.json"
|
||||
import it from "./it.json"
|
||||
import ua from "./ua.json"
|
||||
import uk from "./uk.json"
|
||||
|
||||
const locales = {
|
||||
"en-US": en_US,
|
||||
|
@ -23,7 +23,7 @@ const locales = {
|
|||
"sv": sv,
|
||||
"tr": tr,
|
||||
"it": it,
|
||||
"ua": ua
|
||||
"uk": uk
|
||||
}
|
||||
|
||||
export default locales
|
||||
|
|
|
@ -212,7 +212,7 @@
|
|||
"cacheSize": "Dimensione Cache {size}",
|
||||
"deleteChoices": "Rimuovi articoli di ... giorni fà",
|
||||
"confirmDelete": "Rimuovi",
|
||||
"daysAgo": "{giorni, plural, =1 {# giorno} other {# giorni}} fà",
|
||||
"daysAgo": "{days, plural, =1 {# giorno} other {# giorni}} fà",
|
||||
"deleteAll": "Rimuovi tutti gli articoli",
|
||||
"calculatingSize": "Calcolo dimensione...",
|
||||
"itemSize": "Gli articoli occupano {size} ",
|
||||
|
|
|
@ -107,7 +107,7 @@
|
|||
"fetching": "フィードを更新中、しばらくお待ちください…",
|
||||
"exit": "終了",
|
||||
"sources": "フィード",
|
||||
"grouping": "グルーピングとソーティング",
|
||||
"grouping": "グルーピング",
|
||||
"rules": "ルール",
|
||||
"service": "サービス",
|
||||
"app": "環境設定",
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
"m": "m",
|
||||
"h": "u",
|
||||
"d": "d",
|
||||
"minuut": "{m, plural, =1 {# minute} other {# minutes}}",
|
||||
"uur": "{h, plural, =1 {# hour} other {# hours}}",
|
||||
"dag": "{d, plural, =1 {# day} other {# days}}"
|
||||
"minute": "{m, plural, =1 {# minuut} other {# minuten}}",
|
||||
"hour": "{h, plural, =1 {# uur} other {# uur}}",
|
||||
"day": "{d, plural, =1 {# dag} other {# dagen}}"
|
||||
},
|
||||
"log": {
|
||||
"empty": "Geen meldingen",
|
||||
|
@ -211,7 +211,7 @@
|
|||
"cacheSize": "In cache: {size} aan gegevens",
|
||||
"deleteChoices": "Artikelen verwijderen die ouder zijn dan … dagen",
|
||||
"confirmDelete": "Verwijderen",
|
||||
"daysAgo": "{days, plural, =1 {# day} other {# days}} geleden",
|
||||
"daysAgo": "{days, plural, =1 {# dag} other {# dagen}} geleden",
|
||||
"deleteAll": "Alle artikelen verwijderen",
|
||||
"calculatingSize": "Bezig met grootteberekening…",
|
||||
"itemSize": "De artikelen nemen ongeveer {size} aan lokale opslag in beslag",
|
||||
|
|
|
@ -211,7 +211,7 @@
|
|||
"cacheSize": "Cache-lagra {size} data",
|
||||
"deleteChoices": "Ta bort artiklar från ... dagar sedan",
|
||||
"confirmDelete": "Ta bort",
|
||||
"daysAgo": "{dagar, plural, =1 {# dag} other {# dagar}} sedan",
|
||||
"daysAgo": "{day, plural, =1 {# dag} other {# dagar}} sedan",
|
||||
"deleteAll": "Ta bort alla artiklar",
|
||||
"calculatingSize": "Beräknar storlek...",
|
||||
"itemSize": "Omkring {size} lokal datalagring upptas av artiklar",
|
||||
|
|
|
@ -211,7 +211,7 @@
|
|||
"cacheSize": "Кешовано {size} даних",
|
||||
"deleteChoices": "Видалити статті з ... днів тому",
|
||||
"confirmDelete": "Видалити",
|
||||
"daysAgo": "{days, plural, =1 {# день} other {# днів}} ago",
|
||||
"daysAgo": "{days, plural, =1 {# день} other {# днів}} тому",
|
||||
"deleteAll": "Видалити всі статті",
|
||||
"calculatingSize": "Розрахунок розміру ...",
|
||||
"itemSize": "Близько {size} локальної пам'яті займають статті",
|
|
@ -3,7 +3,7 @@ import { INIT_SOURCES, SourceActionTypes, ADD_SOURCE, UPDATE_SOURCE, DELETE_SOUR
|
|||
import { RSSItem, ItemActionTypes, FETCH_ITEMS, fetchItems } from "./item"
|
||||
import { ActionStatus, AppThunk, getWindowBreakpoint, initTouchBarWithTexts } from "../utils"
|
||||
import { INIT_FEEDS, FeedActionTypes, ALL, initFeeds } from "./feed"
|
||||
import { SourceGroupActionTypes, UPDATE_SOURCE_GROUP, ADD_SOURCE_TO_GROUP, DELETE_SOURCE_GROUP, REMOVE_SOURCE_FROM_GROUP, REORDER_SOURCE_GROUPS, fixBrokenGroups } from "./group"
|
||||
import { SourceGroupActionTypes, UPDATE_SOURCE_GROUP, ADD_SOURCE_TO_GROUP, DELETE_SOURCE_GROUP, REMOVE_SOURCE_FROM_GROUP, REORDER_SOURCE_GROUPS } from "./group"
|
||||
import { PageActionTypes, SELECT_PAGE, PageType, selectAllArticles, showItemFromId } from "./page"
|
||||
import { getCurrentLocale } from "../settings"
|
||||
import locales from "../i18n/_locales"
|
||||
|
@ -323,7 +323,6 @@ export function initApp(): AppThunk {
|
|||
}).then(() => dispatch(initFeeds()))
|
||||
.then(async () => {
|
||||
dispatch(selectAllArticles())
|
||||
dispatch(fixBrokenGroups())
|
||||
await dispatch(fetchItems())
|
||||
}).then(() => {
|
||||
dispatch(updateFavicon())
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import intl from "react-intl-universal"
|
||||
import { SourceActionTypes, ADD_SOURCE, DELETE_SOURCE, addSource, RSSSource } from "./source"
|
||||
import { SourceActionTypes, ADD_SOURCE, DELETE_SOURCE, addSource, RSSSource, SourceState } from "./source"
|
||||
import { SourceGroup } from "../../schema-types"
|
||||
import { ActionStatus, AppThunk, domParser } from "../utils"
|
||||
import { saveSettings } from "./app"
|
||||
|
@ -162,27 +162,33 @@ export function toggleGroupExpansion(groupIndex: number): AppThunk {
|
|||
}
|
||||
}
|
||||
|
||||
export function fixBrokenGroups(): AppThunk {
|
||||
export function fixBrokenGroups(sources: SourceState): AppThunk {
|
||||
return (dispatch, getState) => {
|
||||
const { sources, groups } = getState()
|
||||
const { groups } = getState()
|
||||
const sids = new Set(Object.values(sources).map(s => s.sid))
|
||||
for (let group of groups) {
|
||||
for (let sid of group.sids) {
|
||||
sids.delete(sid)
|
||||
let isBroken = false
|
||||
const newGroups: SourceGroup[] = groups.map(group => {
|
||||
const newGroup: SourceGroup = {
|
||||
...group,
|
||||
sids: group.sids.filter(sid => sids.delete(sid))
|
||||
}
|
||||
}
|
||||
if (sids.size > 0) {
|
||||
if (newGroup.sids.length !== group.sids.length) {
|
||||
isBroken = true
|
||||
}
|
||||
return newGroup
|
||||
}).filter(group => group.isMultiple || group.sids.length > 0)
|
||||
if (isBroken || sids.size > 0) {
|
||||
for (let sid of sids) {
|
||||
groups.push(new SourceGroup([sid]))
|
||||
newGroups.push(new SourceGroup([sid]))
|
||||
}
|
||||
dispatch(reorderSourceGroups(groups))
|
||||
dispatch(reorderSourceGroups(newGroups))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function outlineToSource(outline: Element): [ReturnType<typeof addSource>, string] {
|
||||
let url = outline.getAttribute("xmlUrl")
|
||||
let name = outline.getAttribute("text") || outline.getAttribute("name")
|
||||
let name = outline.getAttribute("text") || outline.getAttribute("title")
|
||||
if (url) {
|
||||
return [addSource(url.trim(), name, true), url]
|
||||
} else {
|
||||
|
@ -252,7 +258,7 @@ export function importOPML(): AppThunk {
|
|||
function sourceToOutline(source: RSSSource, xml: Document) {
|
||||
let outline = xml.createElement("outline")
|
||||
outline.setAttribute("text", source.name)
|
||||
outline.setAttribute("name", source.name)
|
||||
outline.setAttribute("title", source.name)
|
||||
outline.setAttribute("type", "rss")
|
||||
outline.setAttribute("xmlUrl", source.url)
|
||||
return outline
|
||||
|
@ -273,7 +279,7 @@ export function exportOPML(): AppThunk {
|
|||
if (group.isMultiple) {
|
||||
let outline = xml.createElement("outline")
|
||||
outline.setAttribute("text", group.name)
|
||||
outline.setAttribute("name", group.name)
|
||||
outline.setAttribute("title", group.name)
|
||||
for (let sid of group.sids) {
|
||||
outline.appendChild(sourceToOutline(state.sources[sid], xml))
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import { fetchFavicon, ActionStatus, AppThunk, parseRSS } from "../utils"
|
|||
import { RSSItem, insertItems, ItemActionTypes, FETCH_ITEMS, MARK_READ, MARK_UNREAD, MARK_ALL_READ } from "./item"
|
||||
import { saveSettings } from "./app"
|
||||
import { SourceRule } from "./rule"
|
||||
import { fixBrokenGroups } from "./group"
|
||||
|
||||
export const enum SourceOpenTarget {
|
||||
Local, Webpage, External, FullContent
|
||||
|
@ -182,6 +183,7 @@ export function initSources(): AppThunk<Promise<void>> {
|
|||
state[source.sid] = source
|
||||
}
|
||||
await unreadCount(state)
|
||||
dispatch(fixBrokenGroups(state))
|
||||
dispatch(initSourcesSuccess(state))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue