Merge pull request #339 from yang991178/1.1.0

Version 1.1.0
This commit is contained in:
Haoyuan Liu 2021-12-16 17:28:02 +08:00 committed by GitHub
commit 73930f3e69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 671 additions and 766 deletions

View File

@ -1,10 +1,3 @@
# 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"
# Name of your app.
APP="Fluent Reader"
# Your Certificate name.
@ -21,6 +14,17 @@ PARENT_PLIST="build/entitlements.mas.plist"
CHILD_PLIST="build/entitlements.mas.inherit.plist"
LOGINHELPER_PLIST="build/entitlements.mas.loginhelper.plist"
FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks"
# Build universal binary for font-list
# FONTLIST_PATH="node_modules/font-list/libs/darwin/fontlist.m"
# clang -arch arm64 -arch x86_64 "$FONTLIST_PATH" -fmodules -o "dist/fontlist"
# 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"
codesign --deep --force --verify --verbose=4 --timestamp --options runtime --entitlements "$CHILD_PLIST" -s "$APP_KEY" "$APP_PATH/Contents/Resources/app.asar.unpacked/dist/fontlist"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Electron Framework"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libEGL.dylib"
codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libGLESv2.dylib"
@ -44,4 +48,4 @@ codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$APP_PATH/Contents/MacO
codesign -s "$APP_KEY" -f --entitlements "$PARENT_PLIST" "$APP_PATH"
productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RESULT_PATH"
printf "\nresignAndPackage end\n......................\n"
printf "\nresignAndPackage end\n......................\n"

View File

