poi-plugin-inventory-cleaner 1.16.1 → 1.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/i18n/en-US.json CHANGED
@@ -39,6 +39,7 @@
39
39
  "stock.batchToggle": "Batch keep",
40
40
  "stock.categoryAll": "All categories",
41
41
  "stock.backToTop": "Back to top",
42
+ "stock.refreshQuest": "Reload quest data",
42
43
  "stock.categoryTitle": "Filter by in-game equipment type",
43
44
  "stock.sortTitle": "Sort by",
44
45
  "stock.sortVerdict": "Guide verdict",
package/i18n/zh-CN.json CHANGED
@@ -39,6 +39,7 @@
39
39
  "stock.batchToggle": "批量保留",
40
40
  "stock.categoryAll": "全部类别",
41
41
  "stock.backToTop": "回到顶部",
42
+ "stock.refreshQuest": "重新读取任务数据",
42
43
  "stock.categoryTitle": "按游戏装备类型筛选",
43
44
  "stock.sortTitle": "排序方式",
44
45
  "stock.sortVerdict": "按攻略判定",
package/index.js CHANGED
@@ -12,7 +12,8 @@ const {
12
12
  summarize,
13
13
  OTHER_CATEGORY,
14
14
  } = require('./lib/inventory')
15
- const { buildQuestNeeds } = require('./lib/quest-needs')
15
+ const { buildQuestNeeds, resetCaches: resetQuestNeeds } = require('./lib/quest-needs')
16
+ const { resetCaches: resetQuestStatus } = require('./lib/quest-status')
16
17
  const { CSS } = require('./lib/style')
17
18
 
