dsh-ios-webview-app-control 0.2.1 → 0.2.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # 更新记录
2
2
 
3
+ ## 0.2.2 — 2026-11-03
4
+
5
+ - 修复设置页环境面板在准备结束后仍挂着“步骤/字节数/进度条”的问题:只有准备进行中(busy)才输出并渲染过程信息,就绪、失败、取消后的公开状态不再保留 step/progress。
6
+ - 修复从插件列表启用后准备面板一直停留、要切换页面才消失的问题:环境达到 ready 时激活引导自动收起;失败、取消、未准备状态仍保留面板供操作。
7
+
3
8
  ## 0.2.1 — 2026-10-31
4
9
 
5
10
  - README 按 npm 包页面的阅读顺序重组,补上 npm 安装方式和可直接跑的 CLI 示例,并把验证快照与安装要求的表述分开。
package/lib/client.js CHANGED
@@ -108,6 +108,7 @@ window.__ModuleLoader__.load({
108
108
  const [revision, setRevision] = React.useState(0);
109
109
  const live = React.useRef(null);
110
110
  const confirmedButton = React.useRef(null);
111
+ const dismissed = React.useRef(false);
111
112
  const panelId = React.useId();
112
113
  React.useEffect(() => {
113
114
  const control = new AbortController();
@@ -135,6 +136,14 @@ window.__ModuleLoader__.load({
135
136
  };
136
137
  }, [revision]);
137
138
  React.useEffect(() => { if (confirmCleanup) confirmedButton.current?.focus(); }, [confirmCleanup]);
139
+ // Activation guidance exists to get the environment ready, so it closes
140
+ // itself once preparation settles in a state that needs no action.
141
+ const settledReady = snapshot !== null && snapshot.phase === 'ready' && snapshot.busy !== true;
142
+ React.useEffect(() => {
143
+ if (!props.activation || !settledReady || dismissed.current) return;
144
+ dismissed.current = true;
145
+ if (typeof props.onDismiss === 'function') props.onDismiss();
146
+ }, [props.activation, settledReady, props.onDismiss]);
138
147
  async function run(action) {
139
148
  const control = live.current;
140
149
  if (!control || control.signal.aborted || (working && !(action === 'cancel' && working === 'prepare'))) return;
@@ -158,7 +167,10 @@ window.__ModuleLoader__.load({
158
167
  return h('div', { className: 'iosenv-row', key: label }, h('dt', null, label), h('dd', { className: mono ? 'iosenv-mono' : undefined }, value || t('missing')));
159
168
  }
160
169
  const busy = snapshot?.busy === true;
161
- const progress = snapshot?.progress;
170
+ // Step and byte counts describe an in-flight preparation only; once it
171
+ // settles they must not read like a stalled download.
172
+ const progress = busy ? snapshot?.progress : null;
173
+ const step = busy ? snapshot?.step : null;
162
174
  const total = progress?.totalBytes;
163
175
  const progressText = progress ? t(total === undefined ? 'bytesUnknown' : 'bytes', { completed: progress.completedBytes, total }) : null;
164
176
  const phase = snapshot?.phase;
@@ -175,7 +187,7 @@ window.__ModuleLoader__.load({
175
187
  h('p', { className: 'iosenv-muted' }, t('intro')),
176
188
  h('div', { className: 'iosenv-state', role: 'status', 'aria-live': 'polite' },
177
189
  h('div', { className: 'iosenv-statehead' }, h('span', null, t('phase')), h('strong', { className: 'iosenv-phase' }, snapshot ? t(`phase.${phase}`) : t('loading'))),
178
- snapshot?.step ? h('p', { className: 'iosenv-muted' }, `${t('step')}: ${snapshot.step}`) : null,
190
+ step ? h('p', { className: 'iosenv-muted' }, `${t('step')}: ${step}`) : null,
179
191
  progressText ? h('p', null, progressText) : null,
180
192
  progress ? h('progress', { className: 'iosenv-progress', 'aria-label': t('progress'), ...(total > 0 ? { max: total, value: Math.min(progress.completedBytes, total) } : {}) }) : null,
181
193
  phase === 'ready' ? h('p', { className: 'iosenv-muted' }, t('readyHint')) : null),
@@ -141,7 +141,15 @@ export class EnvironmentManager {
141
141
  }
142
142
  status() {
143
143
  const state=clone(this.snapshot);
144
- state.step=state.step||state.stage||state.phase;
144
+ // Step and byte counters describe an in-flight preparation only. Once it
145
+ // settles they read like a stalled download, so a public status drops them.
146
+ if(BUSY_PHASES.has(state.phase)){
147
+ state.step=state.step||state.stage||state.phase;
148
+ state.progress=state.bytes.total>0?{completedBytes:state.bytes.downloaded,totalBytes:state.bytes.total}:null;
149
+ }else{
150
+ state.step='';
151
+ state.progress=null;
152
+ }
145
153
  if(!state.python?.path||!state.python?.version||!['host','private'].includes(state.python?.source))state.python=null;
146
154
  if(typeof state.pymobiledevice3!=='string')delete state.pymobiledevice3;
147
155
  return state;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-ios-webview-app-control",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Business-free DSH tools for inspectable iOS WebView/hybrid apps only.",
5
5
  "type": "module",
6
6
  "license": "MIT",