@ -2,14 +2,25 @@
html,
body {
margin: 0;
font-family: "Segoe UI", "Source Han Sans SC Regular", "Microsoft YaHei",
sans-serif;
}
html {
body {
padding: 12px 96px 32px;
overflow: hidden scroll;
}
body.rtl {
direction: rtl;
}
body.vertical {
padding: 32px;
padding-right: 96px;
writing-mode: vertical-rl;
overflow: scroll hidden;
}
:root {
margin: 12px 96px 32px;
--gray: #484644;
--primary: #0078d4;
--primary-alt: #004578;
@ -58,6 +69,11 @@ a:active {
margin: 0 auto;
display: none;
}
body.vertical #main {
max-width: unset;
max-height: 700px;
margin: auto 0;
}
#main.show {
display: block;
animation-name: fadeIn;
@ -80,12 +96,21 @@ a:active {
article {
line-height: 1.6;
}
body.vertical article {
line-height: 1.5;
}
body.vertical article p {
text-indent: 2rem;
}
article * {
max-width: 100%;
}
article img {
height: auto;
}
body.vertical article img {
max-height: 75%;
}
article figure {
margin: 16px 0;
text-align: center;
@ -103,6 +128,11 @@ article code {
font-size: 0.875rem;
line-height: 1;
}
article pre {
word-break: normal;
overflow-wrap: normal;
white-space: pre-wrap;
}
article blockquote {
border-left: 2px solid var(--gray);
margin: 1em 0;

View File

@ -3,14 +3,14 @@
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy"
content="default-src 'none'; script-src-elem 'sha256-sLDWrq1tUAO8IyyqmUckFqxbXYfZ2/3TEUmtxH8Unf0=' 'sha256-9YXu4Ifpt+hDzuBhE+vFtXKt1ZRbo/CkuUY4VX4dZyE='; img-src http: https: data:; style-src 'self' 'unsafe-inline'; frame-src http: https:; media-src http: https:; connect-src https: http:">
content="default-src 'none'; script-src-elem 'sha256-sLDWrq1tUAO8IyyqmUckFqxbXYfZ2/3TEUmtxH8Unf0=' 'sha256-iOdZeo0zvgcSuiH/7/dXCOHo7s0cn2XtsidqVOcHBjo='; img-src http: https: data:; style-src 'self' 'unsafe-inline'; frame-src http: https:; media-src http: https:; connect-src https: http:">
<title>Article</title>
<link rel="stylesheet" href="article.css" />
<script integrity="sha256-sLDWrq1tUAO8IyyqmUckFqxbXYfZ2/3TEUmtxH8Unf0=" src="mercury.web.js"></script>
</head>
<body>
<div id="main"></div>
<script integrity="sha256-9YXu4Ifpt+hDzuBhE+vFtXKt1ZRbo/CkuUY4VX4dZyE=" src="article.js"></script>
<script integrity="sha256-iOdZeo0zvgcSuiH/7/dXCOHo7s0cn2XtsidqVOcHBjo=" src="article.js"></script>
<!-- Run "cat article.js | openssl dgst -sha256 -binary | openssl enc -base64 -A" for hash -->
</body>
</html>

View File

@ -2,6 +2,15 @@ function get(name) {
if (name = (new RegExp('[?&]' + encodeURIComponent(name) + '=([^&]*)')).exec(location.search))
return decodeURIComponent(name[1]);
}
let dir = get("d")
if (dir === "1") {
document.body.classList.add("rtl")
} else if (dir === "2") {
document.body.classList.add("vertical")
document.body.addEventListener("wheel", (evt) => {
document.scrollingElement.scrollLeft -= evt.deltaY;
});
}
async function getArticle(url) {
let article = get("a")
if (get("m") === "1") {
@ -11,6 +20,8 @@ async function getArticle(url) {
}
}
document.documentElement.style.fontSize = get("s") + "px"
let font = get("f")
if (font) document.body.style.fontFamily = `"${font}"`
let url = get("u")
getArticle(url).then(article => {
let domParser = new DOMParser()
@ -32,4 +43,3 @@ getArticle(url).then(article => {
main.innerHTML = dom.body.innerHTML
main.classList.add("show")
})

BIN
dist/fontlist vendored Executable file

Binary file not shown.

29
dist/fonts.vbs vendored Normal file
View File

@ -0,0 +1,29 @@
Option Explicit
Dim objShell, objFSO, objFile, objFolder
Dim objFolderItem, colItems, objFont
Dim strFileName
Const FONTS = &H14& ' Fonts Folder
' Instantiate Objects
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.Namespace(FONTS)
Set objFolderItem = objFolder.Self
Set colItems = objFolder.Items
Set objFSO = CreateObject("Scripting.FileSystemObject")
For Each objFont in colItems
WScript.StdOut.WriteLine(objFont.Path & vbtab & objFont.Name)
Next
Set objShell = nothing
Set objFile = nothing
Set objFolder = nothing
Set objFolderItem = nothing
Set colItems = nothing
Set objFont = nothing
Set objFSO = nothing
wscript.quit

View File

@ -138,6 +138,10 @@ i.ms-Nav-chevron {
color: var(--neutralPrimary);
}
.ms-Callout-main {
border-radius: 5px;
}
#root > nav {
height: var(--navHeight);
-webkit-app-region: drag;

View File

@ -4,7 +4,10 @@ productName: Fluent Reader
copyright: Copyright © 2020 Haoyuan Liu
files:
- "./dist/**/*"
- "!./dist/fonts.vbs"
- "!**/*.js.map"
asarUnpack:
- "./dist/fontlist"
directories:
output: "./bin/${platform}/${arch}/"
mac:
@ -25,6 +28,7 @@ mac:
- uk
- it
- nl
- ko
minimumSystemVersion: 10.14.0
mas:
entitlements: build/entitlements.mas.plist

View File

@ -3,6 +3,7 @@ productName: Fluent Reader
copyright: Copyright © 2020 Haoyuan Liu
files:
- "./dist/**/*"
- "!./dist/fontlist"
- "!**/*.js.map"
directories:
output: "./bin/${platform}/${arch}/"
@ -24,6 +25,7 @@ mac:
- uk
- it
- nl
- ko
win:
target:
- nsis
@ -46,6 +48,7 @@ appx:
- uk
- it
- nl
- ko
showNameOnTiles: true
setBuildNumber: true
nsis:

1094
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "fluent-reader",
"version": "1.0.2",
"version": "1.1.0",
"description": "Modern desktop RSS reader",
"main": "./dist/electron.js",
"scripts": {
@ -26,11 +26,12 @@
"@types/react-dom": "^16.9.8",
"@types/react-redux": "^7.1.9",
"@yang991178/rss-parser": "^3.8.1",
"electron": "^13.1.4",
"electron": "^16.0.2",
"electron-builder": "^22.11.3",
"electron-react-devtools": "^0.5.3",
"electron-store": "^5.2.0",
"electron-window-state": "^5.0.3",
"font-list": "^1.4.2",
"hard-source-webpack-plugin": "^0.13.1",
"html-webpack-plugin": "^4.3.0",
"js-md5": "^0.7.3",

View File

@ -75,6 +75,13 @@ const settingsBridge = {
ipcRenderer.invoke("set-font-size", size)
},
getFont: (): string => {
return ipcRenderer.sendSync("get-font")
},
setFont: (font: string) => {
ipcRenderer.invoke("set-font", font)
},
getFetchInterval: (): number => {
return ipcRenderer.sendSync("get-fetch-interval")
},

View File

@ -170,11 +170,16 @@ const utilsBridge = {
destroyTouchBar: () => {
ipcRenderer.invoke("touchbar-destroy")
},
initFontList: (): Promise<Array<string>> => {
return ipcRenderer.invoke("init-font-list")
},
}
declare global {
interface Window {
utils: typeof utilsBridge
fontList: Array<string>
}
}

View File

@ -12,7 +12,11 @@ import {
Icon,
Link,
} from "@fluentui/react"
import { RSSSource, SourceOpenTarget } from "../scripts/models/source"
import {
RSSSource,
SourceOpenTarget,
SourceTextDirection,
} from "../scripts/models/source"
import { shareSubmenu } from "./context-menu"
import { platformCtrl, decodeFetchResponse } from "../scripts/utils"
@ -31,9 +35,14 @@ type ArticleProps = {
textMenu: (position: [number, number], text: string, url: string) => void
imageMenu: (position: [number, number]) => void
dismissContextMenu: () => void
updateSourceTextDirection: (
source: RSSSource,
direction: SourceTextDirection
) => void
}
type ArticleState = {
fontFamily: string
fontSize: number
loadWebpage: boolean
loadFull: boolean
@ -49,7 +58,8 @@ class Article extends React.Component<ArticleProps, ArticleState> {
constructor(props: ArticleProps) {
super(props)
this.state = {
fontSize: this.getFontSize(),
fontFamily: window.settings.getFont(),
fontSize: window.settings.getFontSize(),
loadWebpage: props.source.openTarget === SourceOpenTarget.Webpage,
loadFull: props.source.openTarget === SourceOpenTarget.FullContent,
fullContent: "",
@ -64,15 +74,16 @@ class Article extends React.Component<ArticleProps, ArticleState> {
this.loadFull()
}
getFontSize = () => {
return window.settings.getFontSize()
}
setFontSize = (size: number) => {
window.settings.setFontSize(size)
this.setState({ fontSize: size })
}
setFont = (font: string) => {
window.settings.setFont(font)
this.setState({ fontFamily: font })
}
fontMenuProps = (): IContextualMenuProps => ({
fontSizeMenuProps = (): IContextualMenuProps => ({
items: FONT_SIZE_OPTIONS.map(size => ({
key: String(size),
text: String(size),
@ -82,6 +93,53 @@ class Article extends React.Component<ArticleProps, ArticleState> {
})),
})
fontFamilyMenuProps = (): IContextualMenuProps => ({
items: window.fontList.map((font, idx) => ({
key: String(idx),
text: font === "" ? intl.get("default") : font,
canCheck: true,
checked: this.state.fontFamily === font,
onClick: () => this.setFont(font),
})),
})
updateTextDirection = (direction: SourceTextDirection) => {
this.props.updateSourceTextDirection(this.props.source, direction)
}
directionMenuProps = (): IContextualMenuProps => ({
items: [
{
key: "LTR",
text: intl.get("article.LTR"),
iconProps: { iconName: "Forward" },
canCheck: true,
checked: this.props.source.textDir === SourceTextDirection.LTR,
onClick: () =>
this.updateTextDirection(SourceTextDirection.LTR),
},
{
key: "RTL",
text: intl.get("article.RTL"),
iconProps: { iconName: "Back" },
canCheck: true,
checked: this.props.source.textDir === SourceTextDirection.RTL,
onClick: () =>
this.updateTextDirection(SourceTextDirection.RTL),
},
{
key: "Vertical",
text: intl.get("article.Vertical"),
iconProps: { iconName: "Down" },
canCheck: true,
checked:
this.props.source.textDir === SourceTextDirection.Vertical,
onClick: () =>
this.updateTextDirection(SourceTextDirection.Vertical),
},
],
})
moreMenuProps = (): IContextualMenuProps => ({
items: [
{
@ -117,10 +175,24 @@ class Article extends React.Component<ArticleProps, ArticleState> {
},
{
key: "fontMenu",
text: intl.get("article.font"),
iconProps: { iconName: "Font" },
disabled: this.state.loadWebpage,
subMenuProps: this.fontFamilyMenuProps(),
},
{
key: "fontSizeMenu",
text: intl.get("article.fontSize"),
iconProps: { iconName: "FontSize" },
disabled: this.state.loadWebpage,
subMenuProps: this.fontMenuProps(),
subMenuProps: this.fontSizeMenuProps(),
},
{
key: "directionMenu",
text: intl.get("article.textDir"),
iconProps: { iconName: "ChangeEntitlements" },
disabled: this.state.loadWebpage,
subMenuProps: this.directionMenuProps(),
},
{
key: "divider_1",
@ -290,7 +362,9 @@ class Article extends React.Component<ArticleProps, ArticleState> {
</>
)
)
return `article/article.html?a=${a}&h=${h}&s=${this.state.fontSize}&u=${
return `article/article.html?a=${a}&h=${h}&f=${encodeURIComponent(
this.state.fontFamily
)}&s=${this.state.fontSize}&d=${this.props.source.textDir}&u=${
this.props.item.link
}&m=${this.state.loadFull ? 1 : 0}`
}
@ -400,7 +474,7 @@ class Article extends React.Component<ArticleProps, ArticleState> {
? this.props.item.link
: this.articleView()
}
webpreferences="contextIsolation,disableDialogs,autoplayPolicy=document-user-activation-required"
webpreferences="contextIsolation,disableDialogs,autoplayPolicy=document-user-activation-required,nativeWindowOpen=false"
partition={this.state.loadWebpage ? "sandbox" : undefined}
/>
)}

View File

@ -20,7 +20,6 @@ import {
DefaultButton,
ChoiceGroup,
IChoiceGroupOption,
loadTheme,
Dropdown,
IDropdownOption,
PrimaryButton,
@ -140,6 +139,7 @@ class AppTab extends React.Component<AppTabProps, AppTabState> {
{ key: "sv", text: "Svenska" },
{ key: "tr", text: "Türkçe" },
{ key: "uk", text: "Українська" },
{ key: "ko", text: "한글" },
{ key: "ja", text: "日本語" },
{ key: "zh-CN", text: "中文(简体)" },
{ key: "zh-TW", text: "中文(繁體)" },

View File

@ -17,6 +17,11 @@ import {
closeContextMenu,
openImageMenu,
} from "../scripts/models/app"
import {
RSSSource,
SourceTextDirection,
updateSource,
} from "../scripts/models/source"
type ArticleContainerProps = {
itemId: number
@ -58,6 +63,14 @@ const mapDispatchToProps = (dispatch: AppDispatch) => {
imageMenu: (position: [number, number]) =>
dispatch(openImageMenu(position)),
dismissContextMenu: () => dispatch(closeContextMenu()),
updateSourceTextDirection: (
source: RSSSource,
direction: SourceTextDirection
) => {
dispatch(
updateSource({ ...source, textDir: direction } as RSSSource)
)
},
}
}

View File

@ -26,6 +26,11 @@ window.utils.addMainContextListener((pos, text) => {
store.dispatch(openTextMenu(pos, text))
})
window.fontList = [""]
window.utils.initFontList().then(fonts => {
window.fontList.push(...fonts)
})
ReactDOM.render(
<Provider store={store}>
<Root />

View File

@ -122,6 +122,14 @@ ipcMain.handle("set-font-size", (_, size: number) => {
store.set(FONT_SIZE_STORE_KEY, size)
})
const FONT_STORE_KEY = "fontFamily"
ipcMain.on("get-font", event => {
event.returnValue = store.get(FONT_STORE_KEY, "")
})
ipcMain.handle("set-font", (_, font: string) => {
store.set(FONT_STORE_KEY, font)
})
ipcMain.on("get-all-settings", event => {
let output = {}
for (let [key, value] of store) {

View File

@ -1,16 +1,9 @@
import {
ipcMain,
shell,
dialog,
app,
session,
clipboard,
TouchBar,
} from "electron"
import { ipcMain, shell, dialog, app, session, clipboard } from "electron"
import { WindowManager } from "./window"
import fs = require("fs")
import { ImageCallbackTypes, TouchBarTexts } from "../schema-types"
import { initMainTouchBar } from "./touchbar"
import fontList = require("font-list")
export function setUtilsListeners(manager: WindowManager) {
async function openExternal(url: string, background = false) {
@ -28,11 +21,15 @@ export function setUtilsListeners(manager: WindowManager) {
}
app.on("web-contents-created", (_, contents) => {
// TODO: Use contents.setWindowOpenHandler instead of new-window listener
contents.on("new-window", (event, url, _, disposition) => {
if (manager.hasWindow()) event.preventDefault()
contents.setWindowOpenHandler(details => {
if (contents.getType() === "webview")
openExternal(url, disposition === "background-tab")
openExternal(
details.url,
details.disposition === "background-tab"
)
return {
action: manager.hasWindow() ? "deny" : "allow",
}
})
contents.on("will-navigate", (event, url) => {
event.preventDefault()
@ -283,4 +280,10 @@ export function setUtilsListeners(manager: WindowManager) {
ipcMain.handle("touchbar-destroy", () => {
if (manager.hasWindow()) manager.mainWindow.setTouchBar(null)
})
ipcMain.handle("init-font-list", () => {
return fontList.getFonts({
disableQuoting: true,
})
})
}

View File

@ -63,14 +63,13 @@ export class WindowManager {
show: false,
webPreferences: {
webviewTag: true,
enableRemoteModule: false,
contextIsolation: true,
worldSafeExecuteJavaScript: true,
spellcheck: false,
preload: path.join(
app.getAppPath(),
(app.isPackaged ? "dist/" : "") + "preload.js"
),
nativeWindowOpen: false,
},
})
this.mainWindowState.manage(this.mainWindow)

View File

@ -88,6 +88,7 @@ export type SchemaTypes = {
locale: string
sourceGroups: SourceGroup[]
fontSize: number
fontFamily: string
menuOn: boolean
fetchInterval: number
searchEngine: SearchEngines

View File

@ -4,7 +4,7 @@ import lf from "lovefield"
import { RSSSource } from "./models/source"
import { RSSItem } from "./models/item"
const sdbSchema = lf.schema.create("sourcesDB", 1)
const sdbSchema = lf.schema.create("sourcesDB", 2)
sdbSchema
.createTable("sources")
.addColumn("sid", lf.Type.INTEGER)
@ -17,6 +17,7 @@ sdbSchema
.addColumn("serviceRef", lf.Type.STRING)
.addColumn("fetchFrequency", lf.Type.NUMBER)
.addColumn("rules", lf.Type.OBJECT)
.addColumn("textDir", lf.Type.NUMBER)
.addNullable(["iconurl", "serviceRef", "rules"])
.addIndex("idxURL", ["url"], true)
@ -48,8 +49,15 @@ export let sources: lf.schema.Table
export let itemsDB: lf.Database
export let items: lf.schema.Table
async function onUpgradeSourceDB(rawDb: lf.raw.BackStore) {
const version = rawDb.getVersion()
if (version < 2) {
await rawDb.addTableColumn("sources", "textDir", 0)
}
}
export async function init() {
sourcesDB = await sdbSchema.connect()
sourcesDB = await sdbSchema.connect({ onUpgrade: onUpgradeSourceDB })
sources = sourcesDB.getSchema().table("sources")
itemsDB = await idbSchema.connect()
items = itemsDB.getSchema().table("items")
@ -90,6 +98,7 @@ async function migrateNeDB() {
// @ts-ignore
delete doc._id
if (!doc.fetchFrequency) doc.fetchFrequency = 0
doc.textDir = 0
return sources.createRow(doc)
})
const iRows = itemDocs.map(doc => {

View File

@ -18,5 +18,6 @@ Currently, Fluent Reader supports the following languages.
| nl | Nederlands | [@Vistaus](https://github.com/Vistaus) |
| it | Italiano | [@andrewasd](https://github.com/andrewasd) |
| pt-BR | Português do Brasil | [@fabianski7](https://github.com/fabianski7) |
| ko | 한글 | [@1drive](https://github.com/1drive) |
Refer to the repo of [react-intl-universal](https://github.com/alibaba/react-intl-universal) to get started on internationalization.

View File

@ -12,6 +12,7 @@ import it from "./it.json"
import uk from "./uk.json"
import pt_BR from "./pt-BR.json"
import fi_FI from "./fi-FI.json"
import ko from "./ko.json"
const locales = {
"en-US": en_US,
@ -28,6 +29,7 @@ const locales = {
"uk": uk,
"pt-BR": pt_BR,
"fi-FI": fi_FI,
"ko": ko,
}
export default locales

View File

@ -18,6 +18,7 @@
"confirmMarkAll": "Do you really want to mark all articles on this page as read?",
"confirm": "Confirm",
"cancel": "Cancel",
"default": "Default",
"time": {
"now": "now",
"m": "m",
@ -66,7 +67,12 @@
"loadWebpage": "Load webpage",
"loadFull": "Load full content",
"notify": "Notify if fetched in background",
"dontNotify": "Don't notify"
"dontNotify": "Don't notify",
"textDir": "Text direction",
"LTR": "Left-to-right",
"RTL": "Right-to-left",
"Vertical": "Vertical",
"font": "Font"
},
"context": {
"share": "Share",

View File

@ -211,7 +211,7 @@
"cacheSize": "Cache-lagra {size} data",
"deleteChoices": "Ta bort artiklar från ... dagar sedan",
"confirmDelete": "Ta bort",
"daysAgo": "{day, plural, =1 {# dag} other {# dagar}} sedan",
"daysAgo": "{days, 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

@ -18,6 +18,7 @@
"confirmMarkAll": "确认将本页所有文章标为已读?",
"confirm": "确认",
"cancel": "取消",
"default": "默认",
"time": {
"now": "now",
"m": "m",
@ -66,7 +67,12 @@
"loadWebpage": "加载网页",
"loadFull": "抓取全文",
"notify": "后台抓取时发送通知",
"dontNotify": "不发送通知"
"dontNotify": "不发送通知",
"textDir": "文本方向",
"LTR": "从左到右",
"RTL": "从右到左",
"Vertical": "纵书",
"font": "字体"
},
"context": {
"share": "分享",

View File

@ -18,6 +18,7 @@
"confirmMarkAll": "確認將本頁所有文章標為已讀?",
"confirm": "確認",
"cancel": "取消",
"default": "預設",
"time": {
"now": "now",
"m": "m",
@ -66,7 +67,12 @@
"loadWebpage": "載入網頁",
"loadFull": "抓取全文",
"notify": "後臺抓取時傳送通知",
"dontNotify": "不傳送通知"
"dontNotify": "不傳送通知",
"textDir": "文本方向",
"LTR": "從左到右",
"RTL": "從右到左",
"Vertical": "縱書",
"font": "字體"
},
"context": {
"share": "分享",

View File

@ -312,7 +312,8 @@ const markUnreadDone = (item: RSSItem): ItemActionTypes => ({
})
export function markRead(item: RSSItem): AppThunk {
return dispatch => {
return (dispatch, getState) => {
item = getState().items[item._id]
if (!item.hasRead) {
db.itemsDB
.update(db.items)
@ -377,7 +378,8 @@ export function markAllRead(
}
export function markUnread(item: RSSItem): AppThunk {
return dispatch => {
return (dispatch, getState) => {
item = getState().items[item._id]
if (item.hasRead) {
db.itemsDB
.update(db.items)

View File

@ -23,6 +23,12 @@ export const enum SourceOpenTarget {
FullContent,
}
export const enum SourceTextDirection {
LTR,
RTL,
Vertical,
}
export class RSSSource {
sid: number
url: string
@ -34,6 +40,7 @@ export class RSSSource {
serviceRef?: string
fetchFrequency: number // in minutes
rules?: SourceRule[]
textDir: SourceTextDirection
constructor(url: string, name: string = null) {
this.url = url
@ -41,6 +48,7 @@ export class RSSSource {
this.openTarget = SourceOpenTarget.Local
this.lastFetched = new Date()
this.fetchFrequency = 0
this.textDir = SourceTextDirection.LTR
}
static async fetchMetaData(source: RSSSource) {
@ -483,7 +491,7 @@ export function sourceReducer(
}
case MARK_ALL_READ: {
let nextState = { ...state }
action.sids.map((sid, i) => {
action.sids.forEach(sid => {
nextState[sid] = {
...state[sid],
unreadCount: action.time ? state[sid].unreadCount : 0,

View File

@ -3,6 +3,7 @@ import { IPartialTheme, loadTheme } from "@fluentui/react"
import locales from "./i18n/_locales"
import { ThemeSettings } from "../schema-types"
import intl from "react-intl-universal"
import { SourceTextDirection } from "./models/source"
const lightTheme: IPartialTheme = {
defaultFontStyle: {
@ -119,6 +120,7 @@ export async function importAll() {
} else {
const sRows = configs.lovefield.sources.map(s => {
s.lastFetched = new Date(s.lastFetched)
if (!s.textDir) s.textDir = SourceTextDirection.LTR
return db.sources.createRow(s)
})
const iRows = configs.lovefield.items.map(i => {

View File

@ -23,6 +23,9 @@ module.exports = [
path: __dirname + "/dist",
filename: "electron.js",
},
node: {
__dirname: false,
},
plugins: [new HardSourceWebpackPlugin()],
},
{