Non functional code.

This commit is contained in:
Daniel Scalzi 2023-11-25 18:34:04 -05:00
parent 3d470d9a32
commit 2279cb05b7
No known key found for this signature in database
GPG Key ID: 9E3E2AFE45328AA5
27 changed files with 4343 additions and 246 deletions

View File

@ -52,15 +52,15 @@
},
"overrides": [
{
"files": [ "app/assets/js/scripts/*.js" ],
"rules": {
"no-unused-vars": [
0
],
"no-undef": [
0
"env": {
"browser": true,
"node": false,
"jquery": true
},
"files": [
"app/assets/js/scripts/*.js",
"app/assets/js/renderer/*.js"
]
}
}
]
]
}

View File

@ -2,8 +2,10 @@
<head>
<meta charset="utf-8" http-equiv="Content-Security-Policy" content="script-src 'self' 'sha256-In6B8teKZQll5heMl9bS7CESTbGvuAt3VVV86BUQBDk='"/>
<title><%= lang('app.title') %></title>
<script src="./assets/js/scripts/uicore.js"></script>
<script src="./assets/js/scripts/uibinder.js"></script>
<!-- TODO FIXME -->
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
<!-- <script type="module" src="./assets/js/scripts/uicore.js"></script>
<script type="module" src="./assets/js/scripts/uibinder.js"></script> -->
<link type="text/css" rel="stylesheet" href="./assets/css/launcher.css">
<style>
body {
@ -25,6 +27,7 @@
filter: blur(3px) contrast(0.9) brightness(1.0);
}
</style>
<script type="module" src="./assets/js/renderer/megascript.js"></script>
</head>
<body bkid="<%=bkid%>">
<%- include('frame') %>

9
app/assets/@types/preloader.d.ts vendored Normal file
View File

@ -0,0 +1,9 @@
import { api } from '../js/preloader.js'
declare global {
interface Window {
api: typeof api
}
}
export {};

View File

@ -14,7 +14,7 @@ const { LoggerUtil } = require('helios-core')
const { RestResponseStatus } = require('helios-core/common')
const { MojangRestAPI, mojangErrorDisplayable, MojangErrorCode } = require('helios-core/mojang')
const { MicrosoftAuth, microsoftErrorDisplayable, MicrosoftErrorCode } = require('helios-core/microsoft')
const { AZURE_CLIENT_ID } = require('./ipcconstants')
const { AZURE_CLIENT_ID } = require('../ipcconstants')
const log = LoggerUtil.getLogger('AuthManager')

View File

