Package installer & install modal

This commit is contained in:
Jiiks 2018-08-29 06:19:18 +03:00
parent 76d54f0a95
commit cff425f916
8 changed files with 248 additions and 7 deletions

View File

@ -12,6 +12,7 @@ import { ClientLogger as Logger } from 'common';
import { SocketProxy, EventHook, CssEditor } from 'modules';
import { ProfileBadges, ClassNormaliser } from 'ui';
import Updater from './updater';
import PackageInstaller from './packageinstaller';
/**
* Module Manager initializes all modules when everything is ready
@ -28,7 +29,8 @@ export default class {
new SocketProxy(),
new EventHook(),
CssEditor,
Updater
Updater,
new PackageInstaller()
]);
}

View File

@ -0,0 +1,60 @@
import EventListener from './eventlistener';
import asar from 'asar';
import { Modals } from 'ui';
import { Utils } from 'common';
export default class extends EventListener {
get eventBindings() {
return [
{ id: 'install-pkg', callback: this.installPackage }
];
}
async installPackage(pkg, upload) {
try {
const config = JSON.parse(asar.extractFile(pkg.path, 'config.json').toString());
const { info, main } = config;
let icon = null;
if (info.icon && info.icon_type) {
const extractIcon = asar.extractFile(pkg.path, info.icon);
icon = `data:${info.icon_type};base64,${Utils.arrayBufferToBase64(extractIcon)}`;
}
if (icon) config.iconEncoded = icon;
const isPlugin = info.type && info.type === 'plugin' || main.endsWith('.js');
/*
config.permissions = [
{
HEADER: 'Test Permission Header',
BODY: 'Test Permission Body'
},
{
HEADER: 'Test Permission Header',
BODY: 'Test Permission Body'
},
{
HEADER: 'Test Permission Header',
BODY: 'Test Permission Body'
},
{
HEADER: 'Test Permission Header',
BODY: 'Test Permission Body'
}
];
*/
// Show install modal
const modalResult = await Modals.installModal(`Install BetterDiscord ${isPlugin ? 'Plugin' : 'Theme'}`, config).promise;
if (modalResult === 0) {
// Upload it instead
}
console.log(modalResult);
} catch (err) {}
}
}

View File

