Skip to content

Commit

Permalink
updater integrated on ui
Browse files Browse the repository at this point in the history
  • Loading branch information
cardo-podcast committed Aug 26, 2024
1 parent 847b73a commit ddeaed8
Show file tree
Hide file tree
Showing 12 changed files with 180 additions and 50 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ jobs:
with:
tagName: __VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version.
releaseName: '__VERSION__'
releaseBody: 'See the assets to download this version and install.'
releaseBody: ${{ github.event.head_commit.message }}
releaseDraft: true
prerelease: false
args: ${{ matrix.args }}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@dnd-kit/utilities": "^3.2.2",
"@tauri-apps/api": "^1.6.0",
"@uidotdev/usehooks": "^2.4.1",
"date-fns": "^3.6.0",
"i18next": "^23.12.2",
"lodash": "^4.17.21",
"react": "^18.2.0",
Expand Down
7 changes: 7 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion resources/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,10 @@
"welcome_message": "Welcome to Cardo. On this screen you'll see your playlist and what's new on your favorite podcasts.",
"current_podcast": "This podcast",
"copy_feed_url": "Copy podcast URL",
"feed_url_copied": "Podcast URL copied to clipboard"
"feed_url_copied": "Podcast URL copied to clipboard",
"new_update_available": "A new update is available!",
"release_notes": "Release Notes",
"install": "Install",
"later": "Later",
"check_updates": "Check for updates"
}
7 changes: 6 additions & 1 deletion resources/translations/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,10 @@
"welcome_message": "Bienvenido a Cardo. En esta pantalla verás tu cola de reproducción y las novedades en tus podcasts favoritos.",
"current_podcast": "Este podcast",
"copy_feed_url": "Copiar URL del podcast",
"feed_url_copied": "URL del podcast copiada al portapapeles"
"feed_url_copied": "URL del podcast copiada al portapapeles",
"new_update_available": "¡Hay una nueva actualizacion disponible!",
"release_notes": "Notas del lanzamiento",
"install": "Instalar",
"later": "Mas tarde",
"check_updates": "Buscar actualizaciones"
}
4 changes: 2 additions & 2 deletions src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
},
"package": {
"productName": "Cardo",
"version": "1.0.0"
"version": "1.1.0"
},
"tauri": {
"updater": {
"active": true,
"endpoints": [
"https://github.com/n0vella/cardo/releases/latest/download/latest.json"
],
"dialog": true,
"dialog": false,
"pubkey":"dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDdDODExNjU4QTczOUZDMUIKUldRYi9EbW5XQmFCZkdydnVrZ1dWQ0NBR2NMckRpLzBOam5HNzBOcUk0U3VLNTc3b21FKytDeksK"
},
"allowlist": {
Expand Down
72 changes: 34 additions & 38 deletions src/DB.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,52 +93,43 @@ const updateEpisodeState = async (episodeUrl: string, podcastUrl: string, positi
// #endregion
// #region MISC

const getSyncKey = async (): Promise<string | undefined> => {

const getMiscKey = async (key: string): Promise<string | undefined> => {
const r: { value: string }[] = await db.select(
`SELECT value from misc
WHERE description = "syncKey"`,
)
WHERE description = "$1"`, [key])
if (r.length > 0) {
return r[0].value
}
}

const setSyncKey = async (key: string) => {
const setMiscValue = async (key: string, value: string) => {
await db.execute(
`INSERT into misc (description, value)
VALUES ("syncKey", $1)
VALUES ("$1", $2)
ON CONFLICT (description) DO UPDATE
SET value = $1
WHERE description = "syncKey"
SET value = $2
WHERE description = "$1"
`,
[key],
[key, value],
)
}

const getLastSync = async (): Promise<number> => {
const r: { value: number }[] = await db.select(
`SELECT value from misc
WHERE description = "lastSync"`,
)
if (r.length > 0) {
return r[0].value
} else {
return 0
}

const getSyncKey = async (): Promise<string | undefined> => {
return await getMiscKey('syncKey')
}

const setLastSync = async (timestamp: number) => {
const setSyncKey = async (key: string) => {
return await setMiscValue('syncKey', key)
}

await db.execute(
`INSERT into misc (description, value)
VALUES ("lastSync", $1)
ON CONFLICT (description) DO UPDATE
SET value = $1
WHERE description = "lastSync"
`,
[timestamp],
)
const getLastSync = async (): Promise<number> => {
return Number(await getMiscKey('lastSync')) ?? 0
}

const setLastSync = async (timestamp: number) => {
return await setMiscValue('lastSync', timestamp.toString())
}

const getLastPlayed = async (): Promise<EpisodeData | undefined> => {
Expand Down Expand Up @@ -166,16 +157,17 @@ const setLastPlaying = async (playingEpisode?: EpisodeData) => {

const data = playingEpisode ? JSON.stringify(playingEpisode): 'NONE'

await db.execute(
`INSERT into misc (description, value)
VALUES ("lastPlaying", $1)
ON CONFLICT (description) DO UPDATE
SET value = $1
WHERE description = "lastPlaying"
`,
[data],
)
return await setMiscValue('lastPlaying', data)

}


const getLastUpdate = async() => {
return Number(await getMiscKey('lastUpdate')) ?? 0
}

const setLastUpdate = async(timestamp: number) => {
return await setMiscValue('lastUpdate', timestamp.toString())
}

// #endregion
Expand Down Expand Up @@ -556,7 +548,11 @@ function initDB() {
updatingFeeds,
updateSubscriptionsFeed
},
dbLoaded
dbLoaded,
appUpdate: {
getLastUpdate,
setLastUpdate
}
}
}

Expand Down
1 change: 1 addition & 0 deletions src/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export function SettingsProvider({ children }: { children: ReactNode }) {
general: {
numberOfDaysInNews: 15,
fetchSubscriptionsAtStartup: true,
checkUpdates: true
},
colors: {
primary: 'dark',
Expand Down
104 changes: 104 additions & 0 deletions src/Updater.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import {
checkUpdate,
installUpdate,
onUpdaterEvent,
} from '@tauri-apps/api/updater'
import { relaunch } from '@tauri-apps/api/process'
import { useEffect, useRef, useState } from 'react'
import { UnlistenFn } from '@tauri-apps/api/event'
import { useDB } from './DB'
import { parse } from 'date-fns';
import { useTranslation } from 'react-i18next'
import { upArrow } from './Icons'


export default function Updater() {
const unlistenCeckUpdates = useRef<UnlistenFn>()
const [dialog, setDialog] = useState<{ version: string, releaseNotes: string }>()
const [showDialog, setShowDialog] = useState(false)
const { appUpdate } = useDB()
const { t } = useTranslation()

useEffect(() => {
checkUpdates()

return () => unlistenCeckUpdates.current && unlistenCeckUpdates.current()
}, [])


const checkUpdates = async () => {

unlistenCeckUpdates.current = await onUpdaterEvent(({ error, status }) => {
// This will log all updater events, including status updates and errors.
console.log('Updater event', error, status)
})

try {
const { shouldUpdate, manifest } = await checkUpdate()

if (!manifest || !shouldUpdate) return


setDialog({
version: manifest.version,
releaseNotes: manifest.body
})

const formatString = "yyyy-MM-dd HH:mm:ss.SS xxxxx"
const releaseDate = parse(manifest.date, formatString, new Date())

const lastUpdate = new Date(await appUpdate.getLastUpdate())

setShowDialog(releaseDate.getTime() > lastUpdate.getTime()) // annoying dialog is shown only once, after that only the title bar icon appears

await appUpdate.setLastUpdate(Date.now())

} catch (error) {
console.error(error)
}
}

return (
<>
<button onClick={() => setShowDialog(true)} title={t('new_update_available')}
className={`bg-green-600 w-5 h-5 rounded-full ${dialog? 'flex': 'hidden'}`}
>
{upArrow}
</button>

<div className={`fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 min-w-64 max-w-[70%] min-h-36 bg-primary-9 rounded-md z-40
border-2 border-primary-6 shadow-md shadow-primary-8 px-3 pb-2 flex-col justify-between ${showDialog ? 'flex' : 'hidden'}
`}>
<h1 className='text-lg border-b-2 border-primary-8 p-1'>{t('new_update_available')}</h1>
<div>
<p>{t('release_notes')}: v{dialog?.version}</p>
<p className='text-sm break-words bg-primary-8 rounded-md'>{dialog?.releaseNotes}</p>
</div>
<div className='flex gap-4 justify-center mt-1'>
<button className='bg-green-600 px-2 py-1 rounded-md uppercase'
onClick={async () => {
try {
// Install the update. This will also restart the app on Windows!
await installUpdate()

// On macOS and Linux you will need to restart the app manually.
// You could use this step to display another confirmation dialog.
await relaunch()
} catch (error) {
console.error(error)
}
}}
>
{t('install')}
</button>

<button className='bg-red-600 px-2 py-1 rounded-md uppercase'
onClick={() => { setShowDialog(false) }}
>
{t('later')}
</button>
</div>
</div >
</>
)
}
11 changes: 7 additions & 4 deletions src/components/TitleBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import { SyncButton, useSync } from "../sync/Nextcloud";
import { usePlayer } from "./AudioPlayer";
import { UnlistenFn } from "@tauri-apps/api/event";
import { useSettings } from "../Settings";
import Updater from "../Updater";


function TitleBar() {
const [windowPinned, setWindowPinned] = useState(false)
const [maximized, setMaximized] = useState(false)
const { onExit: savePlayerStatus } = usePlayer()
const { performSync } = useSync()
const [{ sync: {syncBeforeAppClose} }, _] = useSettings()
const [{ sync: {syncBeforeAppClose}, general: {checkUpdates} }, _] = useSettings()
const unlistenClose = useRef<UnlistenFn>()


Expand Down Expand Up @@ -44,17 +45,19 @@ function TitleBar() {

return (
<div className={`bg-primary-10 border-b-2 border-primary-8 flex w-full h-10 justify-between px-2 py-1 items-center relative stroke-[1.5px]`} data-tauri-drag-region={true} onDragStart={appWindow.startDragging}>
<div className='flex w-12 justify-between'>
<div className='flex gap-2 items-center'>
<button onClick={() => {
appWindow.setAlwaysOnTop(!windowPinned)
setWindowPinned(!windowPinned)
}} className='hover:text-accent-5 w-6'>
}} className='hover:text-accent-5 w-6 -mr-1'>
{windowPinned ? icons.unpin : icons.pin}
</button>
<SyncButton />

{checkUpdates && <Updater/>}
</div>

<h1 className="cursor-default" data-tauri-drag-region={true} onDragStart={appWindow.startDragging}>Cardo</h1>
<h1 className="cursor-default absolute left-1/2 -translate-x-1/2" data-tauri-drag-region={true} onDragStart={appWindow.startDragging}>Cardo</h1>

<div className='flex justify-between gap-1'>
<button onClick={() => appWindow.minimize()} className='hover:text-accent-5 w-6'>
Expand Down
3 changes: 2 additions & 1 deletion src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ export interface Settings {
},
general: {
numberOfDaysInNews: number,
fetchSubscriptionsAtStartup: boolean
fetchSubscriptionsAtStartup: boolean,
checkUpdates: boolean
},
colors: {
primary: ColorTheme | TailwindBaseColor | DefaultTheme,
Expand Down
11 changes: 9 additions & 2 deletions src/pages/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import appIcon from '../../src-tauri/icons/icon.png'
import { shell } from "@tauri-apps/api"
import { resolveResource } from '@tauri-apps/api/path';
import { readDir } from '@tauri-apps/api/fs';
import tauriConfig from '../../src-tauri/tauri.conf.json'



Expand Down Expand Up @@ -109,6 +110,12 @@ function Settings() {
onChange={(value) => updateSettings({ general: { fetchSubscriptionsAtStartup: value } })} />
</label>

<label className="w-fit flex gap-1">
{t('check_updates')}:
<Checkbox defaultChecked={general.checkUpdates}
onChange={(value) => updateSettings({ general: { checkUpdates: value } })} />
</label>

<label className="w-full flex gap-2 items-center">
{t('number_days_news')}:
<input
Expand Down Expand Up @@ -200,8 +207,8 @@ function Settings() {
src={appIcon}
/>
<div className="flex flex-col gap-2">
<h1 className="UPPERCASE">Cardo - {t('podcast_player')}</h1>
<h1 className="UPPERCASE">{t('author')}: n0vella</h1>
<h1 className="UPPERCASE">Cardo - {t('podcast_player')} (v{tauriConfig.package.version})</h1>
<h1>{t('author')}: n0vella</h1>
<div className="flex gap-1 h-fit items-center">
<p>{t('source_code')}: </p>
<img
Expand Down

0 comments on commit ddeaed8

Please sign in to comment.