mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 21:15:32 +09:00
fix(app): show download icon for shell updates (#3471)
This commit is contained in:
1 parent
5f5e26a8d4
commit
7c16d424ce
5 files changed
+38
-15
No files matched your search
@@ -155,6 +155,7 @@ class Updater {
|
|||||||
private unsubscribeNativeEvents: (() => void) | null = null;
|
private unsubscribeNativeEvents: (() => void) | null = null;
|
||||||
private unsubscribeDesktopUpdate: (() => void) | null = null;
|
private unsubscribeDesktopUpdate: (() => void) | null = null;
|
||||||
private desktopUpdateReported = false;
|
private desktopUpdateReported = false;
|
||||||
|
private desktopUpdateReportedReplacesShell = false;
|
||||||
private desktopUpdateRunning = false;
|
private desktopUpdateRunning = false;
|
||||||
private olderShellModuleUpdateReady = false;
|
private olderShellModuleUpdateReady = false;
|
||||||
private olderShellUpdateDownloaded = false;
|
private olderShellUpdateDownloaded = false;
|
||||||
@@ -203,6 +204,10 @@ class Updater {
|
|||||||
return this.desktopUpdateReported || this.olderShellModuleUpdateReady || this.olderShellUpdateAvailable;
|
return this.desktopUpdateReported || this.olderShellModuleUpdateReady || this.olderShellUpdateAvailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get desktopUpdateReplacesShell(): boolean {
|
||||||
|
return (this.desktopUpdateReported && this.desktopUpdateReportedReplacesShell) || this.olderShellUpdateAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
private get olderShellUpdateAvailable(): boolean {
|
private get olderShellUpdateAvailable(): boolean {
|
||||||
const electronApi = getElectronAPI();
|
const electronApi = getElectronAPI();
|
||||||
if (electronApi == null || electronApi.desktopUpdate != null || electronApi.updaterInstall == null) {
|
if (electronApi == null || electronApi.desktopUpdate != null || electronApi.updaterInstall == null) {
|
||||||
@@ -281,6 +286,7 @@ class Updater {
|
|||||||
this.unsubscribeDesktopUpdate = desktopUpdate.onStateChanged((state) => {
|
this.unsubscribeDesktopUpdate = desktopUpdate.onStateChanged((state) => {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.desktopUpdateReported = state.available;
|
this.desktopUpdateReported = state.available;
|
||||||
|
this.desktopUpdateReportedReplacesShell = state.replacesShell === true;
|
||||||
this.desktopUpdateRunning = state.updating === true;
|
this.desktopUpdateRunning = state.updating === true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -314,6 +320,7 @@ class Updater {
|
|||||||
const state = await desktopUpdate.state();
|
const state = await desktopUpdate.state();
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.desktopUpdateReported = state.available;
|
this.desktopUpdateReported = state.available;
|
||||||
|
this.desktopUpdateReportedReplacesShell = state.replacesShell === true;
|
||||||
this.desktopUpdateRunning = state.updating === true;
|
this.desktopUpdateRunning = state.updating === true;
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -669,6 +676,7 @@ class Updater {
|
|||||||
this.unsubscribeDesktopUpdate = null;
|
this.unsubscribeDesktopUpdate = null;
|
||||||
}
|
}
|
||||||
this.desktopUpdateReported = false;
|
this.desktopUpdateReported = false;
|
||||||
|
this.desktopUpdateReportedReplacesShell = false;
|
||||||
this.desktopUpdateRunning = false;
|
this.desktopUpdateRunning = false;
|
||||||
this.olderShellModuleUpdateReady = false;
|
this.olderShellModuleUpdateReady = false;
|
||||||
this.olderShellUpdateDownloaded = false;
|
this.olderShellUpdateDownloaded = false;
|
||||||
|
|||||||
+6
-2
@@ -8,7 +8,7 @@ import FocusRing from '@app/features/ui/focus_ring/FocusRing';
|
|||||||
import {Tooltip} from '@app/features/ui/tooltip/Tooltip';
|
import {Tooltip} from '@app/features/ui/tooltip/Tooltip';
|
||||||
import {msg} from '@lingui/core/macro';
|
import {msg} from '@lingui/core/macro';
|
||||||
import {useLingui} from '@lingui/react/macro';
|
import {useLingui} from '@lingui/react/macro';
|
||||||
import {ArrowClockwiseIcon} from '@phosphor-icons/react';
|
import {ArrowClockwiseIcon, DownloadSimpleIcon} from '@phosphor-icons/react';
|
||||||
import {observer} from 'mobx-react-lite';
|
import {observer} from 'mobx-react-lite';
|
||||||
import {useCallback} from 'react';
|
import {useCallback} from 'react';
|
||||||
|
|
||||||
@@ -67,6 +67,10 @@ export const UpdaterIcon = observer(() => {
|
|||||||
? i18n._(CLICK_TO_RELOAD_AND_UPDATE_DESCRIPTOR, {version, productName: RuntimeConfig.productName})
|
? i18n._(CLICK_TO_RELOAD_AND_UPDATE_DESCRIPTOR, {version, productName: RuntimeConfig.productName})
|
||||||
: i18n._(CLICK_TO_RELOAD_AND_UPDATE_2_DESCRIPTOR, {productName: RuntimeConfig.productName});
|
: i18n._(CLICK_TO_RELOAD_AND_UPDATE_2_DESCRIPTOR, {productName: RuntimeConfig.productName});
|
||||||
}
|
}
|
||||||
|
const Icon =
|
||||||
|
affordance === 'manual' || (affordance === 'desktop' && Updater.desktopUpdateReplacesShell)
|
||||||
|
? DownloadSimpleIcon
|
||||||
|
: ArrowClockwiseIcon;
|
||||||
return (
|
return (
|
||||||
<Tooltip text={tooltip} position="bottom" data-flx="channel.channel-header-components.updater-icon.tooltip">
|
<Tooltip text={tooltip} position="bottom" data-flx="channel.channel-header-components.updater-icon.tooltip">
|
||||||
<FocusRing offset={-2} data-flx="channel.channel-header-components.updater-icon.focus-ring">
|
<FocusRing offset={-2} data-flx="channel.channel-header-components.updater-icon.focus-ring">
|
||||||
@@ -79,7 +83,7 @@ export const UpdaterIcon = observer(() => {
|
|||||||
aria-label={tooltip}
|
aria-label={tooltip}
|
||||||
data-flx="channel.channel-header-components.updater-icon.button.click"
|
data-flx="channel.channel-header-components.updater-icon.button.click"
|
||||||
>
|
>
|
||||||
<ArrowClockwiseIcon
|
<Icon
|
||||||
weight="bold"
|
weight="bold"
|
||||||
className={affordance === 'updating' ? styles.updateIconSpinning : styles.updateIcon}
|
className={affordance === 'updating' ? styles.updateIconSpinning : styles.updateIcon}
|
||||||
data-flx="channel.channel-header-components.updater-icon.update-icon"
|
data-flx="channel.channel-header-components.updater-icon.update-icon"
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ function deferred() {
|
|||||||
|
|
||||||
describe('DesktopUpdateGate', () => {
|
describe('DesktopUpdateGate', () => {
|
||||||
test('nothing is available and nothing starts before the bootstrap arms the gate', async () => {
|
test('nothing is available and nothing starts before the bootstrap arms the gate', async () => {
|
||||||
assert.deepEqual(getDesktopUpdateState(), {available: false, updating: false});
|
assert.deepEqual(getDesktopUpdateState(), {available: false, updating: false, replacesShell: false});
|
||||||
assert.deepEqual(await checkDesktopUpdateNow(), {available: false, updating: false});
|
assert.deepEqual(await checkDesktopUpdateNow(), {available: false, updating: false, replacesShell: false});
|
||||||
assert.equal(startDesktopUpdate(), false);
|
assert.equal(startDesktopUpdate(), false);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -44,17 +44,17 @@ describe('DesktopUpdateGate', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.deepEqual(await checkDesktopUpdateNow(), {available: true, updating: false});
|
assert.deepEqual(await checkDesktopUpdateNow(), {available: true, updating: false, replacesShell: false});
|
||||||
assert.equal(startDesktopUpdate(), true);
|
assert.equal(startDesktopUpdate(), true);
|
||||||
assert.equal(startDesktopUpdate(), false, 'a second click while the update runs is a no-op');
|
assert.equal(startDesktopUpdate(), false, 'a second click while the update runs is a no-op');
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
getDesktopUpdateState(),
|
getDesktopUpdateState(),
|
||||||
{available: false, updating: true},
|
{available: false, updating: true, replacesShell: false},
|
||||||
'the affordance hides the moment it is clicked',
|
'the affordance hides the moment it is clicked',
|
||||||
);
|
);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
await checkDesktopUpdateNow(),
|
await checkDesktopUpdateNow(),
|
||||||
{available: false, updating: true},
|
{available: false, updating: true, replacesShell: false},
|
||||||
'a poll during the update changes nothing',
|
'a poll during the update changes nothing',
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -62,11 +62,11 @@ describe('DesktopUpdateGate', () => {
|
|||||||
await new Promise((resolve) => setImmediate(resolve));
|
await new Promise((resolve) => setImmediate(resolve));
|
||||||
|
|
||||||
assert.equal(starts, 1);
|
assert.equal(starts, 1);
|
||||||
assert.deepEqual(getDesktopUpdateState(), {available: false, updating: false});
|
assert.deepEqual(getDesktopUpdateState(), {available: false, updating: false, replacesShell: false});
|
||||||
assert.deepEqual(states, [
|
assert.deepEqual(states, [
|
||||||
{available: true, updating: false},
|
{available: true, updating: false, replacesShell: false},
|
||||||
{available: false, updating: true},
|
{available: false, updating: true, replacesShell: false},
|
||||||
{available: false, updating: false},
|
{available: false, updating: false, replacesShell: false},
|
||||||
]);
|
]);
|
||||||
stop();
|
stop();
|
||||||
});
|
});
|
||||||
@@ -111,7 +111,7 @@ describe('DesktopUpdateGate', () => {
|
|||||||
pending.resolve();
|
pending.resolve();
|
||||||
await background;
|
await background;
|
||||||
|
|
||||||
assert.deepEqual(await manual, {available: true, updating: false});
|
assert.deepEqual(await manual, {available: true, updating: false, replacesShell: true});
|
||||||
assert.deepEqual(calls, [false, true]);
|
assert.deepEqual(calls, [false, true]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@ describe('DesktopUpdateGate', () => {
|
|||||||
assert.equal(startDesktopUpdate(), true);
|
assert.equal(startDesktopUpdate(), true);
|
||||||
await new Promise((resolve) => setImmediate(resolve));
|
await new Promise((resolve) => setImmediate(resolve));
|
||||||
|
|
||||||
assert.deepEqual(getDesktopUpdateState(), {available: true, updating: false});
|
assert.deepEqual(getDesktopUpdateState(), {available: true, updating: false, replacesShell: true});
|
||||||
assert.equal(startDesktopUpdate(), true);
|
assert.equal(startDesktopUpdate(), true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -24,6 +24,7 @@ interface DesktopUpdateGateState {
|
|||||||
checking: {readonly manual: boolean; readonly settled: Promise<void>} | null;
|
checking: {readonly manual: boolean; readonly settled: Promise<void>} | null;
|
||||||
notifiedAvailable: boolean;
|
notifiedAvailable: boolean;
|
||||||
notifiedUpdating: boolean;
|
notifiedUpdating: boolean;
|
||||||
|
notifiedReplacesShell: boolean;
|
||||||
readonly listeners: Set<DesktopUpdateStateListener>;
|
readonly listeners: Set<DesktopUpdateStateListener>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,6 +35,7 @@ const gateState: DesktopUpdateGateState = {
|
|||||||
checking: null,
|
checking: null,
|
||||||
notifiedAvailable: false,
|
notifiedAvailable: false,
|
||||||
notifiedUpdating: false,
|
notifiedUpdating: false,
|
||||||
|
notifiedReplacesShell: false,
|
||||||
listeners: new Set(),
|
listeners: new Set(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -42,9 +44,11 @@ function isAvailable(check: DesktopUpdateCheck | null): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getDesktopUpdateState(): DesktopUpdateState {
|
export function getDesktopUpdateState(): DesktopUpdateState {
|
||||||
|
const available = gateState.running == null && isAvailable(gateState.lastCheck);
|
||||||
return {
|
return {
|
||||||
available: gateState.running == null && isAvailable(gateState.lastCheck),
|
available,
|
||||||
updating: gateState.running != null,
|
updating: gateState.running != null,
|
||||||
|
replacesShell: available && gateState.lastCheck?.shellNewer === true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,11 +59,17 @@ export function desktopUpdateReplacesShell(): boolean {
|
|||||||
function notify(): void {
|
function notify(): void {
|
||||||
const state = getDesktopUpdateState();
|
const state = getDesktopUpdateState();
|
||||||
const updating = state.updating === true;
|
const updating = state.updating === true;
|
||||||
if (state.available === gateState.notifiedAvailable && updating === gateState.notifiedUpdating) {
|
const replacesShell = state.replacesShell === true;
|
||||||
|
if (
|
||||||
|
state.available === gateState.notifiedAvailable &&
|
||||||
|
updating === gateState.notifiedUpdating &&
|
||||||
|
replacesShell === gateState.notifiedReplacesShell
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
gateState.notifiedAvailable = state.available;
|
gateState.notifiedAvailable = state.available;
|
||||||
gateState.notifiedUpdating = updating;
|
gateState.notifiedUpdating = updating;
|
||||||
|
gateState.notifiedReplacesShell = replacesShell;
|
||||||
for (const listener of Array.from(gateState.listeners)) {
|
for (const listener of Array.from(gateState.listeners)) {
|
||||||
try {
|
try {
|
||||||
listener(state);
|
listener(state);
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ export interface DesktopModuleAPI {
|
|||||||
export interface DesktopUpdateState {
|
export interface DesktopUpdateState {
|
||||||
readonly available: boolean;
|
readonly available: boolean;
|
||||||
readonly updating?: boolean;
|
readonly updating?: boolean;
|
||||||
|
readonly replacesShell?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DesktopUpdateAPI {
|
export interface DesktopUpdateAPI {
|
||||||
|
|||||||
Reference in new issue
Block a user