@ -15,6 +15,7 @@ import { Utils, Filters, ClientLogger as Logger } from 'common';
import { MonkeyPatch } from './patcher';
import Reflection from './reflection/index';
import DiscordApi from './discordapi';
import Events from './events';
class Helpers {
static get plannedActions() {
@ -506,17 +507,17 @@ export class ReactAutoPatcher {
const reflect = Reflection.DOM(selector);
const stateNode = reflect.getComponentStateNode(this.UploadArea);
const callback = function(e) {
const callback = function (e) {
if (!e.dataTransfer.files.length || !e.dataTransfer.files[0].name.endsWith('.bd')) return;
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
stateNode.clearDragging();
Modals.confirm('Function not ready', `You tried to install "${e.dataTransfer.files[0].path}", but installing .bd files isn't ready yet.`)
// Possibly something like Events.emit('install-file', e.dataTransfer.files[0]);
Events.emit('install-pkg', e.dataTransfer.files[0], DiscordApi.currentChannel.id);
};
// Remove their handler, add ours, then readd theirs to give ours priority to stop theirs when we get a .bd file.
// Remove their handler, add ours, then read theirs to give ours priority to stop theirs when we get a .bd file.
reflect.element.removeEventListener('drop', stateNode.handleDrop);
reflect.element.addEventListener('drop', callback);
reflect.element.addEventListener('drop', stateNode.handleDrop);

View File

@ -8,3 +8,4 @@
@import './settings-modal';
@import './permission-modal';
@import './input-modal';
@import './install-modal';

View File

@ -0,0 +1,112 @@
.bd-installModal {
.bd-modalInner {
min-width: 520px;
min-height: 200px;
.bd-modalBody {
flex-grow: 1;
padding: 0;
.bd-installModalBody {
display: flex;
flex-direction: column;
flex-grow: 1;
.bd-installModalTop {
padding: 0 15px;
display: flex;
height: 100px;
span {
font-weight: 700;
}
.bd-installModalIcon {
background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTAwIDEzMCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMTAwIDEzMDsiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+LnN0MHtmaWxsOiNGNEY2RkM7fS5zdDF7ZmlsbDpub25lO3N0cm9rZTojMzYzOTNFO3N0cm9rZS13aWR0aDoyO30uc3Qye29wYWNpdHk6MC42O2ZpbGw6bm9uZTtzdHJva2U6IzM2MzkzRTtzdHJva2Utd2lkdGg6MjtlbmFibGUtYmFja2dyb3VuZDpuZXcgICAgO308L3N0eWxlPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xNSwxOWMwLTMuMywyLjctNiw2LTZoNDRjNC43LDAsMjAsMTUuMywyMCwyMHY3NGMwLDMuMy0yLjcsNi02LDZIMjFjLTMuMywwLTYtMi43LTYtNlYxOXoiLz48cGF0aCBjbGFzcz0ic3QxIiBkPSJNMTUsMTljMC0zLjMsMi43LTYsNi02aDQ0YzQuNywwLDIwLDE1LjMsMjAsMjB2NzRjMCwzLjMtMi43LDYtNiw2SDIxYy0zLjMsMC02LTIuNy02LTZWMTl6Ii8+PHBhdGggY2xhc3M9InN0MCIgZD0iTTY2LDE2YzAtMy4zLDEuOS00LjEsNC4yLTEuOGwxMy41LDEzLjVjMi4zLDIuMywxLjYsNC4yLTEuOCw0LjJINjljLTEuNywwLTMtMS4zLTMtM1YxNkw2NiwxNnoiLz48cGF0aCBjbGFzcz0ic3QxIiBkPSJNNjYsMTZjMC0zLjMsMS45LTQuMSw0LjItMS44bDEzLjUsMTMuNWMyLjMsMi4zLDEuNiw0LjItMS44LDQuMkg2OWMtMS43LDAtMy0xLjMtMy0zVjE2TDY2LDE2eiIvPjxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik02MSwxN0gyM2MtMi44LDAtNSwyLjItNSw1djciLz48cGF0aCBjbGFzcz0ic3QyIiBkPSJNNjksMTl2Ny41YzAsMS40LDEuMSwyLjUsMi41LDIuNUg3NCIvPjwvc3ZnPg==);
background-size: 100% 100%;
flex-shrink: 0;
width: 100px;
height: 130px;
position: fixed;
border-radius: 3px;
margin-top: -30px;
display: flex;
align-content: center;
justify-content: center;
align-items: center;
justify-items: center;
.bd-installModalCi {
width: 40px;
height: 40px;
}
svg {
fill: #36393e;
width: 40px;
height: 40px;
}
}
.bd-installModalInfo {
display: flex;
flex-grow: 1;
flex-direction: column;
padding: 15px 10px;
margin-left: 100px;
}
.bd-installModalDesc {
margin-top: 5px;
}
}
.bd-installModalBottom {
padding: 0 15px;
flex-grow: 1;
.bd-permScope {
&:last-child {
.bd-permInner {
border: none;
}
}
}
}
}
}
.bd-installModalFooter {
display: flex;
justify-content: flex-end;
padding: 10px;
background: rgba(0, 0, 0, .1);
.bd-button {
font-size: 16px;
padding: 10px;
border-radius: 3px;
min-width: 100px;
background: #fff;
background: #3ecc9c;
transition: opacity .2s ease-in-out;
&:hover {
opacity: .8;
}
&:first-child {
background: transparent;
transition: none;
&:hover {
opacity: 1;
text-decoration: underline;
}
}
}
}
}
}

View File

@ -0,0 +1,51 @@
<template>
<Modal class="bd-installModal" :headertext="modal.title" :closing="modal.closing" @close="modal.close" :noheader="true">
<div slot="body" class="bd-installModalBody">
<div class="bd-installModalTop">
<div class="bd-installModalIcon">
<div v-if="modal.config.iconEncoded" class="bd-installModalCi" :style="{backgroundImage: `url(${modal.config.iconEncoded})`}"/>
<MiExtension v-else/>
</div>
<div class="bd-installModalInfo">
<span>{{modal.config.info.name}} v{{modal.config.info.version.toString()}} by {{modal.config.info.authors.map(a => a.name).join(', ')}}</span>
<div class="bd-installModalDesc">
{{modal.config.info.description}}
</div>
</div>
</div>
<div class="bd-installModalBottom">
<div v-for="(perm, i) in modal.config.permissions" :key="`perm-${i}`" class="bd-permScope">
<div class="bd-permAllow">
<div class="bd-permCheck">
<div class="bd-permCheckInner"></div>
</div>
<div class="bd-permInner">
<div class="bd-permName">{{perm.HEADER}}</div>
<div class="bd-permDesc">{{perm.BODY}}</div>
</div>
</div>
</div>
</div>
</div>
<div slot="footer" class="bd-installModalFooter">
<div class="bd-button bd-ok" @click="modal.confirm(0); modal.close();">Upload</div>
<div class="bd-button bd-ok" @click="modal.confirm(); modal.close();">Install</div>
</div>
</Modal>
</template>
<script>
// Imports
import { Modal, MiExtension } from '../../common';
export default {
data() {
return {
installing: false
}
},
props: ['modal'],
components: {
Modal, MiExtension
}
}
</script>

View File

@ -11,7 +11,7 @@
<template>
<div :class="['bd-modal', {'bd-modalOut': closing, 'bd-modalScrolled': scrolled}]">
<div class="bd-modalInner">
<div class="bd-modalHeader">
<div class="bd-modalHeader" v-if="!noheader">
<slot name="header">
<div v-if="$slots.icon" class="bd-modalIcon">
<slot name="icon" />
@ -41,7 +41,7 @@
import { MiClose } from './MaterialIcon';
export default {
props: ['headertext', 'closing'],
props: ['headertext', 'closing', 'noheader'],
components: {
MiClose
},

View File

@ -17,6 +17,7 @@ import ErrorModal from './components/bd/modals/ErrorModal.vue';
import SettingsModal from './components/bd/modals/SettingsModal.vue';
import PermissionModal from './components/bd/modals/PermissionModal.vue';
import InputModal from './components/bd/modals/InputModal.vue';
import InstallModal from './components/bd/modals/InstallModal.vue';
let modals = 0;
@ -190,6 +191,19 @@ export default class Modals {
return new Modal(modal, InputModal);
}
static installModal(title, config) {
return this.add(this.createInstallModal(title, config));
}
static createInstallModal(title, config) {
const modal = { title, config };
modal.promise = new Promise((resolve, reject) => {
modal.confirm = value => resolve(value);
modal.beforeClose = () => reject();
});
return new Modal(modal, InstallModal);
}
/**
* Creates a new permissions modal and adds it to the open stack.
* The modal will have a promise property that will be set to a Promise object that is resolved or rejected if the user accepts the permissions or closes the modal.