Skip to content

Commit 54e791a

Browse files
authored
Updated editor to support unactivated stats (#3087)
* Updated editor to support unactivated stats * Allow substat to stay selected when clicking checkbox * Fix type error * Fix issue when changing substats * Resolve issues with swap overlap and stats losing values * Fix edit mode
1 parent 7ff699b commit 54e791a

File tree

3 files changed

+202
-16
lines changed

3 files changed

+202
-16
lines changed

libs/gi/localization/assets/locales/en/artifact.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
"alert": "NOTE: Artifact Scanning currently only works for <strong>ENGLISH</strong> artifacts.",
4343
"section1": "<0>Using screenshots can dramatically decrease the amount of time you manually input in stats on the Genshin Optimizer.</0><1>Where to snip the screenshot.</1><2>In game, Open your bag, and navigate to the artifacts tab. Select the artifact you want to scan with Genshin Optimizer. <2>Only artifact from this screen can be scanned.</2></2><3>Single artifact</3><4>To take a screenshot, in Windows, the shortcut is <2>Alt + Print Screen</2>. Once you selected the region, the image is automatically included in your clipboard.</4><5>Multiple artifacts</5><6>To take advantage of batch uploads, you can use a tool like <2>PicPick</2> to create a macro to easily to screenshot multiple artifacts at once.</6><7>What to include in the screenshot.</7><8>The full genshin window, or at least a region that covers the artifact card.</8>",
4444
"section2": "<0>Adding Screenshot to Genshin Optimizer</0><1>At this point, you should have the artifact screenshot either saved to your harddrive, or in your clipboard.</1><2>You can click on the box next to \"Browse\" to browse the files in your harddrive for multiple screenshots.</2><3>For single screenshots from the snippets, just press <2>Ctrl + V</2> to paste from your clipboard.</3><4>You should be able to see a Preview of your artifact snippet, and after waiting a few seconds, the artifact set and the substats will be filled in in the <1>Artifact Editor</1>.</4><5>Finishing the Artifact</5><6>Unfortunately, computer vision is not 100%. There will always be cases where something is not scanned properly. You should always double check the scanned artifact values! Once the artifact has been filled, Click on <2>Add Artifact</2> to finish editing the artifact.</6>"
45-
}
45+
},
46+
"unactivated": "Unactivated"
4647
},
4748
"slot": "Slot",
4849
"setEffectNum": "{{setNum}}-Set",

libs/gi/ui/src/components/artifact/editor/SubstatInput.tsx

Lines changed: 89 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,35 +23,62 @@ import {
2323
Box,
2424
Button,
2525
ButtonGroup,
26+
FormControlLabel,
2627
Grid,
2728
ListItemIcon,
2829
ListItemText,
2930
MenuItem,
3031
Slider,
3132
Typography,
3233
} from '@mui/material'
34+
import Checkbox from '@mui/material/Checkbox'
3335
import { useEffect, useMemo, useState } from 'react'
3436
import { Trans, useTranslation } from 'react-i18next'
3537
import { PercentBadge } from '../../PercentBadge'
3638
import { ArtifactStatWithUnit } from '../ArtifactStatKeyDisplay'
3739
import type { RollColorKey } from '../util'
40+
41+
function getCorrectSubstats(
42+
artifact: ICachedArtifact | undefined,
43+
isUnactivatedSubstat: boolean,
44+
substatIndex: number
45+
) {
46+
if (
47+
artifact?.unactivatedSubstats &&
48+
substatIndex === 3 &&
49+
isUnactivatedSubstat
50+
) {
51+
return artifact.unactivatedSubstats[0]
52+
} else {
53+
return artifact?.substats[substatIndex]
54+
}
55+
}
56+
3857
export function SubstatInput({
3958
index,
4059
artifact,
4160
setSubstat,
61+
onChange,
62+
isUnactivatedSubstat,
4263
}: {
4364
index: number
4465
artifact: ICachedArtifact | undefined
45-
setSubstat: (index: number, substat: ISubstat) => void
66+
setSubstat: (
67+
index: number,
68+
substat: ISubstat,
69+
isUnactivatedSubstat: boolean
70+
) => void
71+
onChange: (index: number, substat: ISubstat, isChecked: boolean) => void
72+
isUnactivatedSubstat: boolean
4673
}) {
4774
const { t } = useTranslation('artifact')
48-
const { mainStatKey = '', rarity = 5 } = artifact ?? {}
75+
const { mainStatKey = '', rarity = 5, level = 0 } = artifact ?? {}
4976
const {
5077
key = '',
5178
value = 0,
5279
rolls = [],
5380
efficiency = 0,
54-
} = artifact?.substats[index] ?? {}
81+
} = getCorrectSubstats(artifact, isUnactivatedSubstat, index) ?? {}
5582

