mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-09 18:44:16 +00:00
402 lines
12 KiB
JavaScript
Executable File
402 lines
12 KiB
JavaScript
Executable File
import React from "react"
|
|
import * as antd from "antd"
|
|
import classnames from "classnames"
|
|
import { ActionSheet } from "antd-mobile"
|
|
import { Motion, spring } from "react-motion"
|
|
|
|
import { Icons, createIconRender } from "components/Icons"
|
|
|
|
import { WithPlayerContext, Context } from "contexts/WithPlayerContext"
|
|
|
|
import { QuickNavMenuItems, QuickNavMenu } from "components/Layout/quickNav"
|
|
|
|
import PlayerView from "pages/@mobile-views/player"
|
|
import CreatorView from "pages/@mobile-views/creator"
|
|
|
|
import "./index.less"
|
|
|
|
const tourSteps = [
|
|
{
|
|
title: "Open quick nav",
|
|
description: "Xd",
|
|
ref: React.createRef(),
|
|
},
|
|
{
|
|
title: "Account button",
|
|
description: "Xd",
|
|
ref: React.createRef(),
|
|
}
|
|
]
|
|
|
|
const openPlayerView = () => {
|
|
app.DrawerController.open("player", PlayerView)
|
|
}
|
|
const openCreator = () => {
|
|
app.DrawerController.open("creator", CreatorView, {
|
|
props: {
|
|
bodyStyle: {
|
|
minHeight: "unset",
|
|
height: "50vh"
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
const PlayerButton = (props) => {
|
|
React.useEffect(() => {
|
|
openPlayerView()
|
|
}, [])
|
|
|
|
return <div
|
|
className={classnames(
|
|
"player_btn",
|
|
{
|
|
"bounce": props.playback === "playing"
|
|
}
|
|
)}
|
|
style={{
|
|
"--average-color": props.colorAnalysis?.rgba,
|
|
"--color": props.colorAnalysis?.isDark ? "var(--text-color-white)" : "var(--text-color-black)",
|
|
}}
|
|
onClick={openPlayerView}
|
|
>
|
|
{
|
|
props.playback === "playing" ? <Icons.MdMusicNote /> : <Icons.MdPause />
|
|
}
|
|
</div>
|
|
}
|
|
|
|
const AccountButton = React.forwardRef((props, ref) => {
|
|
const user = app.userData
|
|
const ActionSheetRef = React.useRef()
|
|
|
|
const handleClick = () => {
|
|
if (!user) {
|
|
return app.navigation.goAuth()
|
|
}
|
|
|
|
return app.navigation.goToAccount()
|
|
}
|
|
|
|
const handleHold = () => {
|
|
ActionSheetRef.current = ActionSheet.show({
|
|
actions: [
|
|
{
|
|
key: "settings",
|
|
text: <><Icons.Settings /> <span>Settings</span></>,
|
|
onClick: () => {
|
|
app.navigation.goToSettings()
|
|
ActionSheetRef.current.close()
|
|
}
|
|
},
|
|
{
|
|
key: "account",
|
|
text: <><Icons.User /> <span>Account</span></>,
|
|
onClick: () => {
|
|
app.navigation.goToAccount()
|
|
ActionSheetRef.current.close()
|
|
}
|
|
},
|
|
{
|
|
key: "logout",
|
|
text: <><Icons.MdOutlineLogout /> <span>Logout</span></>,
|
|
danger: true,
|
|
onClick: () => {
|
|
app.eventBus.emit("app.logout_request")
|
|
ActionSheetRef.current.close()
|
|
}
|
|
}
|
|
]
|
|
})
|
|
}
|
|
|
|
return <div
|
|
key="account"
|
|
id="account"
|
|
className="item"
|
|
ref={ref}
|
|
onClick={handleClick}
|
|
onContextMenu={handleHold}
|
|
context-menu="ignore"
|
|
>
|
|
<div className="icon">
|
|
{
|
|
user ? <antd.Avatar shape="square" src={app.userData.avatar} /> : createIconRender("Login")
|
|
}
|
|
</div>
|
|
</div>
|
|
})
|
|
|
|
export default (props) => {
|
|
return <WithPlayerContext>
|
|
<BottomBar
|
|
{...props}
|
|
/>
|
|
</WithPlayerContext>
|
|
}
|
|
|
|
export class BottomBar extends React.Component {
|
|
static contextType = Context
|
|
|
|
state = {
|
|
visible: false,
|
|
quickNavVisible: false,
|
|
render: null,
|
|
tourOpen: false,
|
|
}
|
|
|
|
busEvents = {
|
|
"runtime.crash": () => {
|
|
this.toggleVisibility(false)
|
|
}
|
|
}
|
|
|
|
refs = {
|
|
homeBtn: React.createRef(),
|
|
accountBtn: React.createRef(),
|
|
}
|
|
|
|
componentDidMount = () => {
|
|
this.interface = app.layout.bottom_bar = {
|
|
toggleVisible: this.toggleVisibility,
|
|
isVisible: () => this.state.visible,
|
|
render: (fragment) => {
|
|
this.setState({ render: fragment })
|
|
},
|
|
clear: () => {
|
|
this.setState({ render: null })
|
|
},
|
|
toggleTour: () => {
|
|
this.setState({ tourOpen: !this.state.tourOpen })
|
|
},
|
|
}
|
|
|
|
setTimeout(() => {
|
|
this.setState({ visible: true })
|
|
}, 10)
|
|
|
|
// Register bus events
|
|
Object.keys(this.busEvents).forEach((key) => {
|
|
app.eventBus.on(key, this.busEvents[key])
|
|
})
|
|
}
|
|
|
|
componentWillUnmount = () => {
|
|
delete window.app.layout.bottom_bar
|
|
|
|
// Unregister bus events
|
|
Object.keys(this.busEvents).forEach((key) => {
|
|
app.eventBus.off(key, this.busEvents[key])
|
|
})
|
|
}
|
|
|
|
toggleVisibility = (to) => {
|
|
if (typeof to === "undefined") {
|
|
to = !this.state.visible
|
|
}
|
|
|
|
this.setState({ visible: to })
|
|
}
|
|
|
|
handleItemClick = (item) => {
|
|
if (item.dispatchEvent) {
|
|
app.eventBus.emit(item.dispatchEvent)
|
|
} else if (item.location) {
|
|
app.location.push(item.location)
|
|
}
|
|
}
|
|
|
|
handleNavTouchStart = (e) => {
|
|
this._navTouchStart = setTimeout(() => {
|
|
this.setState({ quickNavVisible: true })
|
|
|
|
if (app.cores.haptics?.vibrate) {
|
|
app.cores.haptics.vibrate(80)
|
|
}
|
|
|
|
// remove the timeout
|
|
this._navTouchStart = null
|
|
}, 400)
|
|
}
|
|
|
|
handleNavTouchEnd = (event) => {
|
|
if (this._lastHovered) {
|
|
this._lastHovered.classList.remove("hover")
|
|
}
|
|
|
|
if (this._navTouchStart) {
|
|
clearTimeout(this._navTouchStart)
|
|
|
|
this._navTouchStart = null
|
|
|
|
return false
|
|
}
|
|
|
|
this.setState({ quickNavVisible: false })
|
|
|
|
// get cords of the touch
|
|
const x = event.changedTouches[0].clientX
|
|
const y = event.changedTouches[0].clientY
|
|
|
|
// get the element at the touch
|
|
const element = document.elementFromPoint(x, y)
|
|
|
|
// get the closest element with the attribute
|
|
const closest = element.closest(".quick-nav_item")
|
|
|
|
if (!closest) {
|
|
return false
|
|
}
|
|
|
|
const item = QuickNavMenuItems.find((item) => {
|
|
return item.id === closest.getAttribute("quicknav-item")
|
|
})
|
|
|
|
if (!item) {
|
|
return false
|
|
}
|
|
|
|
if (item.location) {
|
|
app.location.push(item.location)
|
|
|
|
if (app.cores.haptics?.vibrate) {
|
|
app.cores.haptics.vibrate([40, 80])
|
|
}
|
|
}
|
|
}
|
|
|
|
handleNavTouchMove = (event) => {
|
|
// check if the touch is hovering a quicknav item
|
|
const x = event.changedTouches[0].clientX
|
|
const y = event.changedTouches[0].clientY
|
|
|
|
// get the element at the touch
|
|
const element = document.elementFromPoint(x, y)
|
|
|
|
// get the closest element with the attribute
|
|
const closest = element.closest("[quicknav-item]")
|
|
|
|
if (!closest) {
|
|
if (this._lastHovered) {
|
|
this._lastHovered.classList.remove("hover")
|
|
}
|
|
|
|
this._lastHovered = null
|
|
|
|
return false
|
|
}
|
|
|
|
if (this._lastHovered !== closest) {
|
|
if (this._lastHovered) {
|
|
this._lastHovered.classList.remove("hover")
|
|
}
|
|
|
|
this._lastHovered = closest
|
|
|
|
closest.classList.add("hover")
|
|
|
|
if (app.cores.haptics?.vibrate) {
|
|
app.cores.haptics.vibrate(40)
|
|
}
|
|
}
|
|
}
|
|
|
|
toggleTour = (to) => {
|
|
if (typeof to === "undefined") {
|
|
to = !this.state.tourOpen
|
|
}
|
|
|
|
this.setState({
|
|
tourOpen: to
|
|
})
|
|
}
|
|
|
|
render() {
|
|
if (this.state.render) {
|
|
return <div className="bottomBar">
|
|
{this.state.render}
|
|
</div>
|
|
}
|
|
|
|
const heightValue = this.state.visible ? Number(app.cores.style.defaultVar("bottom-bar-height").replace("px", "")) : 0
|
|
|
|
return <>
|
|
<QuickNavMenu
|
|
visible={this.state.quickNavVisible}
|
|
/>
|
|
|
|
<Motion style={{
|
|
y: spring(this.state.visible ? 0 : 300),
|
|
height: spring(heightValue)
|
|
}}>
|
|
{({ y, height }) =>
|
|
<div className="bottomBar_wrapper">
|
|
<div
|
|
className="bottomBar"
|
|
style={{
|
|
WebkitTransform: `translateY(${y}px)`,
|
|
transform: `translateY(${y}px)`,
|
|
height: `${height}px`,
|
|
}}
|
|
>
|
|
<div className="items">
|
|
<div
|
|
key="creator"
|
|
id="creator"
|
|
className={classnames("item", "primary")}
|
|
onClick={openCreator}
|
|
>
|
|
<div className="icon">
|
|
{createIconRender("PlusCircle")}
|
|
</div>
|
|
</div>
|
|
|
|
{
|
|
this.context.currentManifest && <div
|
|
className="item"
|
|
>
|
|
<PlayerButton
|
|
manifest={this.context.currentManifest}
|
|
playback={this.context.playbackStatus}
|
|
colorAnalysis={this.context.coverColorAnalysis}
|
|
/>
|
|
</div>
|
|
}
|
|
|
|
<div
|
|
key="navigator"
|
|
id="navigator"
|
|
className="item"
|
|
onClick={() => app.location.push("/")}
|
|
onTouchMove={this.handleNavTouchMove}
|
|
onTouchStart={this.handleNavTouchStart}
|
|
onTouchEnd={this.handleNavTouchEnd}
|
|
onTouchCancel={() => {
|
|
this.setState({ quickNavVisible: false })
|
|
}}
|
|
>
|
|
<div className="icon">
|
|
{createIconRender("Home")}
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
key="searcher"
|
|
id="searcher"
|
|
className="item"
|
|
onClick={app.controls.openSearcher}
|
|
>
|
|
<div className="icon">
|
|
{createIconRender("Search")}
|
|
</div>
|
|
</div>
|
|
|
|
<AccountButton/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
</Motion>
|
|
</>
|
|
}
|
|
} |