Merge branch 'disable-error-alerts'

This commit is contained in:
Samuel Elliott 2025-09-17 17:35:27 +01:00
commit fbaa188e13
No known key found for this signature in database
GPG Key ID: 8420C7CDE43DC4D6
8 changed files with 76 additions and 8 deletions

View File

@ -30,6 +30,8 @@ function _Preferences(props: {
const [login_item, ,, forceRefreshLoginItem] = useAsync(useCallback(() => ipc.getLoginItemSettings(), [ipc]));
const [show_error_alerts, , show_error_alerts_state, forceRefreshErrorAlerts] = useAsync(useCallback(() => ipc.getShowErrorAlerts(), [ipc]));
const setOpenAtLogin = useCallback(async (open_at_login: boolean | 'mixed') => {
await ipc.setLoginItemSettings({...login_item!, startup_enabled: !!open_at_login});
forceRefreshLoginItem();
@ -39,6 +41,11 @@ function _Preferences(props: {
forceRefreshLoginItem();
}, [ipc, login_item]);
const setShowErrorAlerts = useCallback(async (show_error_alerts: boolean | 'mixed') => {
await ipc.setShowErrorAlerts(!!show_error_alerts);
forceRefreshErrorAlerts();
}, [ipc]);
const [discord_users, discord_users_error, discord_users_state, forceRefreshDiscordUsers] =
useAsync(useCallback(() => ipc.getDiscordUsers(), [ipc]));
@ -97,7 +104,8 @@ function _Preferences(props: {
useEventListener(events, 'window:refresh', () => (
forceRefreshAccounts(), forceRefreshLoginItem(),
forceRefreshDiscordUsers(), forceRefreshDiscordOptions()
forceRefreshDiscordUsers(), forceRefreshDiscordOptions(),
forceRefreshErrorAlerts()
), []);
if (!users ||
@ -280,6 +288,26 @@ function _Preferences(props: {
<Text style={[styles.help, theme.text]}>{t('splatnet3.discord_help_2')}</Text>
</View>
</View>
<View style={styles.section}>
<View style={styles.sectionLeft}>
<Text style={[styles.label, theme.text]}>{t('miscellaneous.heading')}</Text>
</View>
<View style={styles.sectionRight}>
<View style={[styles.checkboxContainer]}>
<CheckBox
value={show_error_alerts ?? true}
onValueChange={setShowErrorAlerts}
color={'#' + (accent_colour ?? DEFAULT_ACCENT_COLOUR)}
style={styles.checkbox}
/>
<TouchableOpacity style={styles.checkboxLabel} onPress={() => setShowErrorAlerts(!(show_error_alerts ?? true))}>
<Text style={[styles.checkboxLabelText, theme.text]}>{t('miscellaneous.show_error_alerts')}</Text>
</TouchableOpacity>
</View>
<Text style={[styles.help, theme.text]}>{t('miscellaneous.show_error_alerts_help')}</Text>
</View>
</View>
</View>;
}

View File

@ -292,6 +292,12 @@ export const preferences_window = {
discord_help_1: 'Uses SplatNet 3 to retrieve additional presence information while playing Splatoon 3. You must be using a secondary Nintendo Account that is friends with your main account to fetch your presence, and the secondary account must be able to access SplatNet 3.',
discord_help_2: 'When using a presence URL that returns Splatoon 3 data additional presence information will be shown regardless of this setting.',
},
miscellaneous: {
heading: 'Miscellaneous',
show_error_alerts: 'Show error alerts',
show_error_alerts_help: 'Shows an alert when an error occurs while updating presence. If this is disabled, nxapi will delay updates after errors.',
},
};
export const friend_window = {

View File

@ -90,6 +90,9 @@ export function setupIpc(appinstance: App, ipcMain: IpcMain) {
handle('systemPreferences:getloginitem', () => appinstance.store.getLoginItem());
handle('systemPreferences:setloginitem', (e, settings: LoginItemOptions) => appinstance.store.setLoginItem(settings));
handle('preferences:getshowerroralerts', () => storage.getItem('ShowErrorAlertsPreference').then(s => s ?? false));
handle('preferences:setshowerroralerts', (e, show: boolean) => storage.setItem('ShowErrorAlertsPreference', show));
handle('update:get', () => appinstance.updater.cache ?? appinstance.updater.check());
handle('update:check', () => appinstance.updater.check());
handle('statusupdates:get', () => appinstance.statusupdates.cache ?? []);

View File

@ -69,6 +69,9 @@ export class PresenceMonitorManager {
defaultId: 0,
});
const show_error_alerts: boolean = await this.app.store.storage.getItem('ShowErrorAlertsPreference') ?? false;
if (!show_error_alerts) return ErrorResult.DEFER;
if (response === 1) {
return ErrorResult.RETRY;
}
@ -396,6 +399,9 @@ export class PresenceMonitorManager {
return LoopResult.OK;
}
const show_error_alerts: boolean = await this.app.store.storage.getItem('ShowErrorAlertsPreference') ?? false;
if (!show_error_alerts) return LoopResult.DEFER_NEXT_UPDATE;
const {response} = await showErrorDialog({
message: err.name + ' updating presence monitor',
error: err,

View File

@ -50,6 +50,9 @@ const ipc = {
getLoginItemSettings: () => inv<LoginItem>('systemPreferences:getloginitem'),
setLoginItemSettings: (settings: LoginItemOptions) => inv('systemPreferences:setloginitem', settings),
getShowErrorAlerts: () => inv<boolean>('preferences:getshowerroralerts'),
setShowErrorAlerts: (show: boolean) => inv('preferences:setshowerroralerts', show),
getUpdateData: () => inv<UpdateCacheData | null>('update:get'),
checkUpdates: () => inv<UpdateCacheData | null>('update:check'),
getStatusUpdateData: () => inv<StatusUpdate[] | null>('statusupdates:get'),

View File

@ -91,6 +91,7 @@ export default class SplatNet3Monitor extends EmbeddedLoop {
debug('Error authenticating to SplatNet 3', err);
const result = await this.discord_presence.handleError(err as Error);
if (result === ErrorResult.RETRY) return this.init();
if (result === ErrorResult.DEFER) return this.errors++, LoopResult.DEFER_NEXT_UPDATE;
if (result === ErrorResult.STOP) return LoopResult.STOP;
}
@ -168,6 +169,7 @@ export default class SplatNet3Monitor extends EmbeddedLoop {
async handleError(err: Error) {
const result = await this.discord_presence.handleError(err as Error);
if (result === ErrorResult.RETRY) return LoopResult.OK_SKIP_INTERVAL;
if (result === ErrorResult.DEFER) return LoopResult.DEFER_NEXT_UPDATE;
this.friend = null;
this.discord_presence.refreshPresence();

View File

@ -148,5 +148,6 @@ export interface ExternalMonitor<T = unknown> extends EmbeddedLoop {
export enum ErrorResult {
STOP,
RETRY,
DEFER,
IGNORE,
}

View File

@ -4,6 +4,7 @@ const debug = createDebug('nxapi:util:loop');
export default abstract class Loop {
update_interval = 60;
errors = 0;
init(): void | Promise<LoopResult | void> {}
@ -13,8 +14,11 @@ export default abstract class Loop {
try {
const result = init ? await this.init() : await this.update();
this.errors = 0;
return result ?? (init ? LoopResult.OK_SKIP_INTERVAL : LoopResult.OK);
} catch (err) {
this.errors++;
return this.handleError(err as any);
}
}
@ -23,6 +27,10 @@ export default abstract class Loop {
throw err;
}
get next_update_interval() {
return this.update_interval * Math.min(this.errors / 2, 20);
}
private is_loop_active = 0;
async loop(init = false) {
@ -38,6 +46,14 @@ export default abstract class Loop {
await new Promise(rs => setTimeout(this.timeout_resolve = rs, this.update_interval * 1000));
}
}
if (result === LoopResult.DEFER_NEXT_UPDATE) {
if (this.skip_interval_once) {
this.skip_interval_once = false;
} else {
await new Promise(rs => setTimeout(this.timeout_resolve = rs, this.next_update_interval * 1000));
}
return LoopResult.DEFER_NEXT_UPDATE;
}
if (result === LoopResult.STOP) {
return LoopResult.STOP;
}
@ -62,11 +78,13 @@ export default abstract class Loop {
const LoopRunOk = Symbol('LoopRunOk');
const LoopRunOkSkipInterval = Symbol('LoopRunOkSkipInterval');
const LoopRunIncrementInterval = Symbol('LoopRunIncrementInterval');
const LoopRunStop = Symbol('LoopRunStopNow');
export enum LoopResult {
OK = LoopRunOk as any,
OK_SKIP_INTERVAL = LoopRunOkSkipInterval as any,
DEFER_NEXT_UPDATE = LoopRunIncrementInterval as any,
STOP = LoopRunStop as any,
}
@ -92,25 +110,26 @@ export abstract class EmbeddedLoop extends Loop {
private async _run() {
this._running++;
const i = this._running;
let init = true;
try {
const result = await this.loop(true);
if (result === LoopResult.STOP) return;
while (i === this._running) {
const result = await this.loop();
const result = await this.loop(init);
if (init && result !== LoopResult.DEFER_NEXT_UPDATE) {
init = false;
}
if (result === LoopResult.STOP) {
await this.onStop?.();
if (!init) await this.onStop?.();
return;
}
}
if (this._running === 0 && !this.onStop) {
if (this._running === 0 && !init && !this.onStop) {
// Run one more time after the loop ends
const result = await this.loopRun();
}
} finally {
this._running = 0;
}