Merge pull request #3131 from nickofolas/improvement/create-programs-ui

Refresh "Create Programs" page UI
This commit is contained in:
hydroflame 2022-03-16 14:50:05 -04:00 committed by GitHub
commit 80251818e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 101 additions and 51 deletions

@ -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