add exporting to mobile app

This commit is contained in:
刘浩远 2021-02-01 18:38:22 +08:00
parent 09bb6cbd07
commit b336260d0c
13 changed files with 92 additions and 8 deletions

View File

@ -32,7 +32,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Fluent Reader v${{ steps.package-version.outputs.current-version }} Beta
release_name: Fluent Reader v${{ steps.package-version.outputs.current-version }}
draft: true
prerelease: false

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "fluent-reader",
"version": "0.9.1",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@ -1,6 +1,6 @@
{
"name": "fluent-reader",
"version": "0.9.1",
"version": "1.0.0",
"description": "Modern desktop RSS reader",
"main": "./dist/electron.js",
"scripts": {

View File

@ -40,7 +40,7 @@ export const shareSubmenu = (item: RSSItem): IContextualMenuItem[] => [
{ key: "qr", url: item.link, onRender: renderShareQR }
]
const renderShareQR = (item: IContextualMenuItem) => (
export const renderShareQR = (item: IContextualMenuItem) => (
<div className="qr-container">
<QRCode
value={item.url}

View File

@ -7,6 +7,7 @@ import { Stack, Icon, Label, TextField, PrimaryButton, DefaultButton, Checkbox,
MessageBar, MessageBarType, Dropdown, IDropdownOption } from "@fluentui/react"
import DangerButton from "../../utils/danger-button"
import { urlTest } from "../../../scripts/utils"
import LiteExporter from "./lite-exporter"
type FeedbinConfigsTabState = {
existing: boolean
@ -173,6 +174,7 @@ class FeedbinConfigsTab extends React.Component<ServiceConfigsTabProps, FeedbinC
}
</Stack.Item>
</Stack>
{ this.state.existing && <LiteExporter serviceConfigs={this.props.configs} /> }
</Stack>
</>
}

View File

@ -7,6 +7,7 @@ import { SyncService } from "../../../schema-types"
import { Stack, Icon, Label, TextField, PrimaryButton, DefaultButton, Checkbox, MessageBar, MessageBarType, Dropdown, IDropdownOption } from "@fluentui/react"
import DangerButton from "../../utils/danger-button"
import { urlTest } from "../../../scripts/utils"
import LiteExporter from "./lite-exporter"
type FeverConfigsTabState = {
existing: boolean
@ -173,6 +174,7 @@ class FeverConfigsTab extends React.Component<ServiceConfigsTabProps, FeverConfi
}
</Stack.Item>
</Stack>
{ this.state.existing && <LiteExporter serviceConfigs={this.props.configs} /> }
</Stack>
</>
}

View File

@ -6,6 +6,7 @@ import { SyncService } from "../../../schema-types"
import { Stack, Icon, Label, TextField, PrimaryButton, DefaultButton, Checkbox, MessageBar, MessageBarType, Dropdown, IDropdownOption } from "@fluentui/react"
import DangerButton from "../../utils/danger-button"
import { urlTest } from "../../../scripts/utils"
import LiteExporter from "./lite-exporter"
type GReaderConfigsTabState = {
existing: boolean
@ -173,6 +174,7 @@ class GReaderConfigsTab extends React.Component<ServiceConfigsTabProps, GReaderC
}
</Stack.Item>
</Stack>
{ this.state.existing && <LiteExporter serviceConfigs={this.props.configs} /> }
</Stack>
</>
}

View File

@ -6,6 +6,7 @@ import { SyncService } from "../../../schema-types"
import { Stack, Label, TextField, PrimaryButton, DefaultButton, Checkbox,
MessageBar, MessageBarType, Dropdown, IDropdownOption, MessageBarButton, Link } from "@fluentui/react"
import DangerButton from "../../utils/danger-button"
import LiteExporter from "./lite-exporter"
type GReaderConfigsTabState = {
existing: boolean
@ -225,6 +226,7 @@ class InoreaderConfigsTab extends React.Component<ServiceConfigsTabProps, GReade
}
</Stack.Item>
</Stack>
{ this.state.existing && <LiteExporter serviceConfigs={this.props.configs} /> }
</Stack>
</>
}

View File

@ -0,0 +1,73 @@
import * as React from "react"
import intl from "react-intl-universal"
import { Stack, ContextualMenuItemType, DefaultButton, IContextualMenuProps, DirectionalHint } from "@fluentui/react"
import { ServiceConfigs, SyncService } from "../../../schema-types"
import { renderShareQR } from "../../context-menu"
import { platformCtrl } from "../../../scripts/utils"
import { FeverConfigs } from "../../../scripts/models/services/fever"
import { GReaderConfigs } from "../../../scripts/models/services/greader"
import { FeedbinConfigs } from "../../../scripts/models/services/feedbin"
type LiteExporterProps = {
serviceConfigs: ServiceConfigs
}
const LEARN_MORE_URL = "https://github.com/yang991178/fluent-reader/wiki/Support#mobile-app"
const LiteExporter: React.FunctionComponent<LiteExporterProps> = (props) => {
let url = "https://hyliu.me/fr2l/?"
const params = new URLSearchParams()
switch (props.serviceConfigs.type) {
case SyncService.Fever: {
const configs = props.serviceConfigs as FeverConfigs
params.set("t", "f")
params.set("e", configs.endpoint)
params.set("u", configs.username)
params.set("k", configs.apiKey)
break
}
case SyncService.GReader:
case SyncService.Inoreader: {
const configs = props.serviceConfigs as GReaderConfigs
params.set("t", configs.type == SyncService.GReader ? "g" : "i")
params.set("e", configs.endpoint)
params.set("u", configs.username)
params.set("p", btoa(configs.password))
if (configs.inoreaderId) {
params.set("i", configs.inoreaderId)
params.set("k", configs.inoreaderKey)
}
break
}
case SyncService.Feedbin: {
const configs = props.serviceConfigs as FeedbinConfigs
params.set("t", "fb")
params.set("e", configs.endpoint)
params.set("u", configs.username)
params.set("p", btoa(configs.password))
break
}
}
url += params.toString()
const menuProps: IContextualMenuProps = {
directionalHint: DirectionalHint.bottomCenter,
items: [
{ key: "qr", url: url, onRender: renderShareQR },
{ key: "divider_1", itemType: ContextualMenuItemType.Divider },
{
key: "openInBrowser",
text: intl.get("rules.help"),
iconProps: { iconName: "NavigateExternalInline" },
onClick: e => { window.utils.openExternal(LEARN_MORE_URL, platformCtrl(e)) }
},
]
}
return <Stack style={{marginTop: 32}}>
<DefaultButton
text={intl.get("service.exportToLite")}
onRenderMenuIcon={() => <></>}
menuProps={menuProps} />
</Stack>
}
export default LiteExporter

View File

@ -202,7 +202,8 @@
"importGroups": "Import groups",
"failure": "Cannot connect to service",
"failureHint": "Please check the service configuration or network status.",
"fetchUnlimited": "Unlimited (not recommended)"
"fetchUnlimited": "Unlimited (not recommended)",
"exportToLite": "Export to Fluent Reader Lite"
},
"app": {
"cleanup": "Clean up",

View File

@ -200,7 +200,8 @@
"importGroups": "导入分组",
"failure": "连接到服务时出错",
"failureHint": "请检查服务配置或网络连接",
"fetchUnlimited": "无限制(不建议)"
"fetchUnlimited": "无限制(不建议)",
"exportToLite": "导出至 Fluent Reader Lite"
},
"app": {
"cleanup": "清理",

View File

@ -200,7 +200,8 @@
"importGroups": "匯入分組",
"failure": "連線到服務時出錯",
"failureHint": "請檢查服務配置或網路連線",
"fetchUnlimited": "無限制(不建議)"
"fetchUnlimited": "無限制(不建議)",
"exportToLite": "匯出至 Fluent Reader Lite"
},
"app": {
"cleanup": "清理",

View File

@ -94,7 +94,7 @@ export async function importAll() {
let requests = Object.entries(configs.nedb).map(([key, value]) => {
return objectStore.put(value, key)
})
let promises = requests.map(req => new Promise((resolve, reject) => {
let promises = requests.map(req => new Promise<void>((resolve, reject) => {
req.onsuccess = () => resolve()
req.onerror = () => reject()
}))