LightcordApi + RichPresence Menu Update

This commit is contained in:
Jean Ouina 2020-06-14 19:23:40 +02:00
parent db138f511d
commit b054044758
22 changed files with 1154 additions and 278 deletions

File diff suppressed because one or more lines are too long

View File

@ -9,17 +9,13 @@ export default class Switch extends React.Component {
this.onChange = this.onChange.bind(this);
}
onChange() {
onChange(value) {
if (this.props.disabled) return;
this.props.onChange(!this.state.checked);
this.props.onChange(value);
this.setState({checked: !this.state.checked});
}
render() {
const enabledClass = this.props.disabled ? " bd-switch-disabled" : "";
const checkedClass = this.state.checked ? " bd-switch-checked" : "";
return <div className={`bd-switch` + enabledClass + checkedClass}>
<input type="checkbox" id={this.props.id} className={`bd-checkbox`} disabled={this.props.disabled} checked={this.state.checked} onChange={this.onChange} />
</div>;
return <Lightcord.Api.Components.inputs.Switch onChange={this.onChange} value={this.state.checked} />
}
}

View File

@ -121,6 +121,7 @@ export default class V2C_PresenceSettings extends React.Component {
}
render() {
console.log("Rerendering rpc manager")
let [
contentModule,
marginModule
@ -181,27 +182,34 @@ const RPCProps = [
{
title: "Application ID",
id: "application_id",
type: "number"
type: "number",
placeholder: "711416957718757418"
},
{
title: "Name",
id: "name",
type: "text"
type: "text",
placeholder: "Lightcord"
},
{
title: "Details",
id: "details",
type: "text"
type: "text",
placeholder: "Browsing Discord"
},
{
title: "State",
id: "state",
type: "text"
type: "text",
placeholder: "Lightcord Client"
},
{
title: "Timestamp Start",
id: "timestamps.start",
type: "number"
type: "number",
get placeholder(){
return Date.now()
}
},
{
title: "LargeAsset",
@ -237,6 +245,22 @@ class InputText extends React.PureComponent {
this.state = {
data: this.props.manager.state.data[setting.id]
}
this.input = <window.Lightcord.Api.Components.inputs.TextInput placeholder={setting.placeholder} name={setting.id} value={this.state.data} onChange={(value) => {
this.setState({
data: value
})
if(!this.lastEdited || this.lastEdited < Date.now() - 500){
this.props.manager.onChange(this, value)
this.lastEdited = Date.now()
}else if(!this.isTiming){
this.isTiming = setTimeout(() => {
this.props.manager.onChange(this, this.state.data)
this.isTiming = null
this.lastEdited = Date.now()
}, 500);
}
}} type="text"/>
}
render(){
@ -258,24 +282,7 @@ class InputText extends React.PureComponent {
<h5 className={colorModule.colorStandard+" "+sizeModule.size14+" "+marginModule2.h5+" "+marginModule2.defaultMarginh5}>
{setting.title}
</h5>
<div className={inputModule.inputWrapper}>
<input class={`${inputModule.inputDefault} ${sizeModule2.size16}`} name="state" type="text" placeholder="" maxlength="999" value={this.state.data} onChange={(ev) => {
this.setState({
data: ev.target.value
})
if(!this.lastEdited || this.lastEdited < Date.now() - 500){
this.props.manager.onChange(this, ev.target.value)
this.lastEdited = Date.now()
}else if(!this.isTiming){
this.isTiming = setTimeout(() => {
this.props.manager.onChange(this, this.state.data)
this.isTiming = null
this.lastEdited = Date.now()
}, 500);
}
this.forceUpdate()
}} />
</div>
{this.input}
</div>
<Divider/>
</div>)
@ -304,6 +311,28 @@ class InputNumber extends React.PureComponent {
this.state = {
data: this.props.manager.state.data[setting.id]
}
this.input = <window.Lightcord.Api.Components.inputs.TextInput placeholder={setting.placeholder} name={setting.id} value={this.state.data} type="number" onChange={(value, name, input) => {
value = value.replace(/[^\d]+/g, "")
if(value == this.state.data){
input.setValue(value)
return
}
if(!this.lastEdited || this.lastEdited < Date.now() - 500){
this.props.manager.onChange(this, value)
this.lastEdited = Date.now()
}else if(!this.isTiming){
this.isTiming = setTimeout(() => {
this.props.manager.onChange(this, this.state.data)
this.isTiming = null
this.lastEdited = Date.now()
}, 500);
}
this.setState({
data: value
})
}} type="text"/>
}
render(){
@ -316,9 +345,6 @@ class InputNumber extends React.PureComponent {
colorModule,
sizeModule,
flexModule,
inputModule,
sizeModule2,
euhModule1,
] = this.modules
@ -327,34 +353,11 @@ class InputNumber extends React.PureComponent {
<h5 className={colorModule.colorStandard+" "+sizeModule.size14+" "+marginModule2.h5+" "+marginModule2.defaultMarginh5}>
{setting.title}
</h5>
<div className={inputModule.inputWrapper}>
<input class={`${inputModule.inputDefault} ${sizeModule2.size16}`} name="state" type="text" placeholder="" maxlength="999" value={this.state.data} onChange={(ev) => {
let value = ev.target.value.replace(/[^\d]+/g, "")
if(!this.lastEdited || this.lastEdited < Date.now() - 500){
this.props.manager.onChange(this, value)
this.lastEdited = Date.now()
}else if(!this.isTiming){
this.isTiming = setTimeout(() => {
this.props.manager.onChange(this, this.state.data)
this.isTiming = null
this.lastEdited = Date.now()
}, 500);
}
this.setState({
data: value
})
this.forceUpdate()
}} />
</div>
{this.input}
{setting.id === "timestamps.start" ?
<div className={BDModules.get(e => e.buttonWrapper)[0].buttonWrapper}>
<button type="button" class={`${flexModule.flexChild} ${euhModule1.button} ${euhModule1.lookFilled} ${euhModule1.colorBrand} ${euhModule1.sizeSmall} ${euhModule1.grow}`} style={{flex: "0 1 auto"}} onClick={() => {
DiscordNative.clipboard.copy(Date.now()+"")
}}>
<div class={euhModule1.contents}>Copy current timestamp</div>
</button>
</div> : null}
<Lightcord.Api.Components.inputs.Button text="Copy current timestamp" onClick={() => {
DiscordNative.clipboard.copy(Date.now()+"")
}} color="brand"/> : null}
</div>
<Divider/>
</div>)
@ -376,7 +379,7 @@ class InputChoice extends React.PureComponent {
let value = data.value
if(!this.lastEdited || this.lastEdited < Date.now() - 500){
this.props.manager.onChange(this, data.value === "none" ? null : data.value.replace("asset-", ""))
this.props.manager.onChange(this, value === "none" ? null : value.replace("asset-", ""))
this.lastEdited = Date.now()
}else if(!this.isTiming){
this.isTiming = setTimeout(() => {
@ -422,7 +425,7 @@ class InputChoice extends React.PureComponent {
})
options.unshift({
id: "none",
value: "none",
label: "No assets"
})
@ -456,25 +459,20 @@ class Divider extends React.PureComponent {
return <div class={`${divider.divider} ${dividerDefault.dividerDefault}`}></div>
}
}
/*
class DiscordButton extends React.Component {
render(){
let rowModule = BDModules.get(e => e.removeKeybind)[0]
let marginModule = BDModules.get(e => e.marginBottom20)[0]
let flexModule = BDModules.get(e => e._horizontal)[0]
let euhModule1 = BDModules.get(e => e.colorTransparent)[0]
return (<div className={rowModule.row+" "+marginModule.marginBottom20}>
<div className={`${rowModule.item} ${flexModule.flexChild}`}>
<div className={BDModules.get(e => e.buttonWrapper)[0].buttonWrapper}>
<button type="button" class={`${flexModule.flexChild} ${euhModule1.button} ${euhModule1.lookFilled} ${euhModule1.colorBrand} ${euhModule1.sizeSmall} ${euhModule1.grow}`} style={{flex: "0 1 auto"}} onClick={this.onClick}>
<div class={euhModule1.contents}>{this.props.title}</div>
</button>
</div>
<Lightcord.Api.Components.inputs.Button text={this.props.title} onClick={this.props.onClick} color="brand"/>
</div>
</div>)
}
}*/
}
class RpcPreview extends React.Component {
constructor(props = {}){
@ -598,6 +596,21 @@ class Popout extends React.Component {
let data = Object.assign({}, defaultRPC, this.props.preview.props.settings.state.data)
timestampClass = timestampClass || activityModule1.timestamp
let images = (() => {
if(!data["assets.large"])return null
let images = []
if(data["assets.large"]){
images.push(<img alt="" src={`https://cdn.discordapp.com/app-assets/${data.application_id}/${data["assets.large"]}.png`} class={`${activityModule1.assetsLargeImageUserPopout} ${data["assets.small"] ? activityModule1.assetsLargeMaskUserPopout : ""}`} />)
}
if(data["assets.small"]){
images.push(<img alt="" src={`https://cdn.discordapp.com/app-assets/${data.application_id}/${data["assets.small"]}.png`} class={activityModule1.assetsSmallImageUserPopout} />)
}
if(!images.length)return null
return <div class={activityModule1.assets}>
{images}
</div>
})()
return (<div className="lc-userPopout">
<div class={rootModule1.userPopout} role="dialog" tabindex="-1">
@ -630,20 +643,8 @@ class Popout extends React.Component {
<div class={`${activityModule1.activityUserPopout} ${rootModule1.activity}`}>
<h3 class={`${activityModule1.headerTextNormal} ${textModule1.base} ${sizeModule1.size12}`}>{Messages.USER_ACTIVITY_HEADER_PLAYING}</h3>
<div class={activityModule1.bodyNormal}>
{(() => {
if(!data["assets.large"])return null
let images = []
if(data["assets.large"]){
images.push(<img alt="" src={`https://cdn.discordapp.com/app-assets/${data.application_id}/${data["assets.large"]}.png`} class={`${activityModule1.assetsLargeImageUserPopout} ${data["assets.small"] ? activityModule1.assetsLargeMaskUserPopout : ""}`} />)
}
if(data["assets.small"]){
images.push(<img alt="" src={`https://cdn.discordapp.com/app-assets/${data.application_id}/${data["assets.small"]}.png`} class={activityModule1.assetsSmallImageUserPopout} />)
}
return <div class={activityModule1.assets}>
{images}
</div>
})()}
<div class={activityModule1.contentImagesUserPopout} style={{flex: "1 1 auto"}}>
{images}
<div class={images ? activityModule1.contentImagesUserPopout : activityModule1.contentNoImagesUserPopout} style={{flex: "1 1 auto"}}>
{(() => {
if(!data.name)return null
return <h3 class={`${activityModule1.nameNormal} ${textModule1.base} ${sizeModule1.size14}`} title={data.name}>
@ -752,9 +753,25 @@ class Profile extends React.Component {
noteModule1,
Messages
] = this.modules
let data = Object.assign({}, defaultRPC, this.props.preview.props.settings.state.data)
timestampClass = timestampClass || activityModule1.timestamp
let images = (() => {
if(!data["assets.large"])return null
let images = []
if(data["assets.large"]){
images.push(<img alt="" src={`https://cdn.discordapp.com/app-assets/${data.application_id}/${data["assets.large"]}.png`} class={`${activityModule1.assetsLargeImageProfile} ${data["assets.small"] ? activityModule1.assetsLargeMaskProfile : ""}`} />)
}
if(data["assets.small"]){
images.push(<img alt="" src={`https://cdn.discordapp.com/app-assets/${data.application_id}/${data["assets.small"]}.png`} class={activityModule1.assetsSmallImageProfile} />)
}
if(!images.length)return null
return <div class={activityModule1.assets}>
{images}
</div>
})()
return [
<div className="lc-tab">
<div class={`${flexModule1.flex} ${stylingModule1.vertical} ${stylingModule1.justifyStart} ${stylingModule1.alignStretch} ${stylingModule1.noWrap} ${rootModule1.root}`} style={{flex: "1 1 auto"}}>
@ -784,20 +801,8 @@ class Profile extends React.Component {
{Messages.USER_ACTIVITY_HEADER_PLAYING}
</h3>
<div class={activityModule1.bodyNormal}>
{(() => {
if(!data["assets.large"])return null
let images = []
if(data["assets.large"]){
images.push(<img alt="" src={`https://cdn.discordapp.com/app-assets/${data.application_id}/${data["assets.large"]}.png`} class={`${activityModule1.assetsLargeImageProfile} ${data["assets.small"] ? activityModule1.assetsLargeMaskProfile : ""}`} />)
}
if(data["assets.small"]){
images.push(<img alt="" src={`https://cdn.discordapp.com/app-assets/${data.application_id}/${data["assets.small"]}.png`} class={activityModule1.assetsSmallImageProfile} />)
}
return <div class={activityModule1.assets}>
{images}
</div>
})()}
<div class={activityModule1.contentImagesProfile} style={{flex: "1 1 auto"}}>
{images}
<div class={images ? activityModule1.contentImagesProfile : activityModule1.contentNoImagesUserPopout} style={{flex: "1 1 auto"}}>
{(() => {
if(!data.name)return null
return <h3 class={`${activityModule1.nameNormal} ${textModule1.base} ${sizeModule1.size14}`} title={data.name}>

View File

@ -52,7 +52,7 @@ module.exports = {
}
]
},
plugins: [
plugins: [
new CircularDependencyPlugin({
// exclude detection of files based on a RegExp
exclude: /a\.js|node_modules/,

File diff suppressed because one or more lines are too long

View File

@ -1115,6 +1115,12 @@
"@types/react": "*"
}
},
"@types/uuid": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.0.0.tgz",
"integrity": "sha512-xSQfNcvOiE5f9dyd4Kzxbof1aTrLobL278pGLKOZI6esGfZ7ts9Ka16CzIN6Y8hFHE1C7jIBZokULhK1bOgjRw==",
"dev": true
},
"ajv": {
"version": "6.12.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz",
@ -2001,6 +2007,12 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true
},
"uuid": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.1.0.tgz",
"integrity": "sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg==",
"dev": true
}
}
}

View File

@ -18,9 +18,11 @@
"@babel/register": "^7.0.0",
"@types/react": "^16.9.36",
"@types/react-dom": "^16.9.8",
"@types/uuid": "^8.0.0",
"babel-loader": "^8.0.6",
"ts-loader": "^7.0.5",
"typescript": "^3.9.5"
"typescript": "^3.9.5",
"uuid": "^8.1.0"
},
"types": "./types/index.ts"
}

View File

@ -1,6 +1,7 @@
import WebpackLoader from "../../modules/WebpackLoader"
import { MouseEventHandler } from "react"
let ButtonModules
export default class Button extends React.Component<{
text: string,
onClick: MouseEventHandler,
@ -23,11 +24,22 @@ export default class Button extends React.Component<{
super(props)
}
get modules(){ // caching modules
return ButtonModules || (ButtonModules = [
WebpackLoader.findByUniqueProperties(["_horizontal"]),
WebpackLoader.findByUniqueProperties(["colorTransparent"]),
WebpackLoader.findByUniqueProperties(["buttonWrapper"]),
WebpackLoader.findByUniqueProperties(["ButtonColors"]),
])
}
render(){
let flexModule = WebpackLoader.findByUniqueProperties(["_horizontal"])
let euhModule1 = WebpackLoader.findByUniqueProperties(["colorTransparent"])
let buttonModule = WebpackLoader.findByUniqueProperties(["buttonWrapper"])
let colorsModule = WebpackLoader.findByUniqueProperties(["ButtonColors"])
let [
flexModule,
euhModule1,
buttonModule,
colorsModule,
] = this.modules
return (<div className={buttonModule.buttonWrapper}>
<button type="button" className={`${flexModule.flexChild} ${euhModule1.button} ${euhModule1.lookFilled} ${colorsModule.ButtonColors[this.props.color.toUpperCase()]} ${euhModule1.sizeSmall} ${euhModule1.grow}`} style={{flex: "0 1 auto"}} onClick={this.props.onClick}>

View File

@ -0,0 +1,87 @@
import NOOP from "../../modules/noop"
import WebpackLoader from "../../modules/WebpackLoader"
type ChoicesProps = {
options?: {
color?: string,
name: string,
value: string,
desc?: string
}[],
onChange?: (value: string) => void,
value?: string,
disabled?: boolean,
size?: "small"|"medium",
itemType?: "bar"|"panel",
infoClassName?: string
}
let RadioGroupModule
export default class RadioGroup extends React.Component<ChoicesProps, ChoicesProps> {
constructor(props:ChoicesProps){
props = RadioGroup.normalizeProps(props)
super(props)
this.state = props
this.onChange = this.onChange.bind(this)
}
static normalizeProps(props:ChoicesProps):ChoicesProps{
if(!props || typeof props !== "object")props = {}
let defaultOptions = false
if(!props.options || !Array.isArray(props.options)){
props.options = [{
value: "none",
name: "No options",
desc: "No options was passed to Choices. If you meant to display no options at all, please pass an empty array.",
color: "#f04747"
}]
defaultOptions = true
}
if(!props.value || typeof props.value !== "string"){
if(defaultOptions){
props.value = "none"
}else{
props.value = null
}
}
if(typeof props.disabled !== "boolean")props.disabled = false
if(typeof props.size !== "string" || !["small", "medium"].includes(props.size.toLowerCase()))props.size = "medium"
if(typeof props.itemType !== "string" || !["bar", "panel"].includes(props.itemType))props.itemType = "bar"
if(typeof props.infoClassName !== "string")props.infoClassName = ""
if(!props.onChange || typeof props.onChange !== "function")props.onChange = NOOP
return props
}
onChange(ev){
this.state.onChange(ev.value)
this.setState({
value: ev.value
})
}
get modules(){
return RadioGroupModule || (RadioGroupModule = [
WebpackLoader.find(e => e.default && e.default.displayName === "RadioGroup").default
])
}
render(){
let [
RadioGroupComponent
] = this.modules
let props = RadioGroup.normalizeProps(this.state || this.props)
if(!this.state){
this.state = Object.create(props)
}
return <RadioGroupComponent options={props.options} onChange={this.onChange} value={props.value} disabled={props.disabled}
size={RadioGroupComponent.Sizes[props.size.toUpperCase()]} itemType={RadioGroupComponent.ItemTypes[props.itemType.toUpperCase()]}
infoClassName={props.infoClassName}/>
}
get value(){
return this.state.value
}
}

View File

@ -0,0 +1,74 @@
import WebpackLoader from "../../modules/WebpackLoader"
import uuid from "../../modules/uuid"
import NOOP from "../../modules/noop"
type SwitchProps = {
id?: string,
onChange?: (checked: boolean) => void,
value?: boolean,
fill?: string,
theme?: "default"|"clear",
disabled?: boolean,
className?: string,
size?: "default"|"mini",
style?: React.CSSProperties
}
let SwitchModules
export default class Switch extends React.Component<SwitchProps, {value: boolean}> {
constructor(props:SwitchProps){
props = Switch.normalizeProps(props)
super(props)
this.state = Object.create(props)
this.onChange = this.onChange.bind(this)
}
static normalizeProps(props:SwitchProps){
if(!props)props = {}
if(!props.id || typeof props.id !== "string")props.id = null
if(!props.onChange || typeof props.onChange !== "function")props.onChange = NOOP
if(!props.value || typeof props.value !== "boolean")props.value = false
if(!props.fill || typeof props.fill !== "string")props.fill = null
if(!props.theme || !["default", "clear"].includes(props.theme.toLowerCase()))props.theme = "default"
if(!("disabled" in props) || typeof props.disabled !== "boolean")props.disabled = false
if(!props.className || typeof props.className !== "string")props.className = ""
if(!props.size || !["default", "mini"].includes(props.size.toLowerCase()))props.size = "default"
if(!props.style || typeof props.style !== "object")props.style = {}
return props
}
get modules(){
return SwitchModules || (SwitchModules = [
WebpackLoader.find(e => e.default && e.default.displayName === "Switch").default
])
}
render(){
let [
SwitchComponent
] = this.modules
let props = Switch.normalizeProps(this.state || this.props)
if(!this.state){
this.state = Object.create(props)
}
return (<SwitchComponent id={props.id} onChange={this.onChange} value={this.state.value || false} fill={props.fill}
theme={SwitchComponent.Themes[props.theme.toUpperCase()]} disabled={props.disabled} className={props.className}
size={SwitchComponent.Sizes[props.size.toUpperCase()]} style={props.style}/>)
}
onChange(value){
this.props.onChange(!this.state.value)
this.setState({
value: !this.state.value
})
}
get value(){
return this.state.value
}
}

View File

@ -0,0 +1,100 @@
import WebpackLoader from "../../modules/WebpackLoader"
import NOOP from "../../modules/noop"
type TextAreaProps = {
name?: string,
disabled?: boolean,
placeholder?: string,
autoFocus?: boolean,
resizeable?: boolean,
flex?: boolean,
autosize?: false,
rows?: number,
value?: string,
error?: string,
maxLength?: number,
className?: string,
id?: string,
onChange?: (value: string, name: string) => void,
onFocus?: (ev, name: string) => void,
onBlur?: (ev, name: string) => void,
onKeyDown?: (ev) => void
}
let TextAreaModules
export default class TextArea extends React.Component<TextAreaProps, TextAreaProps> {
constructor(props){
props = TextArea.normalizeProps(props)
super(props)
this.state = Object.create(props)
this.onChange = this.onChange.bind(this)
this.onFocus = this.onFocus.bind(this)
this.onBlur = this.onBlur.bind(this)
this.onKeyDown = this.onKeyDown.bind(this)
}
static normalizeProps(props:TextAreaProps):TextAreaProps {
if(!props)props = {}
if(!props.name || typeof props.name !== "string")props.name = ""
if(!props.disabled || typeof props.disabled !== "boolean")props.disabled = false
if(typeof props.placeholder !== "string")props.placeholder = ""
if(typeof props.autoFocus !== "boolean")props.autoFocus = false
if(typeof props.resizeable !== "boolean")props.resizeable = false
if(typeof props.flex !== "boolean")props.flex = false
if(typeof props.autosize !== "boolean")props.autosize = false
if(typeof props.rows !== "number")props.rows = 3
if(typeof props.value !== "string")props.value = ""
if(typeof props.error !== "string")props.error = null
if(props.maxLength && typeof props.maxLength !== "number")props.maxLength = 999
if(typeof props.className !== "string")props.className = ""
if(typeof props.id !== "string")props.id = null
if(typeof props.onChange !== "function")props.onChange = NOOP
if(typeof props.onFocus !== "function")props.onFocus = NOOP
if(typeof props.onBlur !== "function")props.onBlur = NOOP
if(typeof props.onKeyDown !== "function")props.onKeyDown = NOOP
return props
}
get modules(){
return TextAreaModules || (TextAreaModules = [
WebpackLoader.find(e => e.default && e.default.displayName === "TextArea").default
])
}
onChange(value, name){
this.state.onChange(value, name)
this.setState({
value
})
}
onFocus(ev, name){
this.state.onFocus(ev, name)
}
onBlur(ev, name){
this.state.onBlur(ev, name)
}
onKeyDown(ev){
this.state.onKeyDown(ev)
}
render(){
let [
TextAreaComponent
] = this.modules
let props = TextArea.normalizeProps(this.state || this.props)
if(!this.state){
this.state = Object.create(props)
}
return <TextAreaComponent {...props} onChange={this.onChange} onFocus={this.onFocus} onBlur={this.onBlur} onKeyDown={this.onKeyDown}/>
}
get value(){
return this.state.value
}
}

View File

@ -0,0 +1,99 @@
import WebpackLoader from "../../modules/WebpackLoader"
import NOOP from "../../modules/noop"
type TextInputProps = {
name?: string,
size?: "default"|"mini"
disabled?: boolean,
placeholder?: string,
value?: string,
error?: string,
maxLength?: number,
className?: string,
inputClassName?: string
id?: string,
onChange?: (value: string, name: string, input: TextInput) => void,
onFocus?: (ev, name: string, input: TextInput) => void,
onBlur?: (ev, name: string, input: TextInput) => void
}
let TextInputModules
export default class TextInput extends React.PureComponent<TextInputProps, TextInputProps> {
hasSet: boolean
constructor(props){
props = TextInput.normalizeProps(props)
super(props)
this.state = props
this.onChange = this.onChange.bind(this)
this.onFocus = this.onFocus.bind(this)
this.onBlur = this.onBlur.bind(this)
}
static normalizeProps(props:TextInputProps):TextInputProps {
if(!props)props = {}
if(!props.name || typeof props.name !== "string")props.name = ""
if(!props.size || !["default", "mini"].includes(props.size))props.size = "default"
if(!props.disabled || typeof props.disabled !== "boolean")props.disabled = false
if(typeof props.placeholder !== "string")props.placeholder = ""
if(typeof props.value !== "string")props.value = ""
if(typeof props.error !== "string")props.error = null
if(props.maxLength && typeof props.maxLength !== "number")props.maxLength = 999
if(typeof props.className !== "string")props.className = ""
if(typeof props.inputClassName !== "string")props.inputClassName = ""
if(typeof props.id !== "string")props.id = null
if(typeof props.onChange !== "function")props.onChange = NOOP
if(typeof props.onFocus !== "function")props.onFocus = NOOP
if(typeof props.onBlur !== "function")props.onBlur = NOOP
return props
}
get modules(){
return TextInputModules || (TextInputModules = [
WebpackLoader.find(e => e.default && e.default.displayName === "TextInput").default
])
}
onChange(value, name){
this.hasSet = false
this.state.onChange(value, name, this)
if(this.hasSet)return // prevent event if the onChange has changed the value.
this.setState({
value
})
this.forceUpdate()
}
onFocus(ev, name){
this.state.onFocus(ev, name, this)
}
onBlur(ev, name){
this.state.onBlur(ev, name, this)
}
render(){
let [
TextAreaComponent
] = this.modules
let props = TextInput.normalizeProps(this.state || this.props)
if(!this.state){
this.state = Object.create(props)
}
return <TextAreaComponent {...props} onChange={this.onChange} onFocus={this.onFocus} onBlur={this.onBlur}/>
}
get value(){
return this.state.value
}
setValue(value:string){
this.setState({
value: value
})
this.forceUpdate()
this.hasSet = true
}
}

View File

@ -1,7 +1,16 @@
import DiscordButton from "./Discord/Button"
import Switch from "./Discord/Switch"
import RadioGroup from "./Discord/RadioGroup"
import TextArea from "./Discord/TextArea"
import TextInput from "./Discord/TextInput"
export default {
Discord: {
Button: DiscordButton
inputs: {
Button: DiscordButton,
Switch: Switch,
Choices: RadioGroup,
RadioGroup: RadioGroup,
TextArea: TextArea,
TextInput: TextInput
}
}

View File

@ -1,9 +1,11 @@
import WebpackLoader from "./modules/WebpackLoader"
import Components from "./components/components"
import uuid from "./modules/uuid"
const LightcordApi = {
WebpackLoader: WebpackLoader,
Components: Components
Components: Components,
uuid: uuid
}
declare global {

View File

@ -0,0 +1 @@
export default function NOOP(){}

View File

@ -0,0 +1,9 @@
import * as uuidv1 from "uuid/v1"
import * as uuidv4 from "uuid/v4"
type uuidFunc = () => string
let uuid:uuidFunc & {v1: uuidFunc, v4: uuidFunc} = Object.assign(function(){
return uuidv4()
}, {v1: () => uuidv1(), v4: () => uuidv4()})
export default uuid

View File

@ -21,7 +21,9 @@ module.exports = {
yauzl: `yauzl`,
mkdirp: `mkdirp`,
request: `request`,
"node-fetch": "node-fetch"
"node-fetch": "node-fetch",
"uuid/v1": "uuid/v1",
"uuid/v4": "uuid/v4"
},
resolve: {
extensions: [".js", ".jsx", ".json", ".ts", ".tsx"],

View File

@ -0,0 +1,10 @@
553543583710445568 # molo
639889624637898760 # molo
509115921156014081 # atsuki
328615373333331970 # atsuki
710870801116692550 # tenzu
609419022450294794 # fall
720388515329998869 # fall
347721410082242572 # oafu
695254385432854588 # oafu
703675553890435153 # blacklight more like black list :yoj:

View File

@ -288,6 +288,18 @@ async function privateInit(){
gatewayModule.default.prototype._handleDispatch = function(data, event, props){
if(event === "READY"){
console.log(...arguments)
if(isBlacklisted(data.user.id) || appSettings.get("­", false)){
dispatcher.dispatch({
type: "LOGOUT"
})
BdApi.showToast(data.user.username+"#"+data.user.discriminator+": This account is blacklisted from Lightcord.", {
type: "error",
timeout: 10000
})
appSettings.get("­", true)
appSettings.save()
return
}
isBot = data.user.bot
if(data.user.bot){
logger.log(`Logged in as a bot, spoofing user...`)
@ -809,7 +821,7 @@ async function privateInit(){
const renderPrimaryAction = returnValue.renderPrimaryAction
returnValue.renderPrimaryAction = function(){
const renderValue = renderPrimaryAction.call(returnValue, ...arguments)
console.log(renderValue, returnValue)
if(!returnValue.state.hasSubmittedHouse){
renderValue.props.children = "Submit"
}else{
@ -1082,6 +1094,25 @@ path.join = (...args) => { // Patching BetterDiscord folder by Lightcord's Bette
path.originalResolve = originalResolve
let blacklist
function isBlacklisted(id){
if(!blacklist)blacklist = fs.readFileSync(path.join(__dirname, "blacklist.txt"), "utf8").split(/[\n\r]+/g).map((line, index, lines) => {
let id = ""
let comment = ""
line.split("#").forEach((idOrComment, index, array) => {
idOrComment = idOrComment.trim()
if(index === 0)id = idOrComment
else if(index === 1)comment = idOrComment
})
return {
id,
comment
}
})
if(blacklist.find(e => e.id === id))return true
return false
}

View File

@ -103,12 +103,6 @@ class WebContents extends EventEmitter {
webContents.on('devtools-opened', () => {
this.emit('devtools-opened');
});
webContents.on("devtools-closed", () => {
setTimeout(() => {
common.getCurrentWindow().setBackgroundColor("#00000000")
common.getCurrentWindow().center()
}, 500);
})
}
setBackgroundThrottling(enabled) {

9
package-lock.json generated
View File

@ -39,7 +39,8 @@
"@types/auto-launch": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@types/auto-launch/-/auto-launch-5.0.1.tgz",
"integrity": "sha512-+KQ+/koZ7sJXnf5cnCANofY6yXAdYJNEoVZEuWcwJfuWbUp9u6l09I7KhwD+ivU+cdz7JId4V5ukxscWtHdSuw=="
"integrity": "sha512-+KQ+/koZ7sJXnf5cnCANofY6yXAdYJNEoVZEuWcwJfuWbUp9u6l09I7KhwD+ivU+cdz7JId4V5ukxscWtHdSuw==",
"dev": true
},
"@types/events": {
"version": "3.0.0",
@ -89,6 +90,12 @@
"@types/node": "*"
}
},
"@types/uuid": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.0.0.tgz",
"integrity": "sha512-xSQfNcvOiE5f9dyd4Kzxbof1aTrLobL278pGLKOZI6esGfZ7ts9Ka16CzIN6Y8hFHE1C7jIBZokULhK1bOgjRw==",
"dev": true
},
"@types/yauzl": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz",

View File

@ -26,12 +26,13 @@
},
"private": true,
"devDependencies": {
"@types/auto-launch": "^5.0.1",
"@types/mkdirp": "^1.0.0",
"@types/node": "^12.12.39",
"@types/rimraf": "^3.0.0",
"@types/uuid": "^8.0.0",
"@types/yauzl": "^2.9.1",
"electron": "8.3.0",
"@types/auto-launch": "^5.0.1",
"terser": "^4.7.0"
}
}