diff --git a/packages/app/package.json b/packages/app/package.json
index 2a5dbe48..9652abf4 100755
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -45,13 +45,12 @@
"electron-is": "^3.0.0",
"electron-log": "^4.4.8",
"electron-squirrel-startup": "^1.0.0",
- "evite": "0.13.7",
+ "evite": "0.13.9",
"fast-average-color": "^9.2.0",
"faye": "1.4.0",
"feather-reactjs": "2.0.13",
"fuse.js": "6.5.3",
"global": "4.4.0",
- "history": "5.2.0",
"hls.js": "^1.1.5",
"howler": "2.2.3",
"i18next": "21.6.6",
@@ -59,7 +58,9 @@
"jwt-decode": "3.1.2",
"less": "4.1.2",
"linebridge": "0.13.0",
+ "localforage": "^1.10.0",
"luxon": "^3.0.4",
+ "match-sorter": "^6.3.1",
"moment": "2.29.4",
"moment-timezone": "^0.5.37",
"mpegts.js": "^1.6.10",
@@ -89,10 +90,12 @@
"react-responsive-carousel": "^3.2.23",
"react-reveal": "1.2.2",
"react-rnd": "10.3.5",
+ "react-router-dom": "^6.6.2",
"react-ticker": "^1.3.2",
"react-transition-group": "^4.4.5",
"remark-gfm": "^3.0.1",
"rxjs": "^7.5.5",
+ "sort-by": "^1.2.0",
"store": "^2.0.12",
"uuid": "^9.0.0",
"wait-on": "^6.0.1"
diff --git a/packages/app/src/App.jsx b/packages/app/src/App.jsx
index 56f42e3a..1f75f357 100755
--- a/packages/app/src/App.jsx
+++ b/packages/app/src/App.jsx
@@ -53,6 +53,7 @@ import { EviteRuntime } from "evite"
import { Helmet } from "react-helmet"
import * as antd from "antd"
import { Toast } from "antd-mobile"
+import { BrowserRouter } from "react-router-dom"
import { StatusBar, Style } from "@capacitor/status-bar"
import { App as CapacitorApp } from "@capacitor/app"
import { Translation } from "react-i18next"
@@ -455,15 +456,14 @@ class App extends React.Component {
})
StatusBar.setOverlaysWebView({ overlay: true })
- //window.app.hideStatusBar()
- CapacitorApp.addListener('backButton', ({ canGoBack }) => {
+ CapacitorApp.addListener("backButton", ({ canGoBack }) => {
if (!canGoBack) {
- CapacitorApp.exitApp();
+ CapacitorApp.exitApp()
} else {
- window.history.back();
+ window.history.back()
}
- });
+ })
}
const userAgentPlatform = window.navigator.userAgent.toLowerCase()
@@ -532,6 +532,7 @@ class App extends React.Component {
async () => {
try {
await this.__SessionInit()
+ await this.__UserInit()
app.eventBus.emit("app.initialization.session_success")
} catch (error) {
@@ -543,20 +544,6 @@ class App extends React.Component {
}
}
},
- async () => {
- try {
- await this.__UserInit()
-
- app.eventBus.emit("app.initialization.user_success")
- } catch (error) {
- app.eventBus.emit("app.initialization.user_error", error)
-
- throw {
- cause: "Cannot initialize user data",
- details: error.message,
- }
- }
- },
]
await Promise.tasked(initializationTasks).catch((reason) => {
@@ -607,8 +594,8 @@ class App extends React.Component {
-
-
+
+
-
-
+
+
}
}
diff --git a/packages/app/src/layout.jsx b/packages/app/src/layout.jsx
index b1747c70..fdf789fd 100755
--- a/packages/app/src/layout.jsx
+++ b/packages/app/src/layout.jsx
@@ -54,35 +54,8 @@ export default class Layout extends React.PureComponent {
document.querySelector("#transitionLayer").classList.add("fade-opacity-leave")
},
- "router.transitionStart": () => {
- this.progressBar.start()
-
- if (!app.settings.get("reduceAnimations")) {
- // add "fade-transverse-leave" class to `transitionLayer`
- const transitionLayer = document.getElementById("transitionLayer")
-
- if (!transitionLayer) {
- console.warn("transitionLayer not found, no animation will be played")
- return
- }
-
- transitionLayer.classList.add("fade-transverse-leave")
- }
- },
- "router.transitionFinish": () => {
- this.progressBar.done()
-
- if (!app.settings.get("reduceAnimations")) {
- // remove "fade-transverse-leave" class to `transitionLayer`
- const transitionLayer = document.getElementById("transitionLayer")
-
- if (!transitionLayer) {
- console.warn("transitionLayer not found, no animation will be played")
- return
- }
-
- transitionLayer.classList.remove("fade-transverse-leave")
- }
+ "router.navigate": (path, options) => {
+ this.makePageTransition(path, options)
},
}
@@ -112,6 +85,31 @@ export default class Layout extends React.PureComponent {
this.setState({ renderError: { info, stack } })
}
+ makePageTransition(path, options = {}) {
+ this.progressBar.start()
+
+ if (app.settings.get("reduceAnimations") || options.state.noTransition) {
+ this.progressBar.done()
+
+ return false
+ }
+
+ const transitionLayer = document.getElementById("transitionLayer")
+
+ if (!transitionLayer) {
+ console.warn("transitionLayer not found, no animation will be played")
+ return false
+ }
+
+ transitionLayer.classList.add("fade-transverse-leave")
+
+ setTimeout(() => {
+ this.progressBar.done()
+
+ transitionLayer.classList.remove("fade-transverse-leave")
+ }, options.state.transitionDelay ?? 250)
+ }
+
setLayout = (layout) => {
if (typeof Layouts[layout] === "function") {
return this.setState({
diff --git a/packages/app/src/router.jsx b/packages/app/src/router.jsx
index 9b7f4cea..10456da1 100755
--- a/packages/app/src/router.jsx
+++ b/packages/app/src/router.jsx
@@ -1,12 +1,17 @@
import React from "react"
-import { Switch, Route, BrowserRouter, withRouter } from "react-router-dom"
+import { Route, Routes, Navigate, useLocation, useNavigate, useParams } from "react-router-dom"
+import { Skeleton } from "antd"
+import loadable from "@loadable/component"
const NotFoundRender = () => {
return
Not found
}
+const LoadingRender = () => {
+ return
+}
+
const paths = {
- ...import.meta.glob("/src/debug/components/**/[a-z[]*.jsx"),
...import.meta.glob("/src/pages/**/[a-z[]*.jsx"),
...import.meta.glob("/src/pages/**/[a-z[]*.tsx"),
}
@@ -16,166 +21,103 @@ const pathsMobile = {
...import.meta.glob("/src/pages/**/[a-z[]*.mobile.tsx"),
}
+function generateElementWrapper(route, element, bindProps) {
+ return React.createElement((props) => {
+ const params = useParams()
+
+ return React.createElement(
+ loadable(element, {
+ fallback: React.createElement(LoadingRender),
+ }),
+ {
+ ...props,
+ ...bindProps,
+ params: params,
+ })
+ })
+}
+
const routes = Object.keys(paths).map((route) => {
const path = route
.replace(/\/src\/pages|index|\.jsx$/g, "")
.replace(/\/src\/pages|index|\.tsx$/g, "")
- .replace(/\/src\/debug\/components/g, "/debug")
.replace(/\[\.{3}.+\]/, "*")
.replace(/\[(.+)\]/, ":$1")
- return { path, component: React.lazy(paths[route]) }
+ return {
+ path,
+ element: paths[route]
+ }
})
-const mobileComponents = Object.fromEntries(Object.keys(pathsMobile).map((route) => {
+const mobileRoutes = Object.keys(pathsMobile).map((route) => {
const path = route
.replace(/\/src\/pages|index|\.mobile|\.jsx$/g, "")
.replace(/\/src\/pages|index|\.mobile|\.tsx$/g, "")
- .replace(/\/src\/debug\/components/g, "/debug")
.replace(/\[\.{3}.+\]/, "*")
.replace(/\[(.+)\]/, ":$1")
- return [path, React.lazy(pathsMobile[route])]
-}))
-
-export function BindContexts(component) {
- let contexts = {
- main: {},
- app: {},
+ return {
+ path,
+ element: pathsMobile[path]
}
+})
- if (typeof component.bindApp === "string") {
- if (component.bindApp === "all") {
- Object.keys(app).forEach((key) => {
- contexts.app[key] = app[key]
- })
- }
- } else {
- if (Array.isArray(component.bindApp)) {
- component.bindApp.forEach((key) => {
- contexts.app[key] = app[key]
- })
- }
- }
-
- if (typeof component.bindMain === "string") {
- if (component.bindMain === "all") {
- Object.keys(main).forEach((key) => {
- contexts.main[key] = main[key]
- })
- }
- } else {
- if (Array.isArray(component.bindMain)) {
- component.bindMain.forEach((key) => {
- contexts.main[key] = main[key]
- })
- }
- }
-
- return (props) => React.createElement(component, { ...props, contexts })
-}
-
-export const Router = withRouter((props) => {
- const defaultTransitionDelay = 150
- const forceUpdate = React.useReducer(() => ({}))[1]
+export const PageRender = React.memo((props) => {
+ const navigate = useNavigate()
+ app.location = useLocation()
React.useEffect(() => {
- props.history.listen((event) => {
- if (typeof props.onTransitionFinish === "function") {
- props.onTransitionFinish(event)
- }
-
- window.app.eventBus.emit("router.transitionFinish", event)
- })
-
- props.history.setLocation = (to, state = {}, delay = 150) => {
+ app.setLocation = async (to, state = {}) => {
// clean double slashes
to = to.replace(/\/{2,}/g, "/")
// if state is a number, it's a delay
if (typeof state !== "object") {
- delay = state
state = {}
}
- const lastLocation = props.history.lastLocation
+ state.transitionDelay = Number((app.style.getValue("page-transition-duration") ?? "250ms").replace("ms", ""))
- if (typeof lastLocation !== "undefined" && lastLocation?.pathname === to && lastLocation?.state === state) {
- return false
+ app.eventBus.emit("router.navigate", to, {
+ state,
+ })
+
+ if (state.transitionDelay >= 100) {
+ await new Promise((resolve) => {
+ setTimeout(() => {
+ resolve()
+ }, state.transitionDelay)
+ })
}
- if (typeof props.onTransitionStart === "function") {
- props.onTransitionStart(delay)
- }
-
- window.app.eventBus.emit("router.transitionStart", delay)
-
- setTimeout(() => {
- props.history.push({
- pathname: to,
- }, state)
-
- props.history.lastLocation = window.location
- }, delay ?? defaultTransitionDelay)
+ return navigate(to, {
+ state
+ })
}
-
- window.app.eventBus.on(`router.forceUpdate`, forceUpdate)
-
- props.history.lastLocation = window.location
-
- window.app.setLocation = props.history.setLocation
}, [])
- const router = {
- history: props.history,
- lastLocation: props.history.lastLocation,
- forceUpdate,
- }
+ return
+ {
+ routes.map((route, index) => {
+ let Element = route.element
- // return children with router in props
- return React.cloneElement(props.children, { router })
-})
-
-export const InternalRouter = (props) => {
- return
-
-
-}
-
-export const PageRender = (props) => {
- return
-
- {routes.map(({ path, component: Component = React.Fragment }) => {
if (window.isMobile) {
- if (mobileComponents[path]) {
- Component = mobileComponents[path]
- } else {
- console.warn(`No mobile component for ${path}, using default`)
+ const mobileElement = mobileRoutes.find((r) => r.path === route.path)
+
+ if (mobileElement) {
+ Element = mobileElement
}
}
- const generateRenderComponent = (props) => {
- return React.createElement(BindContexts(Component), {
- ...props,
- history: props.history,
- })
- }
-
return
- })}
-
-
-
-}
-
-export default {
- routes,
- BindContexts,
- InternalRouter,
- PageRender,
-}
\ No newline at end of file
+ })
+ }
+ } />
+
+})
\ No newline at end of file