Skip to content
Draft
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
77 changes: 75 additions & 2 deletions src/ui/addons/install-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import { useSettingsStore } from '@api/storage';
import { Discord } from '@api/metro/components';
import { showDialog } from '@api/dialogs';
import { SocialLinks } from '@constants';
import { showToast } from '@api/toasts';
import { capitalize } from '@utilities';
import Toasts, { showToast } from '@api/toasts';
import * as managers from '@managers';
import { View } from 'react-native';
import { Strings } from '@api/i18n';
import { Icons } from '@api/assets';
import * as Managers from "@managers";
import {createTimeoutSignal} from "@utilities";
import { compareSemanticVersions, getHighestVersion} from "@utilities/compareSemanticVersions";


interface InstallModalProps {
Expand Down Expand Up @@ -154,4 +156,75 @@ export function showInstallAlert({ type, ref }: InstallModalProps) {
});
}

export async function checkForUpdates() {
Toasts.showToast({
title: `Checking for Updates`,
duration: 2000
});
//Themes are doing weird stuff and sometimes come up multiple times
const existingAssets = []
for (const theme of window.UNBOUND_THEMES ?? []) {
const {manifest, bundle} = theme;

if (!(manifest.id in existingAssets)) {

if (manifest.hasOwnProperty("updates")) {
const origin = manifest.url.split('/');
origin.pop();
const updatesURL = new URL(manifest.updates, origin.join('/') + '/');

const updateRequest = await fetch(updatesURL, {
cache: 'no-cache',
signal: createTimeoutSignal()
}).catch((error) => {
this.logger.error('Failed to fetch bundle URL:', error.message);
this.emit('install-error', error);

});

if (!updateRequest) return false;

if (!updateRequest.ok) {
//logger doesnt wanna work :/
console.error(`Failed to fetch bundle URL (${updateRequest.status}: ${updateRequest.statusText ?? 'No status text.'})`);
continue;
}

const updates = await updateRequest.json();
const highestVer = getHighestVersion(updates);
const latestVersionObject = updates.find(v => v.version === highestVer); //Maybe use for later for Patchnotes

if (compareSemanticVersions(highestVer, manifest.version) > 0) {
showDialog({
title: manifest.name,
content: `The Theme "${manifest.name}" has an Update: \n${manifest.version}->${highestVer}\nWould you like to update?`,
buttons: [
{
text: "Update now",
onPress: () => installUpdates(manifest.url, manifest.name)
},

]
});
} else if (compareSemanticVersions(highestVer, manifest.version) == 0) {
//Check if TS is newer
}


}

}


}

}

function installUpdates(updates, name) {
Managers.Themes.install(updates).then(r => Toasts.showToast({
title: `Updated ${name}`,
duration: 2000
}));
}

export default { InstallInput, InternalInstallInput };
7 changes: 7 additions & 0 deletions src/ui/settings/developer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {checkForUpdates} from "@ui/addons/install-modal";
import { Section, useFormStyles } from '@ui/misc/forms';
import { SettingsKeys, SocialLinks } from '@constants';
import { ScrollView, View, Text } from 'react-native';
Expand Down Expand Up @@ -153,6 +154,12 @@ export default function Developer() {
})}
arrow
/>
<TableRow
label="Check for updates"
icon={<TableRowIcon source={Icons.Retry} />}
onPress={async () => await checkForUpdates()}
arrow
/>
</Section>
<View style={{ marginBottom: 50 }} />
</ScrollView>;
Expand Down
40 changes: 40 additions & 0 deletions src/utilities/compareSemanticVersions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* @description Compares 2 semantic versions.
* @cases
* @> 0 - versionA is newer than versionB
* @< 0 - versionA is older than versionB
* @= 0 - versionA and versionB are the same
* @param {T extends string} versionA
* @param {T extends string} versionB
* @return {number}
*/

function compareSemanticVersions(versionA: string, versionB: string): number {
const [majorA, minorA, patchA] = versionA.split('.').map(Number);
const [majorB, minorB, patchB] = versionB.split('.').map(Number);

if (majorA !== majorB) {
return majorA - majorB;
}

if (minorA !== minorB) {
return minorA - minorB;
}

return patchA - patchB;
}

/**
* @description Retrieves the highest version from updates.json.
* @param {Array<{ version: string }>} versionsList - List of objects containing version information.
* @return {string | null} - The highest version found, or null if the list is empty.
*/
function getHighestVersion(versionsList: { version: string }[]): string | null {
if (versionsList.length === 0) return null;

return versionsList.reduce((highest, current) =>
compareSemanticVersions(highest.version, current.version) > 0 ? highest : current
).version;
}

export { compareSemanticVersions, getHighestVersion };