@ -9,7 +9,9 @@ const sysRoot = process.env.APPDATA || (process.platform == 'darwin' ? process.e
const dataPath = path.join(sysRoot, '.helioslauncher')
const launcherDir = require('@electron/remote').app.getPath('userData')
const { app } = require('electron')
const launcherDir = app.getPath('userData')
/**
* Retrieve the absolute path of the launcher directory.

View File

@ -6,7 +6,7 @@ const merge = require('lodash.merge')
let lang
exports.loadLanguage = function(id){
lang = merge(lang || {}, toml.parse(fs.readFileSync(path.join(__dirname, '..', 'lang', `${id}.toml`))) || {})
lang = merge(lang || {}, toml.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'lang', `${id}.toml`))) || {})
}
exports.query = function(id, placeHolders){
@ -40,4 +40,8 @@ exports.setupLanguage = function(){
// Load Custom Language File for Launcher Customizer
exports.loadLanguage('_custom')
}
exports.getLang = () => {
return lang
}

View File

@ -1,67 +1,58 @@
const {ipcRenderer} = require('electron')
const fs = require('fs-extra')
const os = require('os')
const path = require('path')
const { contextBridge, ipcRenderer } = require('electron')
const ConfigManager = require('./configmanager')
const { DistroAPI } = require('./distromanager')
const LangLoader = require('./langloader')
const { LoggerUtil } = require('helios-core')
// eslint-disable-next-line no-unused-vars
const { HeliosDistribution } = require('helios-core/common')
const logger = LoggerUtil.getLogger('Preloader')
logger.info('Loading..')
// Load ConfigManager
ConfigManager.load()
// Yuck!
// TODO Fix this
DistroAPI['commonDir'] = ConfigManager.getCommonDirectory()
DistroAPI['instanceDir'] = ConfigManager.getInstanceDirectory()
// Load Strings
LangLoader.setupLanguage()
/**
*
* @param {HeliosDistribution} data
*/
function onDistroLoad(data){
if(data != null){
// Resolve the selected server if its value has yet to be set.
if(ConfigManager.getSelectedServer() == null || data.getServerById(ConfigManager.getSelectedServer()) == null){
logger.info('Determining default selected server..')
ConfigManager.setSelectedServer(data.getMainServer().rawServer.id)
ConfigManager.save()
}
module.exports.api = {
os: {
totalmem: () => ipcRenderer.invoke('os.totalmem'),
freemem: () => ipcRenderer.invoke('os.freemem')
},
semver: {
prerelease: (version) => ipcRenderer.invoke('semver.prerelease', version)
},
path: {
join: (...args) => ipcRenderer.invoke('path.join', args)
},
app: {
isDev: () => ipcRenderer.invoke('app.isDev'),
getVersion: () => ipcRenderer.invoke('app.getVersion')
},
shell: {
openExternal: (url) => ipcRenderer.invoke('shell.openExternal', url),
openPath: (path) => ipcRenderer.invoke('shell.openPath', path),
},
xwindow: {
close: () => ipcRenderer.invoke('xwindow.close'),
setProgressBar: (progress) => ipcRenderer.invoke('xwindow.setProgressBar', progress),
toggleDevTools: () => {
console.log('%cThe console is dark and full of terrors.', 'color: white; -webkit-text-stroke: 4px #a02d2a; font-size: 60px; font-weight: bold')
console.log('%cIf you\'ve been told to paste something here, you\'re being scammed.', 'font-size: 16px')
console.log('%cUnless you know exactly what you\'re doing, close this window.', 'font-size: 16px')
return ipcRenderer.invoke('xwindow.toggleDevTools')
},
minimize: () => ipcRenderer.invoke('xwindow.minimize'),
maximize: () => ipcRenderer.invoke('xwindow.maximize'),
unmaximize: () => ipcRenderer.invoke('xwindow.unmaximize'),
isMaximized: () => ipcRenderer.invoke('xwindow.isMaximized')
},
process: {
platform: () => ipcRenderer.invoke('process.platform'),
arch: () => ipcRenderer.invoke('process.arch')
},
hc: {
type: () => ipcRenderer.invoke('hc.type')
},
AuthManager: {
addMojangAccount: (username, password) => ipcRenderer.invoke('AuthManager.addMojangAccount', username, password),
addMicrosoftAccount: (authCode) => ipcRenderer.invoke('AuthManager.addMicrosoftAccount', authCode),
removeMojangAccount: (uuid) => ipcRenderer.invoke('AuthManager.removeMojangAccount', uuid),
removeMicrosoftAccount: (uuid) => ipcRenderer.invoke('AuthManager.removeMicrosoftAccount', uuid),
validateSelected: () => ipcRenderer.invoke('AuthManager.validateSelected')
},
Lang: {
getLang: () => ipcRenderer.invoke('Lang.getLang')
},
AutoUpdater: {
port2: () => ipcRenderer.invoke('AutoUpdater.port2')
}
ipcRenderer.send('distributionIndexDone', data != null)
}
// Ensure Distribution is downloaded and cached.
DistroAPI.getDistribution()
.then(heliosDistro => {
logger.info('Loaded distribution index.')
onDistroLoad(heliosDistro)
})
.catch(err => {
logger.info('Failed to load an older version of the distribution index.')
logger.info('Application cannot run.')
logger.error(err)
onDistroLoad(null)
})
// Clean up temp dir incase previous launches ended unexpectedly.
fs.remove(path.join(os.tmpdir(), ConfigManager.getTempNativeFolder()), (err) => {
if(err){
logger.warn('Error while cleaning natives directory', err)
} else {
logger.info('Cleaned natives directory.')
}
})
contextBridge.exposeInMainWorld('api', module.exports.api)

View File

@ -0,0 +1,30 @@
// HACK FIXME
let lang
export async function loadLanguage() {
lang = await window.api.Lang.getLang()
}
export function query(id, placeHolders){
let query = id.split('.')
let res = lang
for(let q of query){
res = res[q]
}
let text = res === lang ? '' : res
if (placeHolders) {
Object.entries(placeHolders).forEach(([key, value]) => {
text = text.replace(`{${key}}`, value)
})
}
return text
}
export function queryJS(id, placeHolders){
return query(`js.${id}`, placeHolders)
}
export function queryEJS(id, placeHolders){
return query(`ejs.${id}`, placeHolders)
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
// Mapping of each view to their container IDs.
export const VIEWS = {
landing: '#landingContainer',
loginOptions: '#loginOptionsContainer',
login: '#loginContainer',
settings: '#settingsContainer',
welcome: '#welcomeContainer',
waiting: '#waitingContainer'
}

View File

@ -1,8 +1,10 @@
/**
* Script for landing.ejs
*/
import { VIEWS } from './views.js'
// Requirements
const { URL } = require('url')
const {
MojangRestAPI,
getServerStatus
@ -85,7 +87,7 @@ function setLaunchPercentage(percent){
* @param {number} percent Percentage (0-100)
*/
function setDownloadPercentage(percent){
remote.getCurrentWindow().setProgressBar(percent/100)
xwindow.setProgressBar(percent/100)
setLaunchPercentage(percent)
}
@ -402,7 +404,7 @@ async function downloadJava(effectiveJavaOptions, launchAfter = true) {
// Extract
// Show installing progress bar.
remote.getCurrentWindow().setProgressBar(2)
xwindow.setProgressBar(2)
// Wait for extration to complete.
const eLStr = Lang.queryJS('landing.downloadJava.extractingJava')
@ -420,7 +422,7 @@ async function downloadJava(effectiveJavaOptions, launchAfter = true) {
const newJavaExec = await extractJdk(asset.path)
// Extraction complete, remove the loading from the OS progress bar.
remote.getCurrentWindow().setProgressBar(-1)
xwindow.setProgressBar(-1)
// Extraction completed successfully.
ConfigManager.setJavaExecutable(ConfigManager.getSelectedServer(), newJavaExec)
@ -533,7 +535,7 @@ async function dlAsync(login = true) {
}
// Remove download bar.
remote.getCurrentWindow().setProgressBar(-1)
xwindow.setProgressBar(-1)
fullRepairModule.destroyReceiver()
@ -554,7 +556,7 @@ async function dlAsync(login = true) {
if(login) {
const authUser = ConfigManager.getSelectedAccount()
loggerLaunchSuite.info(`Sending selected account (${authUser.displayName}) to ProcessBuilder.`)
let pb = new ProcessBuilder(serv, versionData, forgeData, authUser, remote.app.getVersion())
let pb = new ProcessBuilder(serv, versionData, forgeData, authUser, app.getVersion())
setLaunchDetails(Lang.queryJS('landing.dlAsync.launchingGame'))
// const SERVER_JOINED_REGEX = /\[.+\]: \[CHAT\] [a-zA-Z0-9_]{1,16} joined the game/

View File

@ -1,6 +1,9 @@
/**
* Script for login.ejs
*/
import { VIEWS } from './views.js'
// Validation Regexes.
const validUsername = /^[a-zA-Z0-9_]{1,16}$/
const basicEmail = /^\S+@\S+\.\S+$/

View File

@ -1,3 +1,5 @@
import { VIEWS } from './views.js'
const loginOptionsCancelContainer = document.getElementById('loginOptionCancelContainer')
const loginOptionMicrosoft = document.getElementById('loginOptionMicrosoft')
const loginOptionMojang = document.getElementById('loginOptionMojang')

View File

@ -2,6 +2,8 @@
* Script for overlay.ejs
*/
import { VIEWS } from './views.js'
/* Overlay Wrapper Functions */
/**

View File

@ -1,9 +1,8 @@
// Requirements
const os = require('os')
const semver = require('semver')
const DropinModUtil = require('./assets/js/dropinmodutil')
const { MSFT_OPCODE, MSFT_REPLY_TYPE, MSFT_ERROR } = require('./assets/js/ipcconstants')
import { VIEWS } from './views.js'
import DropinModUtil from './assets/js/dropinmodutil'
import { MSFT_OPCODE, MSFT_REPLY_TYPE, MSFT_ERROR } from './assets/js/ipcconstants'
const settingsState = {
invalid: new Set()
@ -64,13 +63,14 @@ function bindFileSelectors(){
]
}
const res = await remote.dialog.showOpenDialog(remote.getCurrentWindow(), options)
if(!res.canceled) {
ele.previousElementSibling.value = res.filePaths[0]
if(isJavaExecSel) {
await populateJavaExecDetails(ele.previousElementSibling.value)
}
}
// TODO FIXME
// const res = await remote.dialog.showOpenDialog(remote.getCurrentWindow(), options)
// if(!res.canceled) {
// ele.previousElementSibling.value = res.filePaths[0]
// if(isJavaExecSel) {
// await populateJavaExecDetails(ele.previousElementSibling.value)
// }
// }
}
}
}
@ -716,7 +716,7 @@ async function resolveModsForUI(){
const distro = await DistroAPI.getDistribution()
const servConf = ConfigManager.getModConfiguration(serv)
const modStr = parseModulesForUI(distro.getServerById(serv).modules, false, servConf.mods)
const modStr = await parseModulesForUI(distro.getServerById(serv).modules, false, servConf.mods)
document.getElementById('settingsReqModsContent').innerHTML = modStr.reqMods
document.getElementById('settingsOptModsContent').innerHTML = modStr.optMods
@ -729,11 +729,13 @@ async function resolveModsForUI(){
* @param {boolean} submodules Whether or not we are parsing submodules.
* @param {Object} servConf The server configuration object for this module level.
*/
function parseModulesForUI(mdls, submodules, servConf){
async function parseModulesForUI(mdls, submodules, servConf){
let reqMods = ''
let optMods = ''
const Type = await hc.type
for(const mdl of mdls){
if(mdl.rawModule.type === Type.ForgeMod || mdl.rawModule.type === Type.LiteMod || mdl.rawModule.type === Type.LiteLoader){
@ -755,7 +757,7 @@ function parseModulesForUI(mdls, submodules, servConf){
</label>
</div>
${mdl.subModules.length > 0 ? `<div class="settingsSubModContainer">
${Object.values(parseModulesForUI(mdl.subModules, true, servConf[mdl.getVersionlessMavenIdentifier()])).join('')}
${Object.values(await parseModulesForUI(mdl.subModules, true, servConf[mdl.getVersionlessMavenIdentifier()])).join('')}
</div>` : ''}
</div>`
@ -779,7 +781,7 @@ function parseModulesForUI(mdls, submodules, servConf){
</label>
</div>
${mdl.subModules.length > 0 ? `<div class="settingsSubModContainer">
${Object.values(parseModulesForUI(mdl.subModules, true, conf.mods)).join('')}
${Object.values(await parseModulesForUI(mdl.subModules, true, conf.mods)).join('')}
</div>` : ''}
</div>`
@ -1403,8 +1405,7 @@ const settingsAboutChangelogButton = settingsTabAbout.getElementsByClassName('se
// Bind the devtools toggle button.
document.getElementById('settingsAboutDevToolsButton').onclick = (e) => {
let window = remote.getCurrentWindow()
window.toggleDevTools()
xwindow.toggleDevTools()
}
/**
@ -1444,7 +1445,7 @@ function populateVersionInformation(version, valueElement, titleElement, checkEl
* Retrieve the version information and display it on the UI.
*/
function populateAboutVersionInformation(){
populateVersionInformation(remote.app.getVersion(), document.getElementById('settingsAboutCurrentVersionValue'), document.getElementById('settingsAboutCurrentVersionTitle'), document.getElementById('settingsAboutCurrentVersionCheck'))
populateVersionInformation(app.getVersion(), document.getElementById('settingsAboutCurrentVersionValue'), document.getElementById('settingsAboutCurrentVersionTitle'), document.getElementById('settingsAboutCurrentVersionCheck'))
}
/**
@ -1455,7 +1456,7 @@ function populateReleaseNotes(){
$.ajax({
url: 'https://github.com/dscalzi/HeliosLauncher/releases.atom',
success: (data) => {
const version = 'v' + remote.app.getVersion()
const version = 'v' + app.getVersion()
const entries = $(data).find('entry')
for(let i=0; i<entries.length; i++){
@ -1537,7 +1538,7 @@ function populateSettingsUpdateInformation(data){
} else {
settingsUpdateTitle.innerHTML = Lang.queryJS('settings.updates.latestVersionTitle')
settingsUpdateChangelogCont.style.display = 'none'
populateVersionInformation(remote.app.getVersion(), settingsUpdateVersionValue, settingsUpdateVersionTitle, settingsUpdateVersionCheck)
populateVersionInformation(app.getVersion(), settingsUpdateVersionValue, settingsUpdateVersionTitle, settingsUpdateVersionCheck)
settingsUpdateButtonStatus(Lang.queryJS('settings.updates.checkForUpdatesButton'), false, () => {
if(!isDev){
ipcRenderer.send('autoUpdateAction', 'checkForUpdate')

View File

@ -2,27 +2,12 @@
* Initialize UI functions which depend on internal modules.
* Loaded after core UI functions are initialized in uicore.js.
*/
// Requirements
const path = require('path')
const { Type } = require('helios-distribution-types')
const AuthManager = require('./assets/js/authmanager')
const ConfigManager = require('./assets/js/configmanager')
const { DistroAPI } = require('./assets/js/distromanager')
import { VIEWS } from './views.js'
let rscShouldLoad = false
let fatalStartupError = false
// Mapping of each view to their container IDs.
const VIEWS = {
landing: '#landingContainer',
loginOptions: '#loginOptionsContainer',
login: '#loginContainer',
settings: '#settingsContainer',
welcome: '#welcomeContainer',
waiting: '#waitingContainer'
}
// The currently shown view container.
let currentView
@ -119,8 +104,7 @@ function showFatalStartupError(){
Lang.queryJS('uibinder.startup.closeButton')
)
setOverlayHandler(() => {
const window = remote.getCurrentWindow()
window.close()
xwindow.close()
})
toggleOverlay(true)
})
@ -145,9 +129,10 @@ function onDistroRefresh(data){
*
* @param {Object} data The distro index object.
*/
function syncModConfigurations(data){
async function syncModConfigurations(data){
const syncedCfgs = []
const Type = await hc.type
for(let serv of data.servers){
@ -439,7 +424,7 @@ document.addEventListener('readystatechange', async () => {
ipcRenderer.on('distributionIndexDone', async (event, res) => {
if(res) {
const data = await DistroAPI.getDistribution()
syncModConfigurations(data)
await syncModConfigurations(data)
ensureJavaSettings(data)
if(document.readyState === 'interactive' || document.readyState === 'complete'){
await showMainUI(data)
@ -462,5 +447,5 @@ async function devModeToggle() {
const data = await DistroAPI.refreshDistributionOrFallback()
ensureJavaSettings(data)
updateSelectedServer(data.servers[0])
syncModConfigurations(data)
await syncModConfigurations(data)
}

View File

@ -1,3 +1,5 @@
import { VIEWS } from './views.js'
/**
* Core UI functions are initialized in this file. This prevents
* unexpected errors from breaking the core features. Specifically,
@ -5,58 +7,41 @@
* modules, excluding dependencies.
*/
// Requirements
const $ = require('jquery')
const {ipcRenderer, shell, webFrame} = require('electron')
const remote = require('@electron/remote')
const isDev = require('./assets/js/isdev')
const { LoggerUtil } = require('helios-core')
const Lang = require('./assets/js/langloader')
// const { ipcRenderer } = require('electron')
const isDev = await window.api.app.isDev()
// const { LoggerUtil } = require('helios-core')
// const Lang = require('./assets/js/langloader')
const loggerUICore = LoggerUtil.getLogger('UICore')
const loggerAutoUpdater = LoggerUtil.getLogger('AutoUpdater')
// Log deprecation and process warnings.
process.traceProcessWarnings = true
process.traceDeprecation = true
// const loggerUICore = LoggerUtil.getLogger('UICore')
// const loggerAutoUpdater = LoggerUtil.getLogger('AutoUpdater')
// Disable eval function.
// eslint-disable-next-line
window.eval = global.eval = function () {
window.eval = function () {
throw new Error('Sorry, this app does not support window.eval().')
}
// Display warning when devtools window is opened.
remote.getCurrentWebContents().on('devtools-opened', () => {
console.log('%cThe console is dark and full of terrors.', 'color: white; -webkit-text-stroke: 4px #a02d2a; font-size: 60px; font-weight: bold')
console.log('%cIf you\'ve been told to paste something here, you\'re being scammed.', 'font-size: 16px')
console.log('%cUnless you know exactly what you\'re doing, close this window.', 'font-size: 16px')
})
// Disable zoom, needed for darwin.
webFrame.setZoomLevel(0)
webFrame.setVisualZoomLevelLimits(1, 1)
// Initialize auto updates in production environments.
let updateCheckListener
if(!isDev){
ipcRenderer.on('autoUpdateNotification', (event, arg, info) => {
switch(arg){
case 'checking-for-update':
loggerAutoUpdater.info('Checking for update..')
// loggerAutoUpdater.info('Checking for update..')
settingsUpdateButtonStatus(Lang.queryJS('uicore.autoUpdate.checkingForUpdateButton'), true)
break
case 'update-available':
loggerAutoUpdater.info('New update available', info.version)
// loggerAutoUpdater.info('New update available', info.version)
if(process.platform === 'darwin'){
info.darwindownload = `https://github.com/dscalzi/HeliosLauncher/releases/download/v${info.version}/Helios-Launcher-setup-${info.version}${process.arch === 'arm64' ? '-arm64' : '-x64'}.dmg`
if(process.platform() === 'darwin'){
info.darwindownload = `https://github.com/dscalzi/HeliosLauncher/releases/download/v${info.version}/Helios-Launcher-setup-${info.version}${process.arch() === 'arm64' ? '-arm64' : '-x64'}.dmg`
showUpdateUI(info)
}
populateSettingsUpdateInformation(info)
break
case 'update-downloaded':
loggerAutoUpdater.info('Update ' + info.version + ' ready to be installed.')
// loggerAutoUpdater.info('Update ' + info.version + ' ready to be installed.')
settingsUpdateButtonStatus(Lang.queryJS('uicore.autoUpdate.installNowButton'), false, () => {
if(!isDev){
ipcRenderer.send('autoUpdateAction', 'installUpdateNow')
@ -65,7 +50,7 @@ if(!isDev){
showUpdateUI(info)
break
case 'update-not-available':
loggerAutoUpdater.info('No new update found.')
// loggerAutoUpdater.info('No new update found.')
settingsUpdateButtonStatus(Lang.queryJS('uicore.autoUpdate.checkForUpdatesButton'))
break
case 'ready':
@ -77,17 +62,17 @@ if(!isDev){
case 'realerror':
if(info != null && info.code != null){
if(info.code === 'ERR_UPDATER_INVALID_RELEASE_FEED'){
loggerAutoUpdater.info('No suitable releases found.')
// loggerAutoUpdater.info('No suitable releases found.')
} else if(info.code === 'ERR_XML_MISSED_ELEMENT'){
loggerAutoUpdater.info('No releases found.')
// loggerAutoUpdater.info('No releases found.')
} else {
loggerAutoUpdater.error('Error during update check..', info)
loggerAutoUpdater.debug('Error Code:', info.code)
// loggerAutoUpdater.error('Error during update check..', info)
// loggerAutoUpdater.debug('Error Code:', info.code)
}
}
break
default:
loggerAutoUpdater.info('Unknown argument', arg)
// loggerAutoUpdater.info('Unknown argument', arg)
break
}
})
@ -133,72 +118,62 @@ $(function(){
loggerUICore.info('UICore Initialized');
})*/
document.addEventListener('readystatechange', function () {
if (document.readyState === 'interactive'){
loggerUICore.info('UICore Initializing..')
// loggerUICore.info('UICore Initializing..')
// Bind close button.
Array.from(document.getElementsByClassName('fCb')).map((val) => {
val.addEventListener('click', e => {
const window = remote.getCurrentWindow()
window.close()
})
})
// Bind close button.
Array.from(document.getElementsByClassName('fCb')).map((val) => {
val.addEventListener('click', async e => {
await window.api.xwindow.close()
})
})
// Bind restore down button.
Array.from(document.getElementsByClassName('fRb')).map((val) => {
val.addEventListener('click', e => {
const window = remote.getCurrentWindow()
if(window.isMaximized()){
window.unmaximize()
} else {
window.maximize()
}
document.activeElement.blur()
})
})
// Bind restore down button.
Array.from(document.getElementsByClassName('fRb')).map((val) => {
val.addEventListener('click', async e => {
if(await window.api.xwindow.isMaximized()){
await window.api.xwindow.unmaximize()
} else {
await window.api.xwindow.maximize()
}
document.activeElement.blur()
})
})
// Bind minimize button.
Array.from(document.getElementsByClassName('fMb')).map((val) => {
val.addEventListener('click', e => {
const window = remote.getCurrentWindow()
window.minimize()
document.activeElement.blur()
})
})
// Bind minimize button.
Array.from(document.getElementsByClassName('fMb')).map((val) => {
val.addEventListener('click', async e => {
console.log('hi')
await window.api.xwindow.minimize()
document.activeElement.blur()
})
})
// Remove focus from social media buttons once they're clicked.
Array.from(document.getElementsByClassName('mediaURL')).map(val => {
val.addEventListener('click', e => {
document.activeElement.blur()
})
})
// Remove focus from social media buttons once they're clicked.
Array.from(document.getElementsByClassName('mediaURL')).map(val => {
val.addEventListener('click', e => {
document.activeElement.blur()
})
})
} else if(document.readyState === 'complete'){
//266.01
//170.8
//53.21
// Bind progress bar length to length of bot wrapper
//const targetWidth = document.getElementById("launch_content").getBoundingClientRect().width
//const targetWidth2 = document.getElementById("server_selection").getBoundingClientRect().width
//const targetWidth3 = document.getElementById("launch_button").getBoundingClientRect().width
//266.01
//170.8
//53.21
// Bind progress bar length to length of bot wrapper
//const targetWidth = document.getElementById("launch_content").getBoundingClientRect().width
//const targetWidth2 = document.getElementById("server_selection").getBoundingClientRect().width
//const targetWidth3 = document.getElementById("launch_button").getBoundingClientRect().width
document.getElementById('launch_details').style.maxWidth = 266.01
document.getElementById('launch_progress').style.width = 170.8
document.getElementById('launch_details_right').style.maxWidth = 170.8
document.getElementById('launch_progress_label').style.width = 53.21
}
}, false)
document.getElementById('launch_details').style.maxWidth = 266.01
document.getElementById('launch_progress').style.width = 170.8
document.getElementById('launch_details_right').style.maxWidth = 170.8
document.getElementById('launch_progress_label').style.width = 53.21
/**
* Open web links in the user's default browser.
*/
$(document).on('click', 'a[href^="http"]', function(event) {
$(document).on('click', 'a[href^="http"]', async (event) => {
event.preventDefault()
shell.openExternal(this.href)
await window.api.shell.openExternal(this.href)
})
/**
@ -206,9 +181,8 @@ $(document).on('click', 'a[href^="http"]', function(event) {
* This will crash the program if you are using multiple
* DevTools, for example the chrome debugger in VS Code.
*/
document.addEventListener('keydown', function (e) {
document.addEventListener('keydown', async (e) => {
if((e.key === 'I' || e.key === 'i') && e.ctrlKey && e.shiftKey){
let window = remote.getCurrentWindow()
window.toggleDevTools()
await window.api.xwindow.toggleDevTools()
}
})

View File

@ -0,0 +1,9 @@
// Mapping of each view to their container IDs.
export const VIEWS = {
landing: '#landingContainer',
loginOptions: '#loginOptionsContainer',
login: '#loginContainer',
settings: '#settingsContainer',
welcome: '#welcomeContainer',
waiting: '#waitingContainer'
}

View File

@ -1,3 +1,5 @@
import { VIEWS } from './views.js'
/**
* Script for welcome.ejs
*/

View File

@ -216,5 +216,5 @@
</div>
</div>
</div>
<script src="./assets/js/scripts/landing.js"></script>
<!-- <script type="module" src="./assets/js/scripts/landing.js"></script> -->
</div>

View File

@ -61,5 +61,5 @@
</div>
</form>
</div>
<script src="./assets/js/scripts/login.js"></script>
<!-- <script type="module" src="./assets/js/scripts/login.js"></script> -->
</div>

View File

@ -30,5 +30,5 @@
</div>
</div>
</div>
<script src="./assets/js/scripts/loginOptions.js"></script>
<!-- <script type="module" src="./assets/js/scripts/loginOptions.js"></script> -->
</div>

View File

@ -37,5 +37,5 @@
</div>
</div>
</div>
<script src="./assets/js/scripts/overlay.js"></script>
<!-- <script type="module" src="./assets/js/scripts/overlay.js"></script> -->
</div>

View File

@ -389,5 +389,5 @@
</div>
</div>
</div>
<script src="./assets/js/scripts/settings.js"></script>
<!-- <script type="module" src="./assets/js/scripts/settings.js"></script> -->
</div>

View File

@ -21,5 +21,5 @@
</div>
</button>
</div>
<script src="./assets/js/scripts/welcome.js"></script>
<!-- <script type="module" src="./assets/js/scripts/welcome.js"></script> -->
</div>

218
index.js
View File

@ -1,23 +1,104 @@
const remoteMain = require('@electron/remote/main')
remoteMain.initialize()
// Requirements
const { app, BrowserWindow, ipcMain, Menu, shell } = require('electron')
const autoUpdater = require('electron-updater').autoUpdater
const ejse = require('ejs-electron')
const fs = require('fs')
const isDev = require('./app/assets/js/isdev')
const fs = require('fs-extra')
const path = require('path')
const semver = require('semver')
const { pathToFileURL } = require('url')
const { AZURE_CLIENT_ID, MSFT_OPCODE, MSFT_REPLY_TYPE, MSFT_ERROR, SHELL_OPCODE } = require('./app/assets/js/ipcconstants')
const LangLoader = require('./app/assets/js/langloader')
const { Type } = require('helios-distribution-types')
const { totalmem, freemem, tmpdir } = require('node:os')
const { prerelease } = require('semver')
const { addMojangAccount, addMicrosoftAccount, removeMojangAccount, removeMicrosoftAccount, validateSelected } = require('./app/assets/js/main/authmanager')
const ConfigManager = require('./app/assets/js/main/configmanager')
const { DistroAPI } = require('./app/assets/js/main/distromanager')
// eslint-disable-next-line no-unused-vars
const { HeliosDistribution } = require('helios-core/common')
const { LoggerUtil } = require('helios-core')
const { getLang, setupLanguage, queryEJS } = require('./app/assets/js/main/langloader')
const logger = LoggerUtil.getLogger('Preloader')
// Log deprecation and process warnings.
process.traceProcessWarnings = true
process.traceDeprecation = true
// Load ConfigManager
ConfigManager.load()
// Yuck!
// TODO Fix this
DistroAPI['commonDir'] = ConfigManager.getCommonDirectory()
DistroAPI['instanceDir'] = ConfigManager.getInstanceDirectory()
// Setup Lang
LangLoader.setupLanguage()
setupLanguage()
/**
*
* @param {HeliosDistribution} data
*/
function onDistroLoad(data){
if(data != null){
// Resolve the selected server if its value has yet to be set.
if(ConfigManager.getSelectedServer() == null || data.getServerById(ConfigManager.getSelectedServer()) == null){
logger.info('Determining default selected server..')
ConfigManager.setSelectedServer(data.getMainServer().rawServer.id)
ConfigManager.save()
}
}
win.webContents.send('distributionIndexDone', data != null)
}
// Ensure Distribution is downloaded and cached.
DistroAPI.getDistribution()
.then(heliosDistro => {
logger.info('Loaded distribution index.')
onDistroLoad(heliosDistro)
})
.catch(err => {
logger.info('Failed to load an older version of the distribution index.')
logger.info('Application cannot run.')
logger.error(err)
onDistroLoad(null)
})
// Clean up temp dir incase previous launches ended unexpectedly.
fs.remove(path.join(tmpdir(), ConfigManager.getTempNativeFolder()), (err) => {
if(err){
logger.warn('Error while cleaning natives directory', err)
} else {
logger.info('Cleaned natives directory.')
}
})
const autoUpdateChannel = new MessageChannel()
// ORIGINAL BELOW
// Setup auto updater.
function initAutoUpdater(event, data) {
function initAutoUpdater(data) {
if(data){
autoUpdater.allowPrerelease = true
@ -26,7 +107,7 @@ function initAutoUpdater(event, data) {
// autoUpdater.allowPrerelease = true
}
if(isDev){
if(!app.isPackaged){
autoUpdater.autoInstallOnAppQuit = false
autoUpdater.updateConfigPath = path.join(__dirname, 'dev-app-update.yml')
}
@ -34,22 +115,77 @@ function initAutoUpdater(event, data) {
autoUpdater.autoDownload = false
}
autoUpdater.on('update-available', (info) => {
event.sender.send('autoUpdateNotification', 'update-available', info)
autoUpdateChannel.port1.postMessage(['autoUpdateNotification', 'update-available', info])
})
autoUpdater.on('update-downloaded', (info) => {
event.sender.send('autoUpdateNotification', 'update-downloaded', info)
autoUpdateChannel.port1.postMessage(['autoUpdateNotification', 'update-downloaded', info])
})
autoUpdater.on('update-not-available', (info) => {
event.sender.send('autoUpdateNotification', 'update-not-available', info)
autoUpdateChannel.port1.postMessage(['autoUpdateNotification', 'update-not-available', info])
})
autoUpdater.on('checking-for-update', () => {
event.sender.send('autoUpdateNotification', 'checking-for-update')
autoUpdateChannel.port1.postMessage(['autoUpdateNotification', 'checking-for-update'])
})
autoUpdater.on('error', (err) => {
event.sender.send('autoUpdateNotification', 'realerror', err)
autoUpdateChannel.port1.postMessage(['autoUpdateNotification', 'realerror', err])
})
}
/*
// all on autoupdatechannel
[
command,
arg1,
arg2,
...
]
*/
autoUpdateChannel.port1.on('message', (event) => {
const command = event[0]
switch(command) {
case 'initAutoUpdater':
console.log('Initializing auto updater.')
initAutoUpdater(event[1])
autoUpdateChannel.port1.postMessage([
'autoUpdateNotification',
'ready'
])
break
case 'checkForUpdate':
// TODO Test that error is passed properly
autoUpdater.checkForUpdates()
.catch(err => {
autoUpdateChannel.port1.postMessage([
'autoUpdateNotification',
'realerror',
err
])
})
break
case 'allowPrereleaseChange':
if(!event[1]){
const preRelComp = semver.prerelease(app.getVersion())
if(preRelComp != null && preRelComp.length > 0){
autoUpdater.allowPrerelease = true
} else {
autoUpdater.allowPrerelease = event[1]
}
} else {
autoUpdater.allowPrerelease = event[1]
}
break
case 'installUpdateNow':
autoUpdater.quitAndInstall()
break
default:
console.log('Unknown command', command)
break
}
})
// Open channel to listen for update actions.
ipcMain.on('autoUpdateAction', (event, arg, data) => {
switch(arg){
@ -84,10 +220,6 @@ ipcMain.on('autoUpdateAction', (event, arg, data) => {
break
}
})
// Redirect distribution index event from preloader to renderer.
ipcMain.on('distributionIndexDone', (event, res) => {
event.sender.send('distributionIndexDone', res)
})
// Handle trash item.
ipcMain.handle(SHELL_OPCODE.TRASH_ITEM, async (event, ...args) => {
@ -234,15 +366,18 @@ function createWindow() {
webPreferences: {
preload: path.join(__dirname, 'app', 'assets', 'js', 'preloader.js'),
nodeIntegration: true,
contextIsolation: false
contextIsolation: true
},
backgroundColor: '#171614'
})
remoteMain.enable(win.webContents)
// Disable zoom, needed for darwin.
win.webContents.setZoomLevel(0)
win.webContents.setVisualZoomLevelLimits(1, 1)
const data = {
bkid: Math.floor((Math.random() * fs.readdirSync(path.join(__dirname, 'app', 'assets', 'images', 'backgrounds')).length)),
lang: (str, placeHolders) => LangLoader.queryEJS(str, placeHolders)
lang: (str, placeHolders) => queryEJS(str, placeHolders)
}
Object.entries(data).forEach(([key, val]) => ejse.data(key, val))
@ -341,8 +476,47 @@ function getPlatformIcon(filename){
return path.join(__dirname, 'app', 'assets', 'images', `${filename}.${ext}`)
}
app.on('ready', createWindow)
app.on('ready', createMenu)
app.whenReady().then(() => {
ipcMain.handle('os.totalmem', () => totalmem())
ipcMain.handle('os.freemem', () => freemem())
ipcMain.handle('semver.prerelease', (version) => prerelease(version))
ipcMain.handle('path.join', (...args) => path.join(args))
ipcMain.handle('app.isDev', () => !app.isPackaged)
ipcMain.handle('app.getVersion', () => app.getVersion())
ipcMain.handle('shell.openExternal', (url) => shell.openExternal(url))
ipcMain.handle('shell.openPath', (path) => shell.openPath(path))
ipcMain.handle('xwindow.close', () => win.close())
ipcMain.handle('xwindow.setProgressBar', (progress) => win.setProgressBar(progress))
ipcMain.handle('xwindow.toggleDevTools', () => win.webContents.toggleDevTools())
ipcMain.handle('xwindow.minimize', () => win.minimize())
ipcMain.handle('xwindow.maximize', () => win.maximize())
ipcMain.handle('xwindow.unmaximize', () => win.unmaximize())
ipcMain.handle('xwindow.isMaximized', () => win.isMaximized())
ipcMain.handle('process.platform', () => process.platform)
ipcMain.handle('process.arch', () => process.arch)
ipcMain.handle('hc.type', () => Type)
ipcMain.handle('AuthManager.addMojangAccount', async (username, password) => await addMojangAccount(username, password))
ipcMain.handle('AuthManager.addMicrosoftAccount', async (authCode) => await addMicrosoftAccount(authCode))
ipcMain.handle('AuthManager.removeMojangAccount', async (uuid) => await removeMojangAccount(uuid))
ipcMain.handle('AuthManager.removeMicrosoftAccount', async (uuid) => await removeMicrosoftAccount(uuid))
ipcMain.handle('AuthManager.validateSelected', async () => await validateSelected())
ipcMain.handle('Lang.getLang', () => getLang())
ipcMain.handle('AutoUpdater.port2', () => autoUpdateChannel.port2)
createWindow()
createMenu()
})
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar