Merge pull request #271 from yang991178/1.0.2

Version 1.0.2
This commit is contained in:
Haoyuan Liu 2021-06-27 19:29:26 -07:00 committed by GitHub
commit e6c6fdbb2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 10273 additions and 648 deletions

View File

@ -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
});

View File

@ -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"

View File

@ -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 {

View File

@ -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);
}

35
electron-builder-mas.yml Normal file
View File

@ -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: []

62
electron-builder.yml Normal file
View File

@ -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

10603
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -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": {}
}
}

View File

@ -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)

View File

@ -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

View File

@ -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: "中文(繁體)" },
]

View File

@ -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

View File

@ -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")
})

View File

@ -51,7 +51,7 @@ export interface ServiceConfigs {
}
export const enum WindowStateListenerType {
Maximized, Focused
Maximized, Focused, Fullscreen
}
export interface TouchBarTexts {

View File

@ -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.

View File

@ -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

View File

@ -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} ",

View File

@ -107,7 +107,7 @@
"fetching": "フィードを更新中、しばらくお待ちください…",
"exit": "終了",
"sources": "フィード",
"grouping": "グルーピングとソーティング",
"grouping": "グルーピング",
"rules": "ルール",
"service": "サービス",
"app": "環境設定",

View File

@ -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",

View File

@ -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",

View File

@ -211,7 +211,7 @@
"cacheSize": "Кешовано {size} даних",
"deleteChoices": "Видалити статті з ... днів тому",
"confirmDelete": "Видалити",
"daysAgo": "{days, plural, =1 {# день} other {# днів}} ago",
"daysAgo": "{days, plural, =1 {# день} other {# днів}} тому",
"deleteAll": "Видалити всі статті",
"calculatingSize": "Розрахунок розміру ...",
"itemSize": "Близько {size} локальної пам'яті займають статті",

View File

@ -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())

View File

@ -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))
}

View File

@ -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))
}
}