v1.1.9 - Android version prep

This commit is contained in:
Yuri Karamian
2026-02-26 20:20:24 +01:00
parent a26f047d2b
commit 37a837a33a
9 changed files with 100 additions and 23 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "helixnotes",
"private": true,
"license": "AGPL-3.0-or-later",
"version": "1.1.8",
"version": "1.1.9",
"type": "module",
"scripts": {
"dev": "vite dev",
+1 -1
View File
@@ -1833,7 +1833,7 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "helixnotes"
version = "1.1.8"
version = "1.1.9"
dependencies = [
"arboard",
"chrono",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "helixnotes"
version = "1.1.8"
version = "1.1.9"
description = "Local markdown note-taking app"
authors = ["HelixNotes"]
license = "AGPL-3.0-or-later"
+4 -2
View File
@@ -1570,11 +1570,13 @@ pub fn get_install_type() -> String {
} else if std::path::Path::new("/var/lib/dpkg/info/helix-notes.list").exists() {
"deb".to_string()
} else if std::path::Path::new("/var/lib/pacman/local").exists()
&& std::process::Command::new("pacman")
.args(["-Q", "helixnotes"])
&& ["helixnotes", "helixnotes-bin", "helixnotes-appimage-bin"].iter().any(|pkg| {
std::process::Command::new("pacman")
.args(["-Q", pkg])
.output()
.map(|o| o.status.success())
.unwrap_or(false)
})
{
"aur".to_string()
} else if std::env::var("APPIMAGE").is_ok() {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
"productName": "HelixNotes",
"version": "1.1.8",
"version": "1.1.9",
"identifier": "com.helixnotes.app",
"build": {
"frontendDist": "../build",
+22 -1
View File
@@ -32,7 +32,9 @@
appConfig,
quickAccessPaths,
tags,
notes
notes,
updateAvailable as globalUpdateAvailable,
settingsTab
} from '$lib/stores/app';
const appWindow = getCurrentWindow();
@@ -446,6 +448,11 @@
{$activeNotebook?.name || 'All Notes'}
{/if}
</span>
{#if $globalUpdateAvailable && $mobileView === 'sidebar'}
<button class="mobile-update-badge" onclick={() => { $settingsTab = 'updates'; $showSettings = true; }}>
v{$globalUpdateAvailable.version}
</button>
{/if}
{/if}
<div class="mobile-header-actions">
{#if $mobileView === 'editor'}
@@ -748,6 +755,20 @@
padding: 0 4px;
}
.mobile-update-badge {
background: var(--accent);
color: white;
border: none;
border-radius: 10px;
padding: 2px 8px;
font-size: 11px;
font-weight: 600;
font-family: inherit;
cursor: pointer;
white-space: nowrap;
flex-shrink: 0;
}
.mobile-header-actions {
display: flex;
align-items: center;
+21 -2
View File
@@ -1,10 +1,10 @@
<script lang="ts">
import { showSettings, theme, appConfig, updateAvailable as globalUpdateAvailable, updateObj as globalUpdateObj, installType, settingsTab, vaultReady } from '$lib/stores/app';
import { showSettings, theme, appConfig, updateAvailable as globalUpdateAvailable, updateObj as globalUpdateObj, installType, settingsTab, vaultReady, androidApkUrl, checkForUpdateMobile } from '$lib/stores/app';
import { setTheme, setAccentColor, setFontSize, setFontFamily, setLineHeight, setGeneralSettings, importObsidian, createBackup, listBackups, restoreBackup, deleteBackup, setBackupSettings, setAiSettings, testAiConnection } from '$lib/api';
import { open as openDialog } from '@tauri-apps/plugin-dialog';
import { listen } from '@tauri-apps/api/event';
import { check as checkUpdate } from '@tauri-apps/plugin-updater';
import { getVersion } from '@tauri-apps/api/app';
import { openUrl } from '@tauri-apps/plugin-opener';
import type { ImportResult, BackupEntry } from '$lib/types';
const isMobile = /android|ios/i.test(navigator.userAgent);
@@ -56,6 +56,17 @@
updateMessage = null;
updateAvailable = null;
try {
if (isMobile) {
await checkForUpdateMobile();
const global = $globalUpdateAvailable;
if (global) {
updateAvailable = { version: global.version, body: global.body };
updateMessage = { type: 'info', text: `Version ${global.version} is available!` };
} else {
updateMessage = { type: 'success', text: 'You are on the latest version.' };
}
} else {
const { check: checkUpdate } = await import('@tauri-apps/plugin-updater');
const update = await checkUpdate();
if (update) {
updateObj = update;
@@ -66,6 +77,7 @@
} else {
updateMessage = { type: 'success', text: 'You are on the latest version.' };
}
}
} catch (e) {
updateMessage = { type: 'error', text: `Failed to check: ${e}` };
} finally {
@@ -1204,6 +1216,13 @@
<p>Update via your AUR helper:</p>
<code>yay -Syu helixnotes</code>
</div>
{:else if $installType === 'android'}
<button class="update-install-btn" onclick={() => { openUrl('https://helixnotes.com/#download').catch(() => {}); }}>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/>
</svg>
Download from Website
</button>
{:else}
<a class="update-install-btn" href="https://codeberg.org/ArkHost/HelixNotes/releases" target="_blank" rel="noopener">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+32
View File
@@ -59,6 +59,7 @@ export const updateAvailable = writable<{
} | null>(null);
export const updateObj = writable<any>(null);
export const installType = writable<string>("native");
export const androidApkUrl = writable<string | null>(null);
export async function checkForUpdate() {
try {
@@ -73,6 +74,37 @@ export async function checkForUpdate() {
}
}
function isNewerVersion(remote: string, local: string): boolean {
const r = remote.split(".").map(Number);
const l = local.split(".").map(Number);
for (let i = 0; i < Math.max(r.length, l.length); i++) {
const rv = r[i] || 0;
const lv = l[i] || 0;
if (rv > lv) return true;
if (rv < lv) return false;
}
return false;
}
export async function checkForUpdateMobile() {
try {
const { getVersion } = await import("@tauri-apps/api/app");
const currentVersion = await getVersion();
const res = await fetch("https://helixnotes.com/latest.json");
if (!res.ok) return;
const data = await res.json();
if (data.version && isNewerVersion(data.version, currentVersion)) {
updateAvailable.set({ version: data.version, body: data.notes });
const android = data.platforms?.["android-universal"];
if (android?.url) {
androidApkUrl.set(android.url);
}
}
} catch {
// Silent fail
}
}
// Derived
export const sortedNotes = derived(
[notes, sortMode, viewMode],
+6 -3
View File
@@ -1,7 +1,7 @@
<script lang="ts">
import { onMount } from 'svelte';
import '../app.css';
import { theme, appConfig, activeNotePath, installType, checkForUpdate } from '$lib/stores/app';
import { theme, appConfig, activeNotePath, installType, checkForUpdate, checkForUpdateMobile } from '$lib/stores/app';
import { openUrl } from '@tauri-apps/plugin-opener';
import { openFile, getInstallType } from '$lib/api';
import { get } from 'svelte/store';
@@ -33,9 +33,12 @@
return resolved.join('/');
}
// Detect install type and check for updates on startup (skip on mobile — updates via app store)
// Detect install type and check for updates on startup
onMount(() => {
if (!isMobile) {
if (isMobile) {
installType.set('android');
checkForUpdateMobile();
} else {
getInstallType().then(t => installType.set(t)).catch(() => {});
checkForUpdate();
}