diff --git a/native/app/bungie/Types.ts b/native/app/bungie/Types.ts index 9efd5cf2a..624b1dd87 100644 --- a/native/app/bungie/Types.ts +++ b/native/app/bungie/Types.ts @@ -5,7 +5,6 @@ import type { GuardianRaceType, ItemType, DamageType, - UISections, } from "@/app/bungie/Common.ts"; import { array, boolean, isoTimestamp, merge, number, object, optional, record, string, unknown } from "valibot"; import type { Output } from "valibot"; @@ -435,7 +434,4 @@ export type GGCharacterUiData = { secondarySpecial: string; lastActiveCharacter: boolean; ggCharacterType: GGCharacterType; - armorPageData: UISections[]; - generalPageData: UISections[]; - weaponsPageData: UISections[]; }; diff --git a/native/app/screens/InventoryPage.tsx b/native/app/screens/InventoryPage.tsx index e718de189..ccd8f8e42 100644 --- a/native/app/screens/InventoryPage.tsx +++ b/native/app/screens/InventoryPage.tsx @@ -1,4 +1,3 @@ -import type { GGCharacterUiData } from "@/app/bungie/Types.ts"; import { InventoryPageEnums, type UISections } from "@/app/bungie/Common"; import { UiCellRenderItem } from "@/app/inventory/UiRowRenderItem.tsx"; import { useGGStore } from "@/app/store/GGStore.ts"; @@ -23,17 +22,6 @@ function calcCurrentListIndex(posX: number, PAGE_WIDTH: number) { useGGStore.getState().setCurrentListIndex(index); } -function getData(ggCharacter: GGCharacterUiData, inventoryPage: InventoryPageEnums): UISections[] | undefined { - switch (inventoryPage) { - case InventoryPageEnums.Armor: - return ggCharacter.armorPageData; - case InventoryPageEnums.General: - return ggCharacter.generalPageData; - case InventoryPageEnums.Weapons: - return ggCharacter.weaponsPageData; - } -} - type InventoryPageProps = { inventoryPages: InventoryPageEnums; }; @@ -101,7 +89,18 @@ export default function InventoryPage(props: InventoryPageProps) { const debouncedMove = debounce(listMoved, 40); const debounceListIndex = debounce(calcCurrentListIndex, 40); - const mainData = useGGStore((state) => state.ggCharacters); + function getData(inventoryPage: InventoryPageEnums): UISections[][] | undefined { + switch (inventoryPage) { + case InventoryPageEnums.Armor: + return useGGStore((state) => state.ggArmor); + case InventoryPageEnums.General: + return useGGStore((state) => state.ggGeneral); + case InventoryPageEnums.Weapons: + return useGGStore((state) => state.ggWeapons); + } + } + + const mainData = getData(props.inventoryPages) ?? []; return ( @@ -112,7 +111,7 @@ export default function InventoryPage(props: InventoryPageProps) { onScroll={(e) => debounceListIndex(e.nativeEvent.contentOffset.x, HOME_WIDTH)} ref={pagedScrollRef} > - {mainData.map((character, index) => { + {mainData.map((_c, index) => { return ( // biome-ignore lint/suspicious/noArrayIndexKey: @@ -120,7 +119,7 @@ export default function InventoryPage(props: InventoryPageProps) { ref={(ref) => { listRefs.current[index] = ref; }} - data={getData(character, props.inventoryPages)} + data={mainData[index]} renderItem={UiCellRenderItem} keyExtractor={keyExtractor} estimatedItemSize={pageEstimatedFlashListItemSize[index]} diff --git a/native/app/store/AccountInventoryLogic.ts b/native/app/store/AccountInventoryLogic.ts index f154919b8..f2ad60283 100644 --- a/native/app/store/AccountInventoryLogic.ts +++ b/native/app/store/AccountInventoryLogic.ts @@ -39,39 +39,62 @@ export function updateAllPages(get: AccountSliceGetter, set: AccountSliceSetter) createUIData(get); const p1 = performance.now(); - const weaponsPageData = buildUIData(get, weaponsPageBuckets); - const ggCharacters = get().ggCharacters; + // For each page use a deepEqual compare to see if the data has changed. + // If it has changed then update just that page. + const ggWeapons = get().ggWeapons; + const newWeaponsPageData = buildUIData(get, weaponsPageBuckets); + const updatedWeapons = getUpdatedItems(ggWeapons, newWeaponsPageData); + if (updatedWeapons) { + set({ ggWeapons: updatedWeapons }); + } + + const ggArmor = get().ggArmor; + const newArmorPageData = buildUIData(get, armorPageBuckets); + const updatedArmor = getUpdatedItems(ggArmor, newArmorPageData); + if (updatedArmor) { + set({ ggArmor: updatedArmor }); + } - const armorPageData = buildUIData(get, armorPageBuckets); - const generalPageData = buildUIData(get, generalPageBuckets); + const ggGeneral = get().ggGeneral; + const newGeneralPageData = buildUIData(get, generalPageBuckets); + const updatedGeneral = getUpdatedItems(ggGeneral, newGeneralPageData); + if (updatedGeneral) { + set({ ggGeneral: updatedGeneral }); + } const p2 = performance.now(); - console.log("buildUIData took:", `${(p2 - p1).toFixed(4)} ms`); + console.log("updateAllPages", `${(p2 - p1).toFixed(4)} ms`); +} - const updatedGGCharacters = create(ggCharacters, (draft) => { - let index = 0; - for (const ggCharacter of draft) { - const newWeaponsPageData = weaponsPageData[index]; +function getUpdatedItems(previousPages: UISections[][], newPageData: UISections[][]): UISections[][] | null { + const newPages: UISections[][] = []; + let foundNewItems = false; + let index = 0; + for (const page of newPageData) { + if (!deepEqual(previousPages[index], page)) { + newPages.push(page); + foundNewItems = true; + } else { + const emptySection: UISections[] = []; + newPages.push(emptySection); + } + index++; + } - if (newWeaponsPageData && !deepEqual(ggCharacter.weaponsPageData, newWeaponsPageData)) { - ggCharacter.weaponsPageData = newWeaponsPageData; - } - const newArmorPageData = armorPageData[index]; - if (newArmorPageData && !deepEqual(ggCharacter.armorPageData, newArmorPageData)) { - ggCharacter.armorPageData = newArmorPageData; + if (foundNewItems) { + const updatedPages = create(previousPages, (draft) => { + let indexPages = 0; + for (const page of newPages) { + if (page.length > 0) { + draft[indexPages] = page; + } + indexPages++; } + }); - const newGeneralPageData = generalPageData[index]; - if (newGeneralPageData && !deepEqual(ggCharacter.generalPageData, newGeneralPageData)) { - ggCharacter.generalPageData = newGeneralPageData; - } - index++; - } - }); - const p3 = performance.now(); - console.log("compare ggCharacters took:", `${(p3 - p2).toFixed(4)} ms`); - set({ ggCharacters: updatedGGCharacters }); - const p4 = performance.now(); - console.log("rebuild UI took:", `${(p4 - p3).toFixed(4)} ms`); + return updatedPages; + } + + return null; } function createUIData(get: AccountSliceGetter) { diff --git a/native/app/store/AccountLogic.ts b/native/app/store/AccountLogic.ts index 230dac851..586462fbe 100644 --- a/native/app/store/AccountLogic.ts +++ b/native/app/store/AccountLogic.ts @@ -45,9 +45,6 @@ export function getCharactersAndVault(guardians: Record): GGCh secondarySpecial, lastActiveCharacter: false, ggCharacterType: GGCharacterType.Vault, - armorPageData: [], - generalPageData: [], - weaponsPageData: [], }; ggCharacters.push(vaultData); @@ -70,9 +67,6 @@ function addCharacterDefinition(guardianData: GuardianData): GGCharacterUiData { secondarySpecial: "", lastActiveCharacter: false, ggCharacterType: GGCharacterType.Guardian, - armorPageData: [], - generalPageData: [], - weaponsPageData: [], }; return data; diff --git a/native/app/store/AccountSlice.ts b/native/app/store/AccountSlice.ts index 4a41aaa1b..d6844889f 100644 --- a/native/app/store/AccountSlice.ts +++ b/native/app/store/AccountSlice.ts @@ -16,6 +16,7 @@ import { DestinyClass, ItemType, type DestinyItemIdentifier, + type UISections, } from "@/app/bungie/Common"; import { findDestinyItem, getCharactersAndVault } from "@/app/store/AccountLogic.ts"; import { @@ -58,6 +59,9 @@ export interface AccountSlice { // The characters live in an object. This array does duplicate some of this data, but it's order // dictates ggCharacters: GGCharacterUiData[]; + ggWeapons: UISections[][]; + ggArmor: UISections[][]; + ggGeneral: UISections[][]; selectedItem: DestinyItem | null; @@ -91,6 +95,9 @@ export const createAccountSlice: StateCreator = (s currentListIndex: 0, ggCharacters: [], + ggWeapons: [], + ggArmor: [], + ggGeneral: [], selectedItem: null,