refactor: much better item UI handling

This commit is contained in:
cha0s 2019-10-15 04:28:42 -05:00
parent ae19826040
commit 20837ea2f0
5 changed files with 54 additions and 47 deletions

View File

@ -0,0 +1,22 @@
// 3rd party.
import * as I from 'immutable';
import React, {useState} from 'react';
// 1st party.
import {useEvent} from './use-event';
export function useInventorySlice(selfEntity, start, end) {
const [items, setItems] = useState(I.List());
useEvent(selfEntity, 'inventoryChanged', () => {
setItems(items.withMutations((items) => {
for (let i = start; i < end; ++i) {
const item = selfEntity.itemInSlot(i);
items.set(i, item ? item : undefined);
}
}));
});
const slice = [];
for (let i = start; i < end; ++i) {
slice.push(items.get(i));
}
return slice;
}

View File

@ -1,51 +1,32 @@
// 3rd party.
import classnames from 'classnames';
import * as I from 'immutable';
import React, {useEffect, useState} from 'react';
import React from 'react';
// 2nd party.
import {compose} from '@avocado/core';
import contempo from 'contempo';
// 1st party.
import {useEvent} from '../hooks/use-event';
import {usePropertyChange} from '../hooks/use-property-change';
import {useInventorySlice} from '../hooks/use-inventory-slice';
import ItemSlot from './item-slot';
const decorate = compose(
contempo(require('./hotbar.raw.scss').default),
);
const HotbarComponent = ({app}) => {
const selfEntity = usePropertyChange(app, 'selfEntity');
const activeSlotIndex = usePropertyChange(selfEntity, 'activeSlotIndex');
const [items, setItems] = useState(I.List());
useEvent(selfEntity, 'inventoryChanged', () => {
setItems(items.withMutations((items) => {
for (let i = 0; i < 10; ++i) {
const item = selfEntity.itemInSlot(i);
if (!item) {
continue;
}
if (!items.has(i)) {
items.set(i, I.Map());
}
items.set(i, items.get(i).withMutations((listItem) => {
listItem.set('backgroundImage', item.imageForSlot());
listItem.set('qty', item.qty);
}));
}
}));
});
const HotbarComponent = ({selfEntity}) => {
const hotkeyForSlot = (index) => {
return (index + 1) % 10;
}
const slots = [];
for (let i = 0; i < 10; ++i) {
const slot = <ItemSlot
const activeSlotIndex = usePropertyChange(selfEntity, 'activeSlotIndex');
const itemSlice = useInventorySlice(selfEntity, 0, 10);
const itemSlots = itemSlice.map((item, i) => {
return <ItemSlot
key={i}
item={item}
className={classnames(
activeSlotIndex === i ? 'active' : '',
)}
item={items.get(i)}
key={i}
onClick={(event) => {
if (selfEntity) {
selfEntity.activeSlotIndex = i;
@ -57,13 +38,12 @@ const HotbarComponent = ({app}) => {
>
<div className="hotbar-key">{hotkeyForSlot(i)}</div>
</ItemSlot>;
slots.push(slot);
}
});
return <div
className="hotbar unselectable"
>
<div className="hotbar-inner">
{slots}
{itemSlots}
</div>
</div>;
}

View File

@ -6,6 +6,7 @@ import {compose} from '@avocado/core';
import contempo from 'contempo';
// 1st party.
import {useEvent} from '../hooks/use-event';
import {usePropertyChange} from '../hooks/use-property-change';
import QuickStatus from './quick-status';
import Hotbar from './hotbar';
import Inventory from './inventory';
@ -17,6 +18,7 @@ const decorate = compose(
const MenuComponent = ({app}) => {
const [opened, setOpened] = useState(false);
const selfEntity = usePropertyChange(app, 'selfEntity');
useEvent(app, 'isMenuOpenedChanged', (_, isOpened) => {
setOpened(isOpened);
});
@ -25,10 +27,10 @@ const MenuComponent = ({app}) => {
'menu-inner',
opened ? 'open' : '',
)}>
<Inventory app={app} />
<Inventory selfEntity={selfEntity} />
<QuickStatus app={app} />
<WorldTime worldTime={app.worldTime} />
<Hotbar app={app} />
<Hotbar selfEntity={selfEntity} />
</div>
</div>;
}

View File

@ -1,24 +1,25 @@
// 3rd party.
import React, {useEffect, useState} from 'react';
import React from 'react';
// 2nd party.
import {compose} from '@avocado/core';
import contempo from 'contempo';
// 1st party.
import {useInventorySlice} from '../hooks/use-inventory-slice';
import ItemSlot from './item-slot';
const decorate = compose(
contempo(require('./inventory.raw.scss').default),
);
const InventoryComponent = () => {
const bagSlots = [];
for (let i = 0; i < 40; ++i) {
bagSlots.push(<ItemSlot key={i} />);
}
const equipmentSlots = [];
for (let i = 0; i < 4; ++i) {
equipmentSlots.push(<ItemSlot key={i} />);
}
const InventoryComponent = ({selfEntity}) => {
const bagSlice = useInventorySlice(selfEntity, 10, 50);
const bagSlots = bagSlice.map((item, i) => {
return <ItemSlot key={i} item={item} />;
});
const equipmentSlice = useInventorySlice(selfEntity, 50, 54);
const equipmentSlots = equipmentSlice.map((item, i) => {
return <ItemSlot key={i} item={item} />;
});
return <div className="inventory unselectable">
<div className="inventory-inner">
<div className="bag">{bagSlots}</div>

View File

@ -4,6 +4,8 @@ import React, {useEffect, useState} from 'react';
// 2nd party.
import {compose} from '@avocado/core';
import contempo from 'contempo';
// 1st party.
import {useEvent} from '../hooks/use-event';
const decorate = compose(
contempo(require('./item-slot.raw.scss').default),
@ -11,15 +13,15 @@ const decorate = compose(
const ItemSlotComponent = (props) => {
const {children, className, item, ...rest} = props;
const [qty, setQty] = useState(undefined);
useEvent(item, 'qtyChanged', (_, qty) => setQty(item.qty));
let backgroundImageUri;
let qty;
let qtyClass;
if (item) {
const backgroundImage = item.get('backgroundImage');
const backgroundImage = item.imageForSlot();
if (backgroundImage) {
backgroundImageUri = backgroundImage.uri;
}
qty = item.get('qty');
if (qty > 9999) {
qtyClass = 'e4';
}