mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-26 09:33:49 +01:00
Merge pull request #3131 from nickofolas/improvement/create-programs-ui
Refresh "Create Programs" page UI
This commit is contained in:
commit
80251818e0
@ -1,9 +1,19 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { use } from "../../ui/Context";
|
import { find } from "lodash";
|
||||||
import { getAvailableCreatePrograms } from "../ProgramHelpers";
|
|
||||||
|
|
||||||
import { Box, Tooltip, Typography } from "@mui/material";
|
import {
|
||||||
import Button from "@mui/material/Button";
|
Box,
|
||||||
|
Typography,
|
||||||
|
Button,
|
||||||
|
Container,
|
||||||
|
Paper
|
||||||
|
} from "@mui/material";
|
||||||
|
import { Check, Lock, Create } from "@mui/icons-material";
|
||||||
|
|
||||||
|
import { use } from "../../ui/Context";
|
||||||
|
import { Settings } from "../../Settings/Settings";
|
||||||
|
|
||||||
|
import { Programs } from "../Programs";
|
||||||
|
|
||||||
export const ProgramsSeen: string[] = [];
|
export const ProgramsSeen: string[] = [];
|
||||||
|
|
||||||
@ -15,7 +25,20 @@ export function ProgramsRoot(): React.ReactElement {
|
|||||||
setRerender((old) => !old);
|
setRerender((old) => !old);
|
||||||
}
|
}
|
||||||
|
|
||||||
const programs = getAvailableCreatePrograms(player);
|
const programs = [...Object.values(Programs)]
|
||||||
|
.filter(prog => {
|
||||||
|
const create = prog.create;
|
||||||
|
if (create === null) return false;
|
||||||
|
if (prog.name === "b1t_flum3.exe") {
|
||||||
|
return create.req(player);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.sort((a, b) => {
|
||||||
|
if (player.hasProgram(a.name)) return 1;
|
||||||
|
if (player.hasProgram(b.name)) return -1;
|
||||||
|
return (a.create?.level ?? 0) - (b.create?.level ?? 0);
|
||||||
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
programs.forEach((p) => {
|
programs.forEach((p) => {
|
||||||
@ -29,8 +52,27 @@ export function ProgramsRoot(): React.ReactElement {
|
|||||||
return () => clearInterval(id);
|
return () => clearInterval(id);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const getHackingLevelRemaining = (lvl: number): number => {
|
||||||
|
return Math.ceil(Math.max(lvl - (player.hacking + player.intelligence / 2), 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
const getProgCompletion = (name: string): number => {
|
||||||
|
const programFile = find(player.getHomeComputer().programs, p => {
|
||||||
|
return (p.startsWith(name) && p.endsWith("%-INC"));
|
||||||
|
});
|
||||||
|
if (!programFile) return -1;
|
||||||
|
|
||||||
|
const res = programFile.split("-");
|
||||||
|
if (res.length != 3) return -1;
|
||||||
|
const percComplete = Number(res[1].slice(0, -1));
|
||||||
|
if (isNaN(percComplete) || percComplete < 0 || percComplete >= 100) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return percComplete;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Container disableGutters maxWidth="lg" sx={{ mx: 0, mb: 10 }}>
|
||||||
<Typography variant="h4">Create program</Typography>
|
<Typography variant="h4">Create program</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
This page displays any programs that you are able to create. Writing the code for a program takes time, which
|
This page displays any programs that you are able to create. Writing the code for a program takes time, which
|
||||||
@ -38,30 +80,45 @@ export function ProgramsRoot(): React.ReactElement {
|
|||||||
time. Your progress will be saved and you can continue later.
|
time. Your progress will be saved and you can continue later.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Box sx={{ display: 'grid', width: 'fit-content' }}>
|
<Box sx={{ display: 'grid', gridTemplateColumns: "repeat(3, 1fr)", my: 1 }}>
|
||||||
{programs.map((program) => {
|
{programs.map((program) => {
|
||||||
const create = program.create;
|
const create = program.create;
|
||||||
if (create === null) return <></>;
|
if (create === null) return <></>;
|
||||||
|
const curCompletion = getProgCompletion(program.name);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={program.name}>
|
<Box component={Paper} sx={{ p: 1, opacity: player.hasProgram(program.name) ? 0.75 : 1 }} key={program.name}>
|
||||||
<Tooltip title={create.tooltip}>
|
<Typography variant="h6" sx={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}>
|
||||||
<Button
|
{player.hasProgram(program.name) && <Check sx={{ mr: 1 }} /> ||
|
||||||
sx={{ my: 1 }}
|
(create.req(player) && <Create sx={{ mr: 1 }} /> || <Lock sx={{ mr: 1 }} />)}
|
||||||
onClick={(event) => {
|
{program.name}
|
||||||
if (!event.isTrusted) return;
|
</Typography>
|
||||||
player.startCreateProgramWork(program.name, create.time, create.level);
|
{(!player.hasProgram(program.name) && create.req(player)) && <Button
|
||||||
player.startFocusing();
|
sx={{ my: 1, width: '100%' }}
|
||||||
router.toWork();
|
onClick={(event) => {
|
||||||
}}
|
if (!event.isTrusted) return;
|
||||||
>
|
player.startCreateProgramWork(program.name, create.time, create.level);
|
||||||
{program.name}
|
player.startFocusing();
|
||||||
</Button>
|
router.toWork();
|
||||||
</Tooltip>
|
}}
|
||||||
</React.Fragment>
|
>
|
||||||
|
Create program
|
||||||
|
</Button>}
|
||||||
|
{(player.hasProgram(program.name) || getHackingLevelRemaining(create.level) === 0) ||
|
||||||
|
<Typography color={Settings.theme.hack}>
|
||||||
|
<b>Unlocks in:</b> {getHackingLevelRemaining(create.level)} hacking levels
|
||||||
|
</Typography>}
|
||||||
|
{(curCompletion !== -1) &&
|
||||||
|
<Typography color={Settings.theme.infolight}>
|
||||||
|
<b>Current completion:</b> {curCompletion}%
|
||||||
|
</Typography>}
|
||||||
|
<Typography>
|
||||||
|
{create.tooltip}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -143,11 +143,6 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
|||||||
const augmentationCount = props.player.queuedAugmentations.length;
|
const augmentationCount = props.player.queuedAugmentations.length;
|
||||||
const invitationsCount = props.player.factionInvitations.filter((f) => !InvitationsSeen.includes(f)).length;
|
const invitationsCount = props.player.factionInvitations.filter((f) => !InvitationsSeen.includes(f)).length;
|
||||||
const programCount = getAvailableCreatePrograms(props.player).length - ProgramsSeen.length;
|
const programCount = getAvailableCreatePrograms(props.player).length - ProgramsSeen.length;
|
||||||
const canCreateProgram =
|
|
||||||
getAvailableCreatePrograms(props.player).length > 0 ||
|
|
||||||
props.player.augmentations.length > 0 ||
|
|
||||||
props.player.queuedAugmentations.length > 0 ||
|
|
||||||
props.player.sourceFiles.length > 0;
|
|
||||||
|
|
||||||
const canOpenFactions =
|
const canOpenFactions =
|
||||||
props.player.factionInvitations.length > 0 ||
|
props.player.factionInvitations.length > 0 ||
|
||||||
@ -439,29 +434,27 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
|||||||
</Typography>
|
</Typography>
|
||||||
</ListItemText>
|
</ListItemText>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
{canCreateProgram && (
|
<ListItem
|
||||||
<ListItem
|
button
|
||||||
button
|
key={"Create Program"}
|
||||||
key={"Create Program"}
|
className={clsx({
|
||||||
className={clsx({
|
[classes.active]: props.page === Page.CreateProgram,
|
||||||
[classes.active]: props.page === Page.CreateProgram,
|
})}
|
||||||
})}
|
onClick={clickCreateProgram}
|
||||||
onClick={clickCreateProgram}
|
>
|
||||||
>
|
<ListItemIcon>
|
||||||
<ListItemIcon>
|
<Badge badgeContent={programCount > 0 ? programCount : undefined} color="error">
|
||||||
<Badge badgeContent={programCount > 0 ? programCount : undefined} color="error">
|
<Tooltip title={!open ? "Create Program" : ""}>
|
||||||
<Tooltip title={!open ? "Create Program" : ""}>
|
<BugReportIcon color={props.page !== Page.CreateProgram ? "secondary" : "primary"} />
|
||||||
<BugReportIcon color={props.page !== Page.CreateProgram ? "secondary" : "primary"} />
|
</Tooltip>
|
||||||
</Tooltip>
|
</Badge>
|
||||||
</Badge>
|
</ListItemIcon>
|
||||||
</ListItemIcon>
|
<ListItemText>
|
||||||
<ListItemText>
|
<Typography color={props.page !== Page.CreateProgram ? "secondary" : "primary"}>
|
||||||
<Typography color={props.page !== Page.CreateProgram ? "secondary" : "primary"}>
|
Create Program
|
||||||
Create Program
|
</Typography>
|
||||||
</Typography>
|
</ListItemText>
|
||||||
</ListItemText>
|
</ListItem>
|
||||||
</ListItem>
|
|
||||||
)}
|
|
||||||
{canStaneksGift && (
|
{canStaneksGift && (
|
||||||
<ListItem
|
<ListItem
|
||||||
button
|
button
|
||||||
|
Loading…
Reference in New Issue
Block a user