mirror of
https://github.com/yang991178/fluent-reader.git
synced 2025-02-07 23:38:41 +01:00
fetch progress indicator
This commit is contained in:
parent
9bdcf4ea34
commit
454cf48a45
28
dist/styles.css
vendored
28
dist/styles.css
vendored
@ -53,6 +53,21 @@ i.ms-Nav-chevron {
|
||||
user-select: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
nav .progress {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.ms-ProgressIndicator-itemProgress {
|
||||
padding: 0;
|
||||
}
|
||||
.ms-ProgressIndicator-progressTrack {
|
||||
background: none;
|
||||
}
|
||||
#root > nav span.title {
|
||||
font-size: 12px;
|
||||
line-height: 32px;
|
||||
@ -240,7 +255,7 @@ img.favicon {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@media (min-width: 1721px) {
|
||||
@media (min-width: 1441px) {
|
||||
#root > nav.menu-on {
|
||||
padding-left: 296px;
|
||||
}
|
||||
@ -256,6 +271,17 @@ img.favicon {
|
||||
.menu-container .menu {
|
||||
background-color: #edebe9;
|
||||
}
|
||||
.menu-container .menu::after {
|
||||
content: "";
|
||||
display: block;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
top: -10%;
|
||||
right: 0;
|
||||
width: 120%;
|
||||
height: 120%;
|
||||
box-shadow: inset 5px 0 20px #0004;
|
||||
}
|
||||
.main.menu-on {
|
||||
padding-left: 280px;
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
import * as React from "react"
|
||||
import { ipcRenderer, remote } from "electron"
|
||||
import { remote } from "electron"
|
||||
import { Icon } from "@fluentui/react/lib/Icon"
|
||||
import { AppState } from "../scripts/models/app"
|
||||
import { ProgressIndicator } from "@fluentui/react"
|
||||
|
||||
type NavProps = {
|
||||
state: AppState,
|
||||
@ -56,6 +57,12 @@ class Nav extends React.Component<NavProps, NavState> {
|
||||
if (this.canFetch()) this.props.fetch()
|
||||
}
|
||||
|
||||
getProgress = () => {
|
||||
return this.props.state.fetchingTotal > 0
|
||||
? this.props.state.fetchingProgress / this.props.state.fetchingTotal
|
||||
: null
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<nav className={this.hideButtons() + this.menuOn()}>
|
||||
@ -78,6 +85,11 @@ class Nav extends React.Component<NavProps, NavState> {
|
||||
</a>
|
||||
<a className={"btn system close"+this.menuOn()} title="关闭" onClick={this.close}><Icon iconName="Cancel" /></a>
|
||||
</div>
|
||||
{!this.canFetch() &&
|
||||
<ProgressIndicator
|
||||
className="progress"
|
||||
percentComplete={this.getProgress()} />
|
||||
}
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ class ProxyTab extends React.Component {
|
||||
|
||||
render = () => (
|
||||
<div className="tab-body">
|
||||
<Stack horizontal verticalAlign="center">
|
||||
<Stack horizontal verticalAlign="baseline">
|
||||
<Stack.Item grow>
|
||||
<Label>启用代理</Label>
|
||||
</Stack.Item>
|
||||
|
@ -30,6 +30,8 @@ export class AppState {
|
||||
sourceInit = false
|
||||
feedInit = false
|
||||
fetchingItems = false
|
||||
fetchingProgress = 0
|
||||
fetchingTotal = 0
|
||||
menu = getWindowBreakpoint()
|
||||
menuKey = ALL
|
||||
title = "全部文章"
|
||||
@ -182,7 +184,9 @@ export function appReducer(
|
||||
switch (action.status) {
|
||||
case ActionStatus.Request: return {
|
||||
...state,
|
||||
fetchingItems: true
|
||||
fetchingItems: true,
|
||||
fetchingProgress: 0,
|
||||
fetchingTotal: action.fetchCount
|
||||
}
|
||||
case ActionStatus.Failure: return {
|
||||
...state,
|
||||
@ -199,6 +203,7 @@ export function appReducer(
|
||||
case ActionStatus.Success: return {
|
||||
...state,
|
||||
fetchingItems: false,
|
||||
fetchingTotal: 0,
|
||||
logMenu: action.items.length == 0 ? state.logMenu : {
|
||||
...state.logMenu,
|
||||
logs: [...state.logMenu.logs, new AppLog(
|
||||
@ -207,6 +212,11 @@ export function appReducer(
|
||||
)]
|
||||
}
|
||||
}
|
||||
case ActionStatus.Intermediate: return {
|
||||
...state,
|
||||
fetchingProgress: state.fetchingProgress + 1
|
||||
}
|
||||
default: return state
|
||||
}
|
||||
case SELECT_PAGE:
|
||||
switch (action.pageType) {
|
||||
|
@ -251,6 +251,7 @@ export function feedReducer(
|
||||
loading: false
|
||||
}
|
||||
}
|
||||
default: return state
|
||||
}
|
||||
case SELECT_PAGE:
|
||||
switch (action.pageType) {
|
||||
|
@ -55,6 +55,7 @@ export const MARK_UNREAD = "MARK_UNREAD"
|
||||
interface FetchItemsAction {
|
||||
type: typeof FETCH_ITEMS
|
||||
status: ActionStatus
|
||||
fetchCount?: number
|
||||
items?: RSSItem[]
|
||||
errSource?: RSSSource
|
||||
err?
|
||||
@ -72,10 +73,11 @@ interface MarkUnreadAction {
|
||||
|
||||
export type ItemActionTypes = FetchItemsAction | MarkReadAction | MarkUnreadAction
|
||||
|
||||
export function fetchItemsRequest(): ItemActionTypes {
|
||||
export function fetchItemsRequest(fetchCount = 0): ItemActionTypes {
|
||||
return {
|
||||
type: FETCH_ITEMS,
|
||||
status: ActionStatus.Request
|
||||
status: ActionStatus.Request,
|
||||
fetchCount: fetchCount
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,6 +98,13 @@ export function fetchItemsFailure(source: RSSSource, err): ItemActionTypes {
|
||||
}
|
||||
}
|
||||
|
||||
export function fetchItemsIntermediate(): ItemActionTypes {
|
||||
return {
|
||||
type: FETCH_ITEMS,
|
||||
status: ActionStatus.Intermediate
|
||||
}
|
||||
}
|
||||
|
||||
export function insertItems(items: RSSItem[]): Promise<RSSItem[]> {
|
||||
return new Promise<RSSItem[]>((resolve, reject) => {
|
||||
db.idb.find({}).projection({ id: 1 }).sort({ id: -1 }).limit(1).exec((err, docs) => {
|
||||
@ -118,13 +127,15 @@ export function insertItems(items: RSSItem[]): Promise<RSSItem[]> {
|
||||
|
||||
export function fetchItems(): AppThunk<Promise<void>> {
|
||||
return (dispatch, getState) => {
|
||||
let p = new Array<Promise<RSSItem[]>>()
|
||||
let promises = new Array<Promise<RSSItem[]>>()
|
||||
if (!getState().app.fetchingItems) {
|
||||
for (let source of <RSSSource[]>Object.values(getState().sources)) {
|
||||
p.push(RSSSource.fetchItems(source, rssParser, db.idb))
|
||||
let promise = RSSSource.fetchItems(source, rssParser, db.idb)
|
||||
promise.finally(() => dispatch(fetchItemsIntermediate()))
|
||||
promises.push(promise)
|
||||
}
|
||||
dispatch(fetchItemsRequest())
|
||||
return Promise.allSettled(p).then(results => new Promise<void>((resolve, reject) => {
|
||||
dispatch(fetchItemsRequest(promises.length))
|
||||
return Promise.allSettled(promises).then(results => new Promise<void>((resolve, reject) => {
|
||||
let items = new Array<RSSItem>()
|
||||
results.map((r, i) => {
|
||||
if (r.status === "fulfilled") items.push(...r.value)
|
||||
|
@ -4,7 +4,7 @@ import { AnyAction } from "redux"
|
||||
import { RootState } from "./reducer"
|
||||
|
||||
export enum ActionStatus {
|
||||
Request, Success, Failure
|
||||
Request, Success, Failure, Intermediate
|
||||
}
|
||||
|
||||
export type AppThunk<ReturnType = void> = ThunkAction<
|
||||
@ -82,4 +82,4 @@ export function openExternal(url: string) {
|
||||
export const urlTest = (s: string) =>
|
||||
/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/gi.test(s)
|
||||
|
||||
export const getWindowBreakpoint = () => remote.getCurrentWindow().getSize()[0] >= 1721
|
||||
export const getWindowBreakpoint = () => remote.getCurrentWindow().getSize()[0] >= 1441
|
Loading…
x
Reference in New Issue
Block a user