Skip to content

Commit

Permalink
Merge pull request #3720 from sircharlo/feat/beta-updates
Browse files Browse the repository at this point in the history
* feat: allow users to receive beta updates

* fix: include prereleases when beta updates are enabled

* fix: fetchLatest logic

* fix: about modal update toggle placement; logo coloring when update toggle warrant attention

---------

Co-authored-by: Charles Olivier Savignac <[email protected]>
  • Loading branch information
sircharlo authored Dec 11, 2024
2 parents b1166e9 + ecc5c94 commit f71b90f
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 68 deletions.
1 change: 1 addition & 0 deletions src-electron/electron-preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ initWebsiteListeners();

const electronApi: ElectronApi = {
askForMediaAccess: () => send('askForMediaAccess'),
checkForUpdates: () => send('checkForUpdates'),
closeWebsiteWindow,
convertHeic,
convertPdfToImages,
Expand Down
3 changes: 3 additions & 0 deletions src-electron/main/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
unregisterAllShortcuts,
unregisterShortcut,
} from './shortcuts';
import { triggerUpdateCheck } from './updater';
import { getAppVersion, isSelf } from './utils';
import { logToWindow } from './window/window-base';
import { mainWindow, toggleAuthorizedClose } from './window/window-main';
Expand Down Expand Up @@ -83,6 +84,8 @@ handleIpcSend('toggleMediaWindow', (_e, show: boolean) => {

handleIpcSend('askForMediaAccess', askForMediaAccess);

handleIpcSend('checkForUpdates', () => triggerUpdateCheck());

handleIpcSend('setUrlVariables', (_e, variables: string) => {
setUrlVariables(JSON.parse(variables));
});
Expand Down
23 changes: 18 additions & 5 deletions src-electron/main/updater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,26 @@ export async function initUpdater() {
});
});

const disabled = await exists(
join(app.getPath('userData'), 'Global Preferences', 'disable-updates'),
);
if (!disabled && PLATFORM !== 'darwin') triggerUpdateCheck();
triggerUpdateCheck();
}

