Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/locales/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export const en = {
"m.claimNextAt": " — available again after {time}",
"m.refreshClaimDone": "Refreshed {n} accounts — {k} with claimable plans",
"m.refreshClaimAcctErr": "\"{name}\" refresh failed: {err}",
"m.refreshClaimOneOk": "\"{name}\" refreshed — has claimable plans",
"m.refreshClaimOneNone": "\"{name}\" refreshed — no claimable plans",
"m.autoClaimOn": "Auto claim enabled",
"m.autoClaimOnDetail": "Checks immediately once enabled, then every 10 minutes",
"m.autoClaimInteractive": "\"{name}\" needs manual verification — auto claim skipped",
Expand Down Expand Up @@ -109,6 +111,7 @@ export const en = {
"btn.refreshClaimTitle": "Activate event eligibility for every account and re-check claimable plans (rate-limited)",
"btn.refreshClaimRunning": "Refresh {done}/{total}",
"btn.refreshClaimCooldownTitle": "Too frequent — retry in {n}s",
"btn.refreshClaimOneTitle": "Activate event eligibility for this account and re-check claimable plans (rate-limited)",
"btn.relogin": "Re-login needed",
"btn.reloginTitle": "This account's snapshot lacks the login info needed for event eligibility — delete it, then click \"Save login\" to re-capture (your current login is not affected)",
"btn.jwtExpired": "Login expired",
Expand Down
3 changes: 3 additions & 0 deletions src/locales/zh.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export const zh = {
"m.claimNextAt": ",{time} 后可再领",
"m.refreshClaimDone": "已刷新 {n} 个账号,{k} 个有可领套餐",
"m.refreshClaimAcctErr": "「{name}」刷新失败:{err}",
"m.refreshClaimOneOk": "「{name}」资格已刷新,当前有可领套餐",
"m.refreshClaimOneNone": "「{name}」资格已刷新,暂无可领套餐",
"m.autoClaimOn": "已开启自动领取",
"m.autoClaimOnDetail": "开启后立即检测一次,此后每 10 分钟一次",
"m.autoClaimInteractive": "「{name}」需人工验证,已跳过自动领取",
Expand Down Expand Up @@ -109,6 +111,7 @@ export const zh = {
"btn.refreshClaimTitle": "为全部账号激活活动资格并重新查询可领套餐(有频率限制)",
"btn.refreshClaimRunning": "刷新资格 {done}/{total}",
"btn.refreshClaimCooldownTitle": "操作太频繁,{n} 秒后可再次刷新",
"btn.refreshClaimOneTitle": "为该账号激活活动资格并重新查询可领套餐(有频率限制)",
"btn.relogin": "需重新登录",
"btn.reloginTitle": "该账号快照缺少活动资格所需的登录信息:删除该账号后点「保存登录」重新入库即可(不影响当前登录)",
"btn.jwtExpired": "登录已过期",
Expand Down
44 changes: 43 additions & 1 deletion src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,40 @@ const actions = {
toast(t("m.refreshClaimDone", { n: ids.length, k: okCount }), "ok");
},

async refreshClaimOne(id) {
const now = Date.now();
if (refreshClaim.running || claimAllRunning || claimActive) {
toast(t("m.claimBusy"), "warn");
return;
}
if (now < refreshClaim.cooldownUntil) {
toast(t("btn.refreshClaimCooldownTitle", { n: Math.ceil((refreshClaim.cooldownUntil - now) / 1000) }), "warn");
return;
}
const name = state?.accounts.find((a) => a.id === id)?.name || id;
refreshClaim = { running: true, done: 0, total: 1, cooldownUntil: 0 };
let hasPlans = false;
try {
claimable[id] = { plans: claimable[id]?.plans || [], busy: true };
if (!uiLocked()) render();
try {
const r = await invoke("claim_refresh", { id });
claimable[id] = { plans: r.plans || [], err: null, busy: false };
hasPlans = (r.plans || []).length > 0;
if (r.activationError) toast(t("m.refreshClaimAcctErr", { name, err: stripErr(r.activationError) }), "warn");
} catch (e) {
claimable[id] = { plans: claimable[id]?.plans || [], err: String(e), busy: false };
toast(t("m.refreshClaimAcctErr", { name, err: stripErr(e) }), "err");
}
scheduleNext(id);
} finally {
refreshClaim.running = false;
refreshClaim.cooldownUntil = Date.now() + REFRESH_CLAIM_COOLDOWN_MS;
if (!uiLocked()) render();
}
toast(hasPlans ? t("m.refreshClaimOneOk", { name }) : t("m.refreshClaimOneNone", { name }), "ok");
},

async toggleAutoClaim() {
if (autoToggleBusy) return;
const next = !state.auto_claim;
Expand Down Expand Up @@ -754,6 +788,13 @@ function render() {
? unsaved ? t("m.status.unsaved") : t("m.status.safe")
: t("m.status.loggedOut");

const rOneCooling = Date.now() < refreshClaim.cooldownUntil;
const rOneBusy = refreshClaim.running && refreshClaim.total === 1;
const rOneDisabled = refreshClaim.running || claimAllRunning || claimActive || autoClaimRunning || rOneCooling;
const rOneTitle = refreshClaim.running || !rOneCooling
? t("btn.refreshClaimOneTitle")
: t("btn.refreshClaimCooldownTitle", { n: Math.ceil((refreshClaim.cooldownUntil - Date.now()) / 1000) });

const rows = s.accounts.map((a) => {
const isActive = a.is_active;
if (renaming === a.id) { return `
Expand Down Expand Up @@ -788,6 +829,7 @@ function render() {
<div class="row-meta">${meta}</div>
</div>
<div class="row-actions">
<button class="icon-btn${rOneBusy ? " spinning" : ""}" title="${esc(rOneTitle)}" aria-label="${t("btn.refreshClaim")}" click="actions.refreshClaimOne('${a.id}')" ${rOneDisabled ? "disabled" : ""}>${ic("refresh", 16)}</button>
<button class="icon-btn" title="${t("btn.quota")}" aria-label="${t("btn.quota")}" click="actions.acctQuota('${a.id}')">${ic("gauge", 16)}</button>
<button class="icon-btn" title="${t("btn.rename")}" aria-label="${t("btn.rename")}" click="actions.rename('${a.id}')">${ic("pen", 16)}</button>
<button class="icon-btn" title="${t("btn.export")}" aria-label="${t("btn.export")}" click="actions.exportOne('${a.id}')">${ic("export", 16)}</button>
Expand Down Expand Up @@ -835,7 +877,7 @@ function render() {
title="${Date.now() < refreshClaim.cooldownUntil && !refreshClaim.running
? esc(t("btn.refreshClaimCooldownTitle", { n: Math.ceil((refreshClaim.cooldownUntil - Date.now()) / 1000) }))
: esc(t("btn.refreshClaimTitle"))}">
${ic("refresh", 16)} ${refreshClaim.running
${ic("refresh", 16)} ${refreshClaim.running && refreshClaim.total > 1
? esc(t("btn.refreshClaimRunning", { done: refreshClaim.done, total: refreshClaim.total }))
: esc(t("btn.refreshClaim"))}
</button>`
Expand Down
3 changes: 3 additions & 0 deletions src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,9 @@ input:focus-visible,
}
.icon-btn:hover { color: var(--ink); border-color: var(--hairline); background: var(--panel-2); }
.icon-btn.danger:hover { color: var(--red); border-color: var(--red-dim); background: rgba(224, 82, 82, .08); }
.icon-btn.spinning { color: var(--ink); }
.icon-btn.spinning .ic { animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

.btn-switch {
border: 1px solid var(--amber-deep);
Expand Down