18
19
  const DICTIONARIES = {
@@ -71,18 +72,34 @@ function getState() {
71
72
  let snapshot = null
72
73
  let snapshotEquips = null
73
74
  let snapshotConst = null
75
+ let snapshotQuests = null
76
+ let snapshotExtQuest = null
74
77
 
75
78
  function getSnapshot() {
76
79
  const state = getState()
77
80
  const equips =
78
81
  state && state.info && state.info.equips ? state.info.equips : null
79
82
  const constant = state ? state.const : null
80
- if (snapshot && snapshotEquips === equips && snapshotConst === constant) {
83
+ const quests =
84
+ state && state.info && state.info.quests ? state.info.quests : null
85
+ const ext = state && state.ext ? state.ext : null
86
+ const extQuest =
87
+ (ext && (ext['poi-plugin-quest-info-2'] || ext['poi-plugin-quest-info'])) || null
88
+
89
+ if (
90
+ snapshot &&
91
+ snapshotEquips === equips &&
92
+ snapshotConst === constant &&
93
+ snapshotQuests === quests &&
94
+ snapshotExtQuest === extQuest
95
+ ) {
81
96
  return snapshot
82
97
  }
83
98
  snapshotEquips = equips
84
99
  snapshotConst = constant
85
- snapshot = state ? { info: { equips }, const: constant } : null
100
+ snapshotQuests = quests
101
+ snapshotExtQuest = extQuest
102
+ snapshot = state ? { info: { equips, quests }, const: constant, ext } : null
86
103
  return snapshot
87
104
  }
88
105
 
@@ -435,8 +452,33 @@ function App() {
435
452
  const [batchOpen, setBatchOpen] = React.useState(false)
436
453
  const [batchValues, setBatchValues] = React.useState({})
437
454
  const [showTop, setShowTop] = React.useState(false)
455
+ const [questTick, setQuestTick] = React.useState(0)
438
456
  const rootRef = React.useRef(null)
439
457
 
458
+ React.useEffect(() => {
459
+ const onResponse = (event) => {
460
+ const detail = event && event.detail
461
+ const path = detail && detail.path ? String(detail.path) : ''
462
+ if (!/questlist/.test(path)) return
463
+ resetQuestNeeds()
464
+ resetQuestStatus()
465
+ setQuestTick((value) => value + 1)
466
+ window.setTimeout(() => {
467
+ resetQuestNeeds()
468
+ resetQuestStatus()
469
+ setQuestTick((value) => value + 1)
470
+ }, 1500)
471
+ }
472
+ window.addEventListener('game.response', onResponse)
473
+ return () => window.removeEventListener('game.response', onResponse)
474
+ }, [])
475
+
476
+ const refreshQuestData = React.useCallback(() => {
477
+ resetQuestNeeds()
478
+ resetQuestStatus()
479
+ setQuestTick((value) => value + 1)
480
+ }, [])
481
+
440
482
  const handleScroll = React.useCallback((event) => {
441
483
  setShowTop(event.currentTarget.scrollTop > 400)
442
484
  }, [])
@@ -446,6 +488,39 @@ function App() {
446
488
  if (element) element.scrollTo({ top: 0, behavior: 'smooth' })
447
489
  }, [])
448
490
 
491
+ // 窗口位置自愈:如果记住的位置在所有屏幕之外,挪回主屏
492
+ React.useEffect(() => {
493
+ try {
494
+ const remote = require('@electron/remote')
495
+ const windows = remote.BrowserWindow.getAllWindows()
496
+ const target = windows.find((win) =>
497
+ String(win.webContents.getURL() || '').includes('poi-plugin-inventory-cleaner'),
498
+ )
499
+ if (!target) return
500
+ const bounds = target.getBounds()
501
+ const displays = remote.screen.getAllDisplays()
502
+ const onScreen = displays.some((display) => {
503
+ const area = display.workArea
504
+ return (
505
+ bounds.x < area.x + area.width &&
506
+ bounds.x + bounds.width > area.x &&
507
+ bounds.y < area.y + area.height &&
508
+ bounds.y + bounds.height > area.y
509
+ )
510
+ })
511
+ if (onScreen) return
512
+ const area = remote.screen.getPrimaryDisplay().workArea
513
+ target.setBounds({
514
+ x: area.x + 80,
515
+ y: area.y + 60,
516
+ width: Math.min(1200, area.width - 160),
517
+ height: Math.min(900, area.height - 120),
518
+ })
519
+ } catch (_error) {
520
+ // 非 Electron 环境或没有权限时忽略
521
+ }
522
+ }, [])
523
+
449
524
  const firstKeepSave = React.useRef(true)
450
525
  React.useEffect(() => {
451
526
  if (firstKeepSave.current) {
@@ -455,10 +530,10 @@ function App() {
455
530
  saveKeeps(keeps)
456
531
  }, [keeps])
457
532
 
458
- const needs = React.useMemo(() => buildQuestNeeds(state), [state])
533
+ const needs = React.useMemo(() => buildQuestNeeds(state), [state, questTick])
459
534
  const rows = React.useMemo(
460
535
  () => buildInventory(state, { questNeeds: needs, keeps }),
461
- [state, needs, keeps],
536
+ [state, needs, keeps, questTick],
462
537
  )
463
538
  const summary = React.useMemo(() => summarize(rows), [rows])
464
539
 
@@ -573,6 +648,16 @@ function App() {
573
648
  h('option', { value: 'name' }, t('stock.sortName')),
574
649
  h('option', { value: 'category' }, t('stock.sortCategory')),
575
650
  ),
651
+ h(
652
+ 'button',
653
+ {
654
+ type: 'button',
655
+ className: 'stock-chip stock-refresh',
656
+ title: t('stock.refreshQuest'),
657
+ onClick: refreshQuestData,
658
+ },
659
+ '↻',
660
+ ),
576
661
  h(
577
662
  'div',
578
663
  { className: 'stock-views' },
@@ -123,8 +123,6 @@ function clampCount(value) {
123
123
  }
124
124
 
125
125
  function readCachedQuests(now = Date.now()) {
126
- if (cacheState.quests && now - cacheState.at < CACHE_TTL) return cacheState.quests
127
-
128
126
  const file = questCachePath()
129
127
  try {
130
128
  const stat = fs.statSync(file)
@@ -185,10 +183,6 @@ function questPlannerStatePath() {
185
183
  * 里面的 observed 是它见过的任务(含标题/说明/状态),completed 是已完成集合。
186
184
  */
187
185
  function readQuestPlanner(now = Date.now()) {
188
- if (plannerCache.quests && now - plannerCache.at < CACHE_TTL) {
189
- return plannerCache.quests
190
- }
191
-
192
186
  const file = questPlannerStatePath()
193
187
  try {
194
188
  const stat = fs.statSync(file)
@@ -62,10 +62,6 @@ function emptyPlannerState() {
62
62
  }
63
63
 
64
64
  function readPlannerState(now = Date.now()) {
65
- if (plannerCache.completed && now - plannerCache.at < CACHE_TTL) {
66
- return plannerCache
67
- }
68
-
69
65
  const file = questPlannerStatePath()
70
66
  try {
71
67
  const stat = fs.statSync(file)
@@ -189,8 +185,10 @@ function expandCompleted(completed, available) {
189
185
  }
190
186
  }
191
187
 
192
- // 现在还能接的任务,一定没完成;数据互相矛盾时以「可接」为准
193
- for (const no of available) result.delete(no)
188
+ // 还能接的任务不算完成;但如果它同时出现在「确定完成」里,以确定完成为准
189
+ for (const no of available) {
190
+ if (!completed.has(no)) result.delete(no)
191
+ }
194
192
  return result
195
193
  }
196
194
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poi-plugin-inventory-cleaner",
3
- "version": "1.16.1",
3
+ "version": "1.17.1",
4
4
  "description": "库存清理大师:对照改修攻略与保留上限,找出囤积过量、可以清理的装备,并标出不能拆的改修材料。",
5
5
  "main": "index.js",
6
6
  "files": [