const triggerUpdateCheck = async (attempt = 1) => {
export const triggerUpdateCheck = async (attempt = 1) => {
// macOS auto-updates are not supported without code signing
if (PLATFORM === 'darwin') return;
if (
await exists(
join(app.getPath('userData'), 'Global Preferences', 'disable-updates'),
)
) {
return;
}

if (attempt === 1) {
autoUpdater.allowPrerelease = await exists(
join(app.getPath('userData'), 'Global Preferences', 'beta-updates'),
);
}

try {
const { default: isOnline } = await import('is-online');
const online = await isOnline();
Expand Down
110 changes: 84 additions & 26 deletions src/components/dialog/DialogAbout.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<q-dialog v-model="open">
<div
class="items-center q-pb-lg q-px-lg q-gutter-y-lg bg-secondary-contrast"
class="items-center q-pb-lg q-px-lg q-gutter-y-md bg-secondary-contrast"
>
<div class="row items-center">
<div class="col-shrink q-mr-md">
Expand All @@ -13,21 +13,6 @@
</div>
<div class="row items-center">
<div class="col">v{{ appVersion }}</div>
<div
:class="
'col text-right ' +
(!updatesEnabled ? 'text-negative text-weight-bold' : '')
"
>
<q-toggle
v-model="updatesEnabled"
checked-icon="mmm-check"
dense
:label="$t('auto-updates')"
left-label
unchecked-icon="mmm-clear"
/>
</div>
</div>
</div>
</div>
Expand All @@ -36,6 +21,11 @@
{{ $t('app-description') }}
</div>
</div>
<div class="row">
<div class="col">
{{ $t('app-issues') }}
</div>
</div>
<div class="row q-gutter-x-md">
<div class="col">
<q-btn
Expand Down Expand Up @@ -82,19 +72,76 @@
</q-btn>
</div>
</div>
<div class="row text-subtitle1">
{{ $t('app-updates') }}
</div>
<div class="row">
<div class="col">
{{ $t('app-issues') }}
<q-toggle
v-model="updatesEnabled"
checked-icon="mmm-check"
class="q-mr-sm"
:color="!updatesEnabled ? 'negative' : 'primary'"
dense
keep-color
:label="$t('auto-update-app')"
unchecked-icon="mmm-clear"
/>
<q-btn
v-if="!updatesEnabled"
color="negative"
flat
icon="mmm-warning"
round
size="sm"
>
<q-tooltip>
{{ $t('auto-update-app-explain') }}
</q-tooltip>
</q-btn>
</div>
</div>
<div v-if="updatesEnabled" class="row">
<div class="col">
<q-toggle
v-model="betaUpdatesEnabled"
checked-icon="mmm-check"
class="q-mr-sm"
:color="betaUpdatesEnabled ? 'negative' : 'primary'"
dense
keep-color
unchecked-icon="mmm-clear"
>
{{ $t('receive-beta-updates') }}
</q-toggle>
<q-btn
:color="betaUpdatesEnabled ? 'negative' : 'primary'"
flat
:icon="betaUpdatesEnabled ? 'mmm-warning' : 'mmm-info'"
round
size="sm"
>
<q-tooltip>
{{ $t('receive-beta-updates-explain') }}
</q-tooltip>
</q-btn>
</div>
</div>
<div class="row justify-end">
<q-btn v-close-popup flat>{{ $t('close') }}</q-btn>
<div class="row">
<div class="col text-right">
<q-btn v-close-popup flat :label="$t('close')" />
</div>
</div>
</div>
</q-dialog>
</template>
<script setup lang="ts">
import { disableUpdates, enableUpdates, updatesDisabled } from 'src/utils/fs';
import {
betaUpdatesDisabled,
toggleAutoUpdates,
toggleBetaUpdates,
updatesDisabled,
} from 'src/utils/fs';
import { onMounted, ref, watch } from 'vue';
const { getAppVersion, openExternal } = window.electronApi;
Expand All @@ -104,6 +151,7 @@ const open = defineModel<boolean>({ default: false });
const appVersion = ref('');
const updatesEnabled = ref(true);
const betaUpdatesEnabled = ref(false);
const loadAppVersion = async () => {
appVersion.value = await getAppVersion();
Expand All @@ -113,16 +161,26 @@ const getUpdatesEnabled = async () => {
updatesEnabled.value = !(await updatesDisabled());
};
const getBetaUpdatesEnabled = async () => {
betaUpdatesEnabled.value = !(await betaUpdatesDisabled());
};
onMounted(() => {
loadAppVersion();
getUpdatesEnabled();
getBetaUpdatesEnabled();
});
watch(updatesEnabled, (val) => {
toggleAutoUpdates(val);
});
watch(betaUpdatesEnabled, (val) => {
toggleBetaUpdates(val);
});
watch(updatesEnabled, (newUpdatesEnabled) => {
if (newUpdatesEnabled) {
enableUpdates();
} else {
disableUpdates();
}
defineExpose({
betaUpdatesEnabled,
updatesEnabled,
});
</script>
40 changes: 32 additions & 8 deletions src/components/header/HeaderBase.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,33 @@
bordered
class="bg-primary text-white text-bigger text-weight-medium"
>
<DialogAbout v-model="aboutModal" />
<div class="row items-center q-my-sm q-mr-md">
<div
class="row justify-center cursor-pointer"
style="width: 56px"
<DialogAbout ref="aboutInfo" v-model="aboutModal" />
<div class="row items-center q-mr-md">
<q-btn
:color="
!aboutInfo?.updatesEnabled || aboutInfo?.betaUpdatesEnabled
? 'negative'
: ''
"
round
style="width: 56px; height: 56px"
unelevated
@click="aboutModal = true"
>
<img src="~assets/img/logo-no-background.svg" />
</div>
<!-- @mouseout="hoveredLogo = false"
@mouseover="hoveredLogo = true" -->
<q-img
loading="lazy"
src="~assets/img/logo-no-background.svg"
width="40px"
/>
<!-- <q-badge
v-if="!aboutInfo?.updatesEnabled || aboutInfo?.betaUpdatesEnabled"
color="negative"
rounded
style="position: absolute; top: 12px; left: 38px"
/> -->
</q-btn>
<q-separator class="bg-semi-white-24 q-ml-none" inset vertical />
<div class="col q-ml-md flex items-center">
<div class="col-shrink items-center">
Expand Down Expand Up @@ -64,7 +82,7 @@ import DialogAbout from 'src/components/dialog/DialogAbout.vue';
// Stores
import { useCongregationSettingsStore } from 'src/stores/congregation-settings';
import { useCurrentStateStore } from 'src/stores/current-state';
import { ref } from 'vue';
import { /*computed,*/ ref } from 'vue';
import { useRoute } from 'vue-router';
// Sub-components
Expand All @@ -81,4 +99,10 @@ const currentState = useCurrentStateStore();
const { currentCongregation } = storeToRefs(currentState);
const aboutModal = ref(false);
const aboutInfo = ref<InstanceType<typeof DialogAbout> | null>(null);
// const hoveredLogo = ref(false);
// const activeLogo = computed(() => {
// return hoveredLogo.value || aboutModal.value;
// });
</script>
6 changes: 5 additions & 1 deletion src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"also-look-for-this-button-in-m-s-footer": "Also, look for this button in M³'s footer:",
"app-description": "Meeting Media Manager is a cross-platform app for displaying media at congregation meetings of Jehovah's Witnesses. It integrates with OBS Studio for one-click media display in both the Kingdom Hall and on Zoom. With its rich functionality and intuitive interface, M³ reduces the workload of audio/video servants. It supports all theocratic file formats, as well as PDF files and common media files. It can complement or even replace JW Library, as per your congregation needs.",
"app-issues": "If you're facing any issues or have found a bug, please create an Issue on our GitHub repository page or contact us via GitHub Discussions, describing the problem in detail. We will get back to you as soon as possible.",
"app-updates": "Application updates",
"applicationConfiguration": "Application configuration",
"applicationConfigurationDescription": "Customize this app's behavior and appearance",
"archive-file-found": "Archive files must be processed separately.",
Expand All @@ -27,7 +28,8 @@
"audio-bible": "Bible audio recording",
"audio-bible-media": "Audio recordings from the New World Translation",
"audio:": "Audio:",
"auto-updates": "Automatic updates",
"auto-update-app": "Automatically download and install application updates",
"auto-update-app-explain": "This option should always be enabled to receive the latest features, improvements, and bug fixes.",
"autoStartAtLogin": "Automatically start M³ on computer startup",
"autoStartAtLogin-explain": "M³ can start automatically when the computer is started.",
"autoStartMusic": "Automatically start background music before meetings",
Expand Down Expand Up @@ -286,6 +288,8 @@
"projecting": "Projecting",
"public-talk": "Public talk",
"public-talk-media": "Public talk media",
"receive-beta-updates": "Receive early access to beta versions",
"receive-beta-updates-explain": "Beta updates may contain unstable features and potential bugs. Do not enable this option on the computer used for live meetings.",
"refresh": "Refresh",
"regular": "Regular",
"remind-me-later": "Remind me later",
Expand Down
2 changes: 2 additions & 0 deletions src/types/electron.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export type Display = Electron.Display & {

export interface ElectronApi {
askForMediaAccess: () => void;
checkForUpdates: () => void;
closeWebsiteWindow: () => void;
convertHeic: (image: ConversionOptions) => Promise<ArrayBuffer>;
convertPdfToImages: (
Expand Down Expand Up @@ -159,6 +160,7 @@ export type ElectronIpcListenKey =
export type ElectronIpcSendKey =
| 'askForMediaAccess'
| 'authorizedClose'
| 'checkForUpdates'
| 'moveMediaWindow'
| 'navigateWebsiteWindow'
| 'openDiscussion'
Expand Down
4 changes: 3 additions & 1 deletion src/utils/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
} from 'src/types';

import { errorCatcher } from 'src/helpers/error-catcher';
import { betaUpdatesDisabled } from 'src/utils/fs';

/**
* Fetches data from the given url.
Expand Down Expand Up @@ -134,8 +135,9 @@ export const fetchAnnouncements = async (): Promise<Announcement[]> => {
export const fetchLatestVersion = async () => {
if (!process.env.repository) return;
const url = `${process.env.repository.replace('github.com', 'api.github.com/repos')}/releases`;
const includeBeta = !(await betaUpdatesDisabled())
const result = await fetchJson<Release[]>(url);
return result?.find((r) => !r.prerelease)?.tag_name.slice(1);
return result?.find((r) => includeBeta || !r.prerelease)?.tag_name.slice(1);
};

export const fetchPubMediaLinks = async (
Expand Down
Loading

0 comments on commit f71b90f

Please sign in to comment.