5683
const accurateValue = rolls.reduce((a, b) => a + b, 0)
5784
const unit = getUnitStr(key),
@@ -108,7 +135,9 @@ export function SubstatInput({
108135
>
109136
{key && (
110137
<MenuItem
111-
onClick={() => setSubstat(index, { key: '', value: 0 })}
138+
onClick={() =>
139+
setSubstat(index, { key: '', value: 0 }, isUnactivatedSubstat)
140+
}
112141
>
113142
{t('editor.substat.noSubstat')}
114143
</MenuItem>
@@ -120,7 +149,13 @@ export function SubstatInput({
120149
key={k}
121150
selected={key === k}
122151
disabled={key === k}
123-
onClick={() => setSubstat(index, { key: k, value: 0 })}
152+
onClick={() =>
153+
setSubstat(
154+
index,
155+
{ key: k, value: 0 },
156+
isUnactivatedSubstat
157+
)
158+
}
124159
>
125160
<ListItemIcon>
126161
<StatIcon statKey={k} />
@@ -144,8 +179,14 @@ export function SubstatInput({
144179
float={unit === '%'}
145180
placeholder={t('editor.substat.selectSub')}
146181
value={key ? value : 0}
147-
onChange={(value) => setSubstat(index, { key, value: value ?? 0 })}
148-
disabled={!key}
182+
onChange={(value) =>
183+
setSubstat(
184+
index,
185+
{ key, value: value ?? 0 },
186+
isUnactivatedSubstat
187+
)
188+
}
189+
disabled={!key || (isUnactivatedSubstat && index === 3)}
149190
error={!!error}
150191
inputProps={{
151192
sx: { textAlign: 'right' },
@@ -163,9 +204,17 @@ export function SubstatInput({
163204
<Button
164205
key={i}
165206
color={`roll${clamp(rollOffset + i, 1, 6)}` as any}
166-
disabled={(value && !rollNum) || allowedRolls <= 0}
207+
disabled={
208+
(value && !rollNum) ||
209+
allowedRolls <= 0 ||
210+
(isUnactivatedSubstat && rollNum > 0 && index === 3)
211+
}
167212
onClick={() =>
168-
setSubstat(index, { key, value: parseFloat(newValue) })
213+
setSubstat(
214+
index,
215+
{ key, value: parseFloat(newValue) },
216+
isUnactivatedSubstat
217+
)
169218
}
170219
>
171220
{newValue}
@@ -179,9 +228,13 @@ export function SubstatInput({
179228
value={value}
180229
marks={marks}
181230
setValue={(v) =>
182-
setSubstat(index, { key, value: (v as number) ?? 0 })
231+
setSubstat(
232+
index,
233+
{ key, value: (v as number) ?? 0 },
234+
isUnactivatedSubstat
235+
)
183236
}
184-
disabled={!key}
237+
disabled={!key || (isUnactivatedSubstat && index === 3)}
185238
/>
186239
</Box>
187240
<Box sx={{ px: 1, pb: 1 }}>
@@ -202,7 +255,7 @@ export function SubstatInput({
202255
: t('editor.substat.noRoll')}
203256
</SqBadge>
204257
</Grid>
205-
<Grid item flexGrow={1}>
258+
<Grid item>
206259
{!!rolls.length &&
207260
[...rolls].sort().map((val, i) => (
208261
<Typography
@@ -219,6 +272,30 @@ export function SubstatInput({
219272
</Typography>
220273
))}
221274
</Grid>
275+
<Grid item flexGrow={1}>
276+
{index === 3 ? (
277+
<FormControlLabel
278+
label={t('editor.unactivated')}
279+
control={
280+
<Checkbox
281+
checked={isUnactivatedSubstat}
282+
onChange={(e) =>
283+
onChange(
284+
index,
285+
{ key: key, value: value },
286+
e.target.checked
287+
)
288+
}
289+
sx={{ padding: 0 }}
290+
disabled={!artifact || level > 0}
291+
></Checkbox>
292+
}
293+
sx={{ ml: 1 }}
294+
/>
295+
) : (
296+
''
297+
)}
298+
</Grid>
222299
<Grid item xs="auto" flexShrink={1}>
223300
<Typography>
224301
<Trans

libs/gi/ui/src/components/artifact/editor/index.tsx

Lines changed: 111 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,19 @@ import { UploadExplainationModal } from './UploadExplainationModal'
9898
const allSubstatFilter = new Set(allSubstatKeys)
9999
type ResetMessage = { type: 'reset' }
100100
type SubstatMessage = { type: 'substat'; index: number; substat: ISubstat }
101+
type UnactivatedSubstatMessage = {
102+
type: 'unactivatedSubstat'
103+
index: number
104+
substat: ISubstat
105+
}
101106
type OverwriteMessage = { type: 'overwrite'; artifact: IArtifact }
102107
type UpdateMessage = { type: 'update'; artifact: Partial<IArtifact> }
103-
type Message = ResetMessage | SubstatMessage | OverwriteMessage | UpdateMessage
108+
type Message =
109+
| ResetMessage
110+
| SubstatMessage
111+
| OverwriteMessage
112+
| UpdateMessage
113+
| UnactivatedSubstatMessage
104114
function artifactReducer(
105115
state: IArtifact | undefined,
106116
action: Message
@@ -114,6 +124,7 @@ function artifactReducer(
114124
const oldIndex = substat.key
115125
? state!.substats.findIndex((current) => current.key === substat.key)
116126
: -1
127+
117128
if (oldIndex === -1 || oldIndex === index)
118129
state!.substats[index] = substat
119130
// Already in used, swap the items instead
@@ -122,6 +133,79 @@ function artifactReducer(
122133
state!.substats[oldIndex],
123134
state!.substats[index],
124135
]
136+
137+
// Reset unactivated substat data if it exists
138+
if (
139+
state!.unactivatedSubstats?.length &&
140+
state!.unactivatedSubstats[0].key
141+
) {
142+
state!.unactivatedSubstats = []
143+
}
144+
return { ...state! }
145+
}
146+
case 'unactivatedSubstat': {
147+
if (!state?.unactivatedSubstats) {
148+
return { ...state! }
149+
}
150+
151+
const { index, substat } = action
152+
const findSubstatIndex = (
153+
substats: typeof state.substats,
154+
key: string
155+
) => substats.findIndex((current) => current.key === key)
156+
const oldActivatedIndex = substat.key
157+
? findSubstatIndex(state.substats, substat.key)
158+
: -1
159+
const unactivatedIndex = substat.key
160+
? findSubstatIndex(state.unactivatedSubstats, substat.key)
161+
: -1
162+
const oldUnactivatedIndex =
163+
unactivatedIndex !== -1 ? unactivatedIndex + 3 : -1
164+
const activeSubstat = state.substats[3].key
165+
? state.substats[3]
166+
: substat
167+
168+
// Allow swapping of substats between unactivated and activated
169+
if (index === 3) {
170+
// check if unactivated stat needs to swap with activated stat
171+
if (oldUnactivatedIndex === -1 || oldUnactivatedIndex === index) {
172+
if (
173+
oldActivatedIndex !== -1 &&
174+
oldUnactivatedIndex !== oldActivatedIndex
175+
) {
176+
const tempStat = state!.unactivatedSubstats[0]
177+
state!.unactivatedSubstats[0] = state!.substats[oldActivatedIndex]
178+
state!.substats[oldActivatedIndex] = tempStat
179+
} else {
180+
state!.unactivatedSubstats[0] = activeSubstat
181+
}
182+
}
183+
} else {
184+
// check if activated stat needs to swap with unactivated stat
185+
if (oldActivatedIndex === -1 || oldActivatedIndex === index) {
186+
if (
187+
oldUnactivatedIndex !== -1 &&
188+
oldUnactivatedIndex !== oldActivatedIndex
189+
) {
190+
const tempStat = state!.substats[index]
191+
state!.substats[index] = state!.unactivatedSubstats[0]
192+
state!.unactivatedSubstats[0] = tempStat
193+
} else {
194+
state!.substats[index] = activeSubstat
195+
}
196+
} else {
197+
// swap between activated stats
198+
const tempStat = state!.substats[index]
199+
state!.substats[index] = state!.substats[oldActivatedIndex]
200+
state!.substats[oldActivatedIndex] = tempStat
201+
}
202+
}
203+
204+
// Reset activated substat
205+
if (state.substats[3].key) {
206+
state.substats[3] = { key: '', value: 0 }
207+
}
208+
125209
return { ...state! }
126210
}
127211
case 'overwrite':
@@ -172,6 +256,7 @@ export function ArtifactEditor({
172256
)
173257
const queue = queueRef.current
174258
const { t } = useTranslation('artifact')
259+
const [isUnactivatedSubstat, setIsUnactivatedSubstat] = useState(false)
175260

176261
const database = useDatabase()
177262

@@ -246,6 +331,7 @@ export function ArtifactEditor({
246331
const artStat = artifact && getArtSetStat(artifact.setKey)
247332
const reset = useCallback(() => {
248333
cancelEdit?.()
334+
setIsUnactivatedSubstat(false)
249335
artifactDispatch({ type: 'reset' })
250336
setScannedData(undefined)
251337
}, [cancelEdit, artifactDispatch])
@@ -304,8 +390,9 @@ export function ArtifactEditor({
304390
[artifact, artStat, artifactDispatch, fixedSlotKey]
305391
)
306392
const setSubstat = useCallback(
307-
(index: number, substat: ISubstat) => {
308-
artifactDispatch({ type: 'substat', index, substat })
393+
(index: number, substat: ISubstat, isUnactivatedSubstat: boolean) => {
394+
const type = isUnactivatedSubstat ? 'unactivatedSubstat' : 'substat'
395+
artifactDispatch({ type: type, index, substat })
309396
},
310397
[artifactDispatch]
311398
)
@@ -425,6 +512,25 @@ export function ArtifactEditor({
425512
}
426513
}, [queue])
427514

515+
const handleChange = (
516+
index: number,
517+
substat: ISubstat,
518+
isChecked: boolean
519+
) => {
520+
setIsUnactivatedSubstat(isChecked)
521+
setSubstat(index, substat, isChecked)
522+
}
523+
524+
useEffect(() => {
525+
if (level >= 4) {
526+
setIsUnactivatedSubstat(false)
527+
}
528+
529+
if (artifactIdToEdit && artifact?.unactivatedSubstats?.[0]?.key) {
530+
setIsUnactivatedSubstat(true)
531+
}
532+
}, [artifact?.unactivatedSubstats, artifactIdToEdit, level])
533+
428534
const removeId = (artifactIdToEdit !== 'new' && artifactIdToEdit) || old?.id
429535
return (
430536
<ModalWrapper open={show} onClose={onClose} data-testid="artifact-editor">
@@ -730,6 +836,8 @@ export function ArtifactEditor({
730836
index={index}
731837
artifact={cArtifact}
732838
setSubstat={setSubstat}
839+
onChange={handleChange}
840+
isUnactivatedSubstat={isUnactivatedSubstat}
733841
/>
734842
))}
735843
{texts && (

0 commit comments

Comments
 (0)