Implement autoupdater functionality and enhance icon management
- Added a new UpdateNotification component to inform users about available updates and facilitate installation. - Integrated useAutoUpdater hook for managing update checks and installations. - Updated package.json with new build and generate scripts for release preparation and key generation. - Enhanced tauri configuration to support autoupdater with signing keys and endpoints. - Created scripts for preparing signed releases and updating icons, ensuring a streamlined workflow for asset management. - Added detailed documentation for autoupdater setup and icon update workflow.
@@ -99,6 +99,8 @@ jobs:
|
||||
- uses: tauri-apps/tauri-action@v0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
||||
with:
|
||||
projectPath: tauri
|
||||
tagName: v__VERSION__
|
||||
@@ -111,6 +113,9 @@ jobs:
|
||||
- **macOS**: Download the `.dmg` file
|
||||
- **Windows**: Download the `.msi` installer
|
||||
- **Linux**: Download the `.AppImage` or `.deb` package
|
||||
|
||||
The app includes automatic updates - future updates will be installed automatically.
|
||||
releaseDraft: true
|
||||
prerelease: false
|
||||
args: ${{ matrix.args }}
|
||||
includeUpdaterJson: true
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Download, Play, Trash2 } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { CircleButton } from '@/components/ui/circle-button';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
@@ -29,6 +30,8 @@ export function HistoryTable() {
|
||||
const setAudio = usePlayerStore((state) => state.setAudio);
|
||||
const currentAudioId = usePlayerStore((state) => state.audioId);
|
||||
const isPlaying = usePlayerStore((state) => state.isPlaying);
|
||||
const audioUrl = usePlayerStore((state) => state.audioUrl);
|
||||
const isPlayerVisible = !!audioUrl;
|
||||
|
||||
const handlePlay = (audioId: string, text: string) => {
|
||||
const audioUrl = apiClient.getAudioUrl(audioId);
|
||||
@@ -67,16 +70,19 @@ export function HistoryTable() {
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex-1 min-h-0 overflow-y-auto border rounded-md max-h-[calc(100vh-280px)]">
|
||||
<Table>
|
||||
<div className={cn(
|
||||
"flex-1 min-h-0 overflow-y-auto border rounded-md overflow-x-hidden",
|
||||
isPlayerVisible && "max-h-[calc(100vh-280px)]"
|
||||
)}>
|
||||
<Table className="w-full table-fixed">
|
||||
<TableHeader className="sticky top-0 bg-background z-10">
|
||||
<TableRow>
|
||||
<TableHead>Text</TableHead>
|
||||
<TableHead>Profile</TableHead>
|
||||
<TableHead>Language</TableHead>
|
||||
<TableHead>Duration</TableHead>
|
||||
<TableHead>Created</TableHead>
|
||||
<TableHead className="text-right">Actions</TableHead>
|
||||
<TableHead className="w-[40%]">Text</TableHead>
|
||||
<TableHead className="w-[15%]">Profile</TableHead>
|
||||
<TableHead className="w-[10%]">Language</TableHead>
|
||||
<TableHead className="w-[10%]">Duration</TableHead>
|
||||
<TableHead className="w-[15%]">Created</TableHead>
|
||||
<TableHead className="w-[10%] text-right">Actions</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
@@ -85,45 +91,37 @@ export function HistoryTable() {
|
||||
return (
|
||||
<TableRow
|
||||
key={gen.id}
|
||||
className={cn(isCurrentlyPlaying && 'bg-muted/50')}
|
||||
className={cn(
|
||||
isCurrentlyPlaying && 'bg-muted/50',
|
||||
'cursor-pointer'
|
||||
)}
|
||||
onClick={() => handlePlay(gen.id, gen.text)}
|
||||
>
|
||||
<TableCell className="max-w-[200px] truncate">{gen.text}</TableCell>
|
||||
<TableCell>{gen.profile_name}</TableCell>
|
||||
<TableCell className="truncate">{gen.text}</TableCell>
|
||||
<TableCell className="truncate">{gen.profile_name}</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant="outline">{gen.language}</Badge>
|
||||
<Badge variant="outline" className="text-xs">{gen.language}</Badge>
|
||||
</TableCell>
|
||||
<TableCell>{formatDuration(gen.duration)}</TableCell>
|
||||
<TableCell className="text-sm">{formatDate(gen.created_at)}</TableCell>
|
||||
<TableCell className="text-sm">{formatDuration(gen.duration)}</TableCell>
|
||||
<TableCell className="text-xs text-muted-foreground/60">{formatDate(gen.created_at)}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<div className="flex justify-end gap-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
<div className="flex justify-end gap-0.5" onClick={(e) => e.stopPropagation()}>
|
||||
<CircleButton
|
||||
icon={Play}
|
||||
onClick={() => handlePlay(gen.id, gen.text)}
|
||||
aria-label="Play audio"
|
||||
className={
|
||||
currentAudioId === gen.id && isPlaying ? 'text-primary' : ''
|
||||
}
|
||||
>
|
||||
<Play className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
/>
|
||||
<CircleButton
|
||||
icon={Download}
|
||||
onClick={() => handleDownload(gen.id, gen.text)}
|
||||
aria-label="Download audio"
|
||||
>
|
||||
<Download className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
/>
|
||||
<CircleButton
|
||||
icon={Trash2}
|
||||
onClick={() => deleteGeneration.mutate(gen.id)}
|
||||
disabled={deleteGeneration.isPending}
|
||||
aria-label="Delete generation"
|
||||
>
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
</Button>
|
||||
/>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import { useAutoUpdater } from '../hooks/useAutoUpdater';
|
||||
import { Button } from './ui/button';
|
||||
import { Card } from './ui/card';
|
||||
import { Progress } from './ui/progress';
|
||||
|
||||
export function UpdateNotification() {
|
||||
const { status, checkForUpdates, downloadAndInstall } = useAutoUpdater(true);
|
||||
|
||||
if (status.error) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!status.available && !status.checking) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (status.checking) {
|
||||
return (
|
||||
<Card className="p-4 mb-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="animate-spin h-4 w-4 border-2 border-primary border-t-transparent rounded-full" />
|
||||
<span className="text-sm">Checking for updates...</span>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
if (status.available) {
|
||||
return (
|
||||
<Card className="p-4 mb-4 border-primary">
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
<h3 className="font-semibold">Update Available</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Version {status.version} is ready to install
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{status.downloading && (
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm">Downloading update...</p>
|
||||
<Progress />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{status.installing && (
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm">Installing update...</p>
|
||||
<p className="text-xs text-muted-foreground">App will restart automatically</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!status.downloading && !status.installing && (
|
||||
<div className="flex gap-2">
|
||||
<Button onClick={downloadAndInstall} size="sm">
|
||||
Install Now
|
||||
</Button>
|
||||
<Button onClick={() => window.location.reload()} variant="outline" size="sm">
|
||||
Later
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { check, type Update } from '@tauri-apps/plugin-updater';
|
||||
import { relaunch } from '@tauri-apps/plugin-process';
|
||||
|
||||
export interface UpdateStatus {
|
||||
checking: boolean;
|
||||
available: boolean;
|
||||
version?: string;
|
||||
downloading: boolean;
|
||||
installing: boolean;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export function useAutoUpdater(checkOnMount = false) {
|
||||
const [status, setStatus] = useState<UpdateStatus>({
|
||||
checking: false,
|
||||
available: false,
|
||||
downloading: false,
|
||||
installing: false,
|
||||
});
|
||||
|
||||
const [update, setUpdate] = useState<Update | null>(null);
|
||||
|
||||
const checkForUpdates = async () => {
|
||||
try {
|
||||
setStatus((prev) => ({ ...prev, checking: true, error: undefined }));
|
||||
|
||||
const foundUpdate = await check();
|
||||
|
||||
if (foundUpdate?.available) {
|
||||
setUpdate(foundUpdate);
|
||||
setStatus({
|
||||
checking: false,
|
||||
available: true,
|
||||
version: foundUpdate.version,
|
||||
downloading: false,
|
||||
installing: false,
|
||||
});
|
||||
} else {
|
||||
setStatus({
|
||||
checking: false,
|
||||
available: false,
|
||||
downloading: false,
|
||||
installing: false,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
setStatus({
|
||||
checking: false,
|
||||
available: false,
|
||||
downloading: false,
|
||||
installing: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to check for updates',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const downloadAndInstall = async () => {
|
||||
if (!update) return;
|
||||
|
||||
try {
|
||||
setStatus((prev) => ({ ...prev, downloading: true, error: undefined }));
|
||||
|
||||
await update.downloadAndInstall((event) => {
|
||||
switch (event.event) {
|
||||
case 'Started':
|
||||
setStatus((prev) => ({ ...prev, downloading: true }));
|
||||
break;
|
||||
case 'Progress':
|
||||
console.log(`Downloaded ${event.data.chunkLength} bytes`);
|
||||
break;
|
||||
case 'Finished':
|
||||
setStatus((prev) => ({
|
||||
...prev,
|
||||
downloading: false,
|
||||
installing: true,
|
||||
}));
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
await relaunch();
|
||||
} catch (error) {
|
||||
setStatus((prev) => ({
|
||||
...prev,
|
||||
downloading: false,
|
||||
installing: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to install update',
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (checkOnMount) {
|
||||
checkForUpdates();
|
||||
}
|
||||
}, [checkOnMount]);
|
||||
|
||||
return {
|
||||
status,
|
||||
checkForUpdates,
|
||||
downloadAndInstall,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
# Tauri v2 Autoupdater Setup
|
||||
|
||||
The autoupdater has been configured for this project. Follow these steps to complete the setup.
|
||||
|
||||
## 1. Generate Signing Keys
|
||||
|
||||
Run this command to generate your signing keypair:
|
||||
|
||||
```bash
|
||||
cd tauri && bun tauri signer generate -w ~/.tauri/voicebox.key
|
||||
```
|
||||
|
||||
This creates:
|
||||
- **Private key**: `~/.tauri/voicebox.key` (keep this secret!)
|
||||
- **Public key**: `~/.tauri/voicebox.key.pub`
|
||||
|
||||
## 2. Update Configuration
|
||||
|
||||
Copy the content from `~/.tauri/voicebox.key.pub` and replace the placeholder in `tauri/src-tauri/tauri.conf.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"updater": {
|
||||
"pubkey": "PASTE_PUBLIC_KEY_CONTENT_HERE",
|
||||
"endpoints": [
|
||||
"https://github.com/YOUR_USERNAME/voicebox/releases/latest/download/latest.json"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Update the endpoint URL with your actual GitHub username/organization.
|
||||
|
||||
## 3. Building with Signatures
|
||||
|
||||
When building releases, set these environment variables:
|
||||
|
||||
**macOS/Linux:**
|
||||
```bash
|
||||
export TAURI_SIGNING_PRIVATE_KEY="$(cat ~/.tauri/voicebox.key)"
|
||||
export TAURI_SIGNING_PRIVATE_KEY_PASSWORD=""
|
||||
bun run build
|
||||
```
|
||||
|
||||
**Windows PowerShell:**
|
||||
```powershell
|
||||
$env:TAURI_SIGNING_PRIVATE_KEY = Get-Content ~/.tauri/voicebox.key -Raw
|
||||
$env:TAURI_SIGNING_PRIVATE_KEY_PASSWORD = ""
|
||||
bun run build
|
||||
```
|
||||
|
||||
## 4. GitHub Release Setup
|
||||
|
||||
When you create a GitHub release, the build process will generate:
|
||||
- Installers for each platform
|
||||
- `.sig` signature files
|
||||
- `latest.json` update manifest
|
||||
|
||||
### Manual Release Process
|
||||
|
||||
1. Build the app with signing keys set
|
||||
2. Create a new GitHub release
|
||||
3. Upload all files from `tauri/src-tauri/target/release/bundle/`
|
||||
4. Create `latest.json` in your release assets:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"notes": "Bug fixes and improvements",
|
||||
"pub_date": "2026-01-25T12:00:00Z",
|
||||
"platforms": {
|
||||
"darwin-aarch64": {
|
||||
"signature": "CONTENT_FROM_.app.tar.gz.sig",
|
||||
"url": "https://github.com/YOUR_USERNAME/voicebox/releases/download/v0.2.0/voicebox_0.2.0_aarch64.dmg"
|
||||
},
|
||||
"darwin-x86_64": {
|
||||
"signature": "CONTENT_FROM_.app.tar.gz.sig",
|
||||
"url": "https://github.com/YOUR_USERNAME/voicebox/releases/download/v0.2.0/voicebox_0.2.0_x64.dmg"
|
||||
},
|
||||
"linux-x86_64": {
|
||||
"signature": "CONTENT_FROM_.AppImage.sig",
|
||||
"url": "https://github.com/YOUR_USERNAME/voicebox/releases/download/v0.2.0/voicebox_0.2.0_amd64.AppImage"
|
||||
},
|
||||
"windows-x86_64": {
|
||||
"signature": "CONTENT_FROM_.msi.sig",
|
||||
"url": "https://github.com/YOUR_USERNAME/voicebox/releases/download/v0.2.0/voicebox_0.2.0_x64_en-US.msi"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Automated GitHub Actions (Recommended)
|
||||
|
||||
Create `.github/workflows/release.yml`:
|
||||
|
||||
```yaml
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [macos-latest, ubuntu-22.04, windows-latest]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Install dependencies (Ubuntu)
|
||||
if: matrix.platform == 'ubuntu-22.04'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
||||
run: bun run build
|
||||
|
||||
- name: Upload Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: tauri/src-tauri/target/release/bundle/**/*
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
```
|
||||
|
||||
Add your private key to GitHub secrets:
|
||||
- Go to Settings → Secrets and variables → Actions
|
||||
- Add `TAURI_SIGNING_PRIVATE_KEY` with the content of `~/.tauri/voicebox.key`
|
||||
- Add `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` (empty string if no password)
|
||||
|
||||
## 5. Implementing Update Check in Frontend
|
||||
|
||||
Add the updater package:
|
||||
|
||||
```bash
|
||||
bun add @tauri-apps/plugin-updater
|
||||
```
|
||||
|
||||
Example implementation:
|
||||
|
||||
```typescript
|
||||
import { check } from '@tauri-apps/plugin-updater';
|
||||
import { relaunch } from '@tauri-apps/plugin-process';
|
||||
|
||||
async function checkForUpdates() {
|
||||
try {
|
||||
const update = await check();
|
||||
|
||||
if (update?.available) {
|
||||
console.log(`Update available: ${update.version}`);
|
||||
|
||||
// Show UI to user
|
||||
const shouldUpdate = confirm(
|
||||
`Version ${update.version} is available. Install now?`
|
||||
);
|
||||
|
||||
if (shouldUpdate) {
|
||||
await update.downloadAndInstall();
|
||||
await relaunch();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Update check failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Check on app startup
|
||||
checkForUpdates();
|
||||
|
||||
// Or add a manual check button
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
|
||||
- Never commit your private key to version control
|
||||
- Store private keys securely (use GitHub secrets for CI/CD)
|
||||
- The public key in `tauri.conf.json` is safe to commit
|
||||
- Updates are cryptographically verified before installation
|
||||
- HTTP endpoints are blocked by default (HTTPS only)
|
||||
|
||||
## Testing Updates
|
||||
|
||||
1. Build version 0.1.0 and install it
|
||||
2. Update version in `tauri.conf.json` to 0.2.0
|
||||
3. Build version 0.2.0 with signatures
|
||||
4. Create a local server or GitHub release with `latest.json`
|
||||
5. Run version 0.1.0 and trigger update check
|
||||
6. Verify update downloads and installs correctly
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**"Invalid signature" error:**
|
||||
- Verify public key matches the private key used to sign
|
||||
- Ensure signature files (.sig) are uploaded correctly
|
||||
|
||||
**"No update available" when one exists:**
|
||||
- Check endpoint URL is correct
|
||||
- Verify `latest.json` format matches specification
|
||||
- Ensure version in latest.json is higher than current version
|
||||
|
||||
**Build fails with signing:**
|
||||
- Confirm environment variables are set correctly
|
||||
- Check private key file exists and is readable
|
||||
- Verify private key format (should start with `dW50cnVzdGVkIGNvbW1lbnQ6`)
|
||||
@@ -0,0 +1,150 @@
|
||||
# Icon Update Workflow for voicebox
|
||||
|
||||
## Prerequisites
|
||||
- Xcode Command Line Tools installed (`xcode-select --install`)
|
||||
- Your icon designed in Icon Composer and saved as `voicebox.icon` in the project root
|
||||
|
||||
## Directory Structure
|
||||
```
|
||||
voicebox/
|
||||
├── voicebox.icon/ # macOS 26 Liquid Glass icon bundle
|
||||
│ ├── icon.json
|
||||
│ └── Assets/
|
||||
│ └── Voicebox.png # Your source image
|
||||
├── tauri/
|
||||
│ ├── assets/
|
||||
│ │ └── voicebox_exports/ # Your 1024x1024 exports
|
||||
│ └── src-tauri/
|
||||
│ ├── gen/ # Auto-generated at build time
|
||||
│ │ ├── Assets.car # Liquid Glass assets
|
||||
│ │ ├── voicebox.icns # Generated fallback icon
|
||||
│ │ └── partial.plist
|
||||
│ └── icons/ # Tauri fallback icons (all platforms)
|
||||
│ ├── icon.icns
|
||||
│ ├── icon.ico
|
||||
│ ├── 32x32.png
|
||||
│ ├── 128x128.png
|
||||
│ └── ...
|
||||
```
|
||||
|
||||
## Step 1: Update the Liquid Glass Icon
|
||||
|
||||
Edit `voicebox.icon/` in Icon Composer (or manually update `icon.json` and `Assets/`).
|
||||
|
||||
The build script (`build.rs`) automatically compiles this during `cargo build`.
|
||||
|
||||
## Step 2: Regenerate Fallback Icons
|
||||
|
||||
After updating the `.icon` bundle, regenerate the fallback icons:
|
||||
|
||||
```bash
|
||||
cd tauri/src-tauri
|
||||
|
||||
# Trigger rebuild to generate new icns
|
||||
cargo build
|
||||
|
||||
# Copy the generated icns to icons folder
|
||||
cp gen/voicebox.icns icons/icon.icns
|
||||
|
||||
# Generate PNGs from the icns
|
||||
sips -s format png -z 32 32 gen/voicebox.icns --out icons/32x32.png
|
||||
sips -s format png -z 64 64 gen/voicebox.icns --out icons/64x64.png
|
||||
sips -s format png -z 128 128 gen/voicebox.icns --out icons/128x128.png
|
||||
sips -s format png -z 256 256 gen/voicebox.icns --out icons/[email protected]
|
||||
sips -s format png -z 512 512 gen/voicebox.icns --out icons/icon.png
|
||||
|
||||
# Windows Square logos
|
||||
for size in 30 44 71 89 107 142 150 284 310; do
|
||||
sips -s format png -z $size $size gen/voicebox.icns --out "icons/Square${size}x${size}Logo.png"
|
||||
done
|
||||
```
|
||||
|
||||
## Step 3: Rebuild the App
|
||||
|
||||
```bash
|
||||
cd tauri && bun run tauri build
|
||||
```
|
||||
|
||||
## Step 4: Clear Icon Cache (if icons don't update)
|
||||
|
||||
```bash
|
||||
sudo rm -rf /Library/Caches/com.apple.iconservices.store
|
||||
sudo killall Finder
|
||||
sudo killall Dock
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## How It Works
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `voicebox.icon/` | Source for macOS 26 Liquid Glass icon |
|
||||
| `build.rs` | Compiles `.icon` → `Assets.car` + `voicebox.icns` at build time |
|
||||
| `gen/Assets.car` | Liquid Glass assets (macOS 26+) |
|
||||
| `gen/voicebox.icns` | Auto-generated fallback icon |
|
||||
| `icons/icon.icns` | Tauri's fallback for older macOS |
|
||||
| `icons/*.png` | Tauri's fallback for other platforms |
|
||||
| `Info.plist` | Points to `voicebox` as icon name |
|
||||
| `tauri.conf.json` | Bundles `gen/*` to Resources root |
|
||||
|
||||
## Key Config Files
|
||||
|
||||
### `build.rs` — Compiles the icon
|
||||
|
||||
```rust
|
||||
xcrun actool --app-icon voicebox ... voicebox.icon
|
||||
```
|
||||
|
||||
### `tauri.conf.json` — Bundles generated assets to Resources root
|
||||
|
||||
```json
|
||||
"resources": {
|
||||
"gen/Assets.car": "./",
|
||||
"gen/voicebox.icns": "./",
|
||||
"gen/partial.plist": "./"
|
||||
}
|
||||
```
|
||||
|
||||
### `Info.plist` — Tells macOS which icon to use
|
||||
|
||||
```xml
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>voicebox</string>
|
||||
<key>CFBundleIconName</key>
|
||||
<string>voicebox</string>
|
||||
```
|
||||
|
||||
## Quick Reference Script
|
||||
|
||||
Save this as `scripts/update-icons.sh`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")/../tauri/src-tauri"
|
||||
|
||||
echo "Building to generate new icons..."
|
||||
cargo build
|
||||
|
||||
echo "Copying icns to icons folder..."
|
||||
cp gen/voicebox.icns icons/icon.icns
|
||||
|
||||
echo "Generating PNG icons..."
|
||||
sips -s format png -z 32 32 gen/voicebox.icns --out icons/32x32.png
|
||||
sips -s format png -z 64 64 gen/voicebox.icns --out icons/64x64.png
|
||||
sips -s format png -z 128 128 gen/voicebox.icns --out icons/128x128.png
|
||||
sips -s format png -z 256 256 gen/voicebox.icns --out icons/[email protected]
|
||||
sips -s format png -z 512 512 gen/voicebox.icns --out icons/icon.png
|
||||
|
||||
echo "Generating Windows Square logos..."
|
||||
for size in 30 44 71 89 107 142 150 284 310; do
|
||||
sips -s format png -z $size $size gen/voicebox.icns --out "icons/Square${size}x${size}Logo.png"
|
||||
done
|
||||
|
||||
echo "Done! Icons updated."
|
||||
echo "Run 'bun run tauri build' to rebuild the app."
|
||||
```
|
||||
|
||||
Make it executable: `chmod +x scripts/update-icons.sh`
|
||||
@@ -16,8 +16,11 @@
|
||||
"build": "cd tauri && bun run tauri build",
|
||||
"build:web": "cd web && bun run build",
|
||||
"build:landing": "cd landing && bun run build",
|
||||
"build:release": "./scripts/prepare-release.sh",
|
||||
"generate:api": "./scripts/generate-api.sh",
|
||||
"generate:keys": "cd tauri && bun tauri signer generate -w ~/.tauri/voicebox.key",
|
||||
"build:server": "./scripts/build-server.sh",
|
||||
"update:icons": "./scripts/update-icons.sh",
|
||||
"lint": "biome lint .",
|
||||
"lint:fix": "biome lint --write .",
|
||||
"format": "biome format --write .",
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script to prepare a signed release build
|
||||
# Usage: ./scripts/prepare-release.sh
|
||||
|
||||
set -e
|
||||
|
||||
echo "🔑 Checking for signing keys..."
|
||||
|
||||
if [ ! -f ~/.tauri/voicebox.key ]; then
|
||||
echo "❌ Private key not found at ~/.tauri/voicebox.key"
|
||||
echo "Run: cd tauri && bun tauri signer generate -w ~/.tauri/voicebox.key"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f ~/.tauri/voicebox.key.pub ]; then
|
||||
echo "❌ Public key not found at ~/.tauri/voicebox.key.pub"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Signing keys found"
|
||||
echo ""
|
||||
|
||||
# Check if public key is in tauri.conf.json
|
||||
if grep -q "REPLACE_WITH_YOUR_PUBLIC_KEY" tauri/src-tauri/tauri.conf.json; then
|
||||
echo "⚠️ Public key not configured in tauri.conf.json"
|
||||
echo ""
|
||||
echo "Add this to tauri/src-tauri/tauri.conf.json:"
|
||||
echo ""
|
||||
cat ~/.tauri/voicebox.key.pub
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🔧 Setting up environment..."
|
||||
|
||||
export TAURI_SIGNING_PRIVATE_KEY="$(cat ~/.tauri/voicebox.key)"
|
||||
export TAURI_SIGNING_PRIVATE_KEY_PASSWORD=""
|
||||
|
||||
echo "✅ Environment configured"
|
||||
echo ""
|
||||
|
||||
echo "📦 Building release..."
|
||||
echo ""
|
||||
|
||||
bun run build
|
||||
|
||||
echo ""
|
||||
echo "✅ Release build complete!"
|
||||
echo ""
|
||||
echo "📂 Bundles created in: tauri/src-tauri/target/release/bundle/"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "1. Create a GitHub release"
|
||||
echo "2. Upload all files from the bundle directory"
|
||||
echo "3. Create latest.json with update metadata"
|
||||
echo ""
|
||||
@@ -0,0 +1,315 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Complete Icon Update Script
|
||||
# Updates both Liquid Glass icon bundle AND all platform fallback icons from exports
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
EXPORTS_DIR="tauri/assets/voicebox_exports"
|
||||
ICON_BUNDLE="tauri/assets/voicebox.icon"
|
||||
ASSETS_DIR="$ICON_BUNDLE/Assets"
|
||||
ICONS_DIR="tauri/src-tauri/icons"
|
||||
SOURCE_ICON="$EXPORTS_DIR/[email protected]"
|
||||
|
||||
echo "🎨 Updating all Voicebox icons from exports..."
|
||||
echo ""
|
||||
|
||||
# Check if source exists
|
||||
if [ ! -f "$SOURCE_ICON" ]; then
|
||||
echo "Error: Source icon not found at $SOURCE_ICON"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ============================================
|
||||
# PART 1: Update voicebox.icon Bundle
|
||||
# ============================================
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "📦 Part 1: Updating Liquid Glass Icon Bundle"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
mkdir -p "$ASSETS_DIR"
|
||||
|
||||
echo "Copying appearance variants..."
|
||||
cp "$EXPORTS_DIR/[email protected]" "$ASSETS_DIR/Voicebox.png"
|
||||
echo " ✓ Default"
|
||||
|
||||
[ -f "$EXPORTS_DIR/[email protected]" ] && {
|
||||
cp "$EXPORTS_DIR/[email protected]" "$ASSETS_DIR/Voicebox-Dark.png"
|
||||
echo " ✓ Dark"
|
||||
}
|
||||
|
||||
[ -f "$EXPORTS_DIR/[email protected]" ] && {
|
||||
cp "$EXPORTS_DIR/[email protected]" "$ASSETS_DIR/Voicebox-ClearLight.png"
|
||||
echo " ✓ Clear Light"
|
||||
}
|
||||
|
||||
[ -f "$EXPORTS_DIR/[email protected]" ] && {
|
||||
cp "$EXPORTS_DIR/[email protected]" "$ASSETS_DIR/Voicebox-ClearDark.png"
|
||||
echo " ✓ Clear Dark"
|
||||
}
|
||||
|
||||
[ -f "$EXPORTS_DIR/[email protected]" ] && {
|
||||
cp "$EXPORTS_DIR/[email protected]" "$ASSETS_DIR/Voicebox-TintedLight.png"
|
||||
echo " ✓ Tinted Light"
|
||||
}
|
||||
|
||||
[ -f "$EXPORTS_DIR/[email protected]" ] && {
|
||||
cp "$EXPORTS_DIR/[email protected]" "$ASSETS_DIR/Voicebox-TintedDark.png"
|
||||
echo " ✓ Tinted Dark"
|
||||
}
|
||||
|
||||
echo ""
|
||||
echo "Updating icon.json..."
|
||||
|
||||
cat > "$ICON_BUNDLE/icon.json" << 'EOF'
|
||||
{
|
||||
"fill" : "automatic",
|
||||
"groups" : [
|
||||
{
|
||||
"layers" : [
|
||||
{
|
||||
"blend-mode" : "normal",
|
||||
"glass" : true,
|
||||
"image-name" : "Voicebox.png",
|
||||
"name" : "Voicebox",
|
||||
"position" : {
|
||||
"scale" : 0.37,
|
||||
"translation-in-points" : [
|
||||
-0.12338405356129378,
|
||||
297.27705195772353
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"shadow" : {
|
||||
"kind" : "neutral",
|
||||
"opacity" : 0.5
|
||||
},
|
||||
"translucency" : {
|
||||
"enabled" : true,
|
||||
"value" : 0.5
|
||||
}
|
||||
}
|
||||
],
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "light",
|
||||
"groups" : [
|
||||
{
|
||||
"layers" : [
|
||||
{
|
||||
"blend-mode" : "normal",
|
||||
"glass" : true,
|
||||
"image-name" : "Voicebox.png",
|
||||
"name" : "Voicebox"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"appearance" : "dark",
|
||||
"groups" : [
|
||||
{
|
||||
"layers" : [
|
||||
{
|
||||
"blend-mode" : "normal",
|
||||
"glass" : true,
|
||||
"image-name" : "Voicebox-Dark.png",
|
||||
"name" : "Voicebox Dark"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"appearance" : "light",
|
||||
"contrast" : "clear",
|
||||
"groups" : [
|
||||
{
|
||||
"layers" : [
|
||||
{
|
||||
"blend-mode" : "normal",
|
||||
"glass" : true,
|
||||
"image-name" : "Voicebox-ClearLight.png",
|
||||
"name" : "Voicebox Clear Light"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"appearance" : "dark",
|
||||
"contrast" : "clear",
|
||||
"groups" : [
|
||||
{
|
||||
"layers" : [
|
||||
{
|
||||
"blend-mode" : "normal",
|
||||
"glass" : true,
|
||||
"image-name" : "Voicebox-ClearDark.png",
|
||||
"name" : "Voicebox Clear Dark"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"appearance" : "light",
|
||||
"contrast" : "tinted",
|
||||
"groups" : [
|
||||
{
|
||||
"layers" : [
|
||||
{
|
||||
"blend-mode" : "normal",
|
||||
"glass" : true,
|
||||
"image-name" : "Voicebox-TintedLight.png",
|
||||
"name" : "Voicebox Tinted Light"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"appearance" : "dark",
|
||||
"contrast" : "tinted",
|
||||
"groups" : [
|
||||
{
|
||||
"layers" : [
|
||||
{
|
||||
"blend-mode" : "normal",
|
||||
"glass" : true,
|
||||
"image-name" : "Voicebox-TintedDark.png",
|
||||
"name" : "Voicebox Tinted Dark"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"supported-platforms" : {
|
||||
"circles" : [
|
||||
"watchOS"
|
||||
],
|
||||
"squares" : "shared"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
echo " ✓ icon.json updated"
|
||||
echo ""
|
||||
|
||||
# ============================================
|
||||
# PART 2: Generate Platform Fallback Icons
|
||||
# ============================================
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "🖼️ Part 2: Generating Platform Fallback Icons"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
mkdir -p "$ICONS_DIR"
|
||||
|
||||
# macOS & Desktop Icons
|
||||
echo "Generating macOS/Desktop icons..."
|
||||
sips -s format png -z 32 32 "$SOURCE_ICON" --out "$ICONS_DIR/32x32.png" 2>/dev/null
|
||||
sips -s format png -z 64 64 "$SOURCE_ICON" --out "$ICONS_DIR/64x64.png" 2>/dev/null
|
||||
sips -s format png -z 128 128 "$SOURCE_ICON" --out "$ICONS_DIR/128x128.png" 2>/dev/null
|
||||
sips -s format png -z 256 256 "$SOURCE_ICON" --out "$ICONS_DIR/[email protected]" 2>/dev/null
|
||||
sips -s format png -z 512 512 "$SOURCE_ICON" --out "$ICONS_DIR/icon.png" 2>/dev/null
|
||||
|
||||
# Generate ICNS
|
||||
echo "Generating icon.icns..."
|
||||
mkdir -p /tmp/voicebox-iconset.iconset
|
||||
sips -s format png -z 16 16 "$SOURCE_ICON" --out /tmp/voicebox-iconset.iconset/icon_16x16.png 2>/dev/null
|
||||
sips -s format png -z 32 32 "$SOURCE_ICON" --out /tmp/voicebox-iconset.iconset/[email protected] 2>/dev/null
|
||||
sips -s format png -z 32 32 "$SOURCE_ICON" --out /tmp/voicebox-iconset.iconset/icon_32x32.png 2>/dev/null
|
||||
sips -s format png -z 64 64 "$SOURCE_ICON" --out /tmp/voicebox-iconset.iconset/[email protected] 2>/dev/null
|
||||
sips -s format png -z 128 128 "$SOURCE_ICON" --out /tmp/voicebox-iconset.iconset/icon_128x128.png 2>/dev/null
|
||||
sips -s format png -z 256 256 "$SOURCE_ICON" --out /tmp/voicebox-iconset.iconset/[email protected] 2>/dev/null
|
||||
sips -s format png -z 256 256 "$SOURCE_ICON" --out /tmp/voicebox-iconset.iconset/icon_256x256.png 2>/dev/null
|
||||
sips -s format png -z 512 512 "$SOURCE_ICON" --out /tmp/voicebox-iconset.iconset/[email protected] 2>/dev/null
|
||||
sips -s format png -z 512 512 "$SOURCE_ICON" --out /tmp/voicebox-iconset.iconset/icon_512x512.png 2>/dev/null
|
||||
sips -s format png -z 1024 1024 "$SOURCE_ICON" --out /tmp/voicebox-iconset.iconset/[email protected] 2>/dev/null
|
||||
iconutil -c icns /tmp/voicebox-iconset.iconset -o "$ICONS_DIR/icon.icns"
|
||||
rm -rf /tmp/voicebox-iconset.iconset
|
||||
|
||||
# Windows Square Logos
|
||||
echo "Generating Windows icons..."
|
||||
for size in 30 44 71 89 107 142 150 284 310; do
|
||||
sips -s format png -z $size $size "$SOURCE_ICON" --out "$ICONS_DIR/Square${size}x${size}Logo.png" 2>/dev/null
|
||||
done
|
||||
sips -s format png -z 50 50 "$SOURCE_ICON" --out "$ICONS_DIR/StoreLogo.png" 2>/dev/null
|
||||
|
||||
# iOS Icons
|
||||
echo "Generating iOS icons..."
|
||||
mkdir -p "$ICONS_DIR/ios"
|
||||
|
||||
declare -A ios_sizes=(
|
||||
["[email protected]"]="20"
|
||||
["[email protected]"]="40"
|
||||
["[email protected]"]="40"
|
||||
["[email protected]"]="60"
|
||||
["[email protected]"]="29"
|
||||
["[email protected]"]="58"
|
||||
["[email protected]"]="58"
|
||||
["[email protected]"]="87"
|
||||
["[email protected]"]="40"
|
||||
["[email protected]"]="80"
|
||||
["[email protected]"]="80"
|
||||
["[email protected]"]="120"
|
||||
["[email protected]"]="120"
|
||||
["[email protected]"]="180"
|
||||
["[email protected]"]="76"
|
||||
["[email protected]"]="152"
|
||||
["[email protected]"]="167"
|
||||
["[email protected]"]="1024"
|
||||
)
|
||||
|
||||
for filename in "${!ios_sizes[@]}"; do
|
||||
size="${ios_sizes[$filename]}"
|
||||
sips -s format png -z $size $size "$SOURCE_ICON" --out "$ICONS_DIR/ios/$filename" 2>/dev/null
|
||||
done
|
||||
|
||||
# Android Icons
|
||||
echo "Generating Android icons..."
|
||||
mkdir -p "$ICONS_DIR/android/mipmap-mdpi"
|
||||
mkdir -p "$ICONS_DIR/android/mipmap-hdpi"
|
||||
mkdir -p "$ICONS_DIR/android/mipmap-xhdpi"
|
||||
mkdir -p "$ICONS_DIR/android/mipmap-xxhdpi"
|
||||
mkdir -p "$ICONS_DIR/android/mipmap-xxxhdpi"
|
||||
|
||||
sips -s format png -z 48 48 "$SOURCE_ICON" --out "$ICONS_DIR/android/mipmap-mdpi/ic_launcher.png" 2>/dev/null
|
||||
sips -s format png -z 48 48 "$SOURCE_ICON" --out "$ICONS_DIR/android/mipmap-mdpi/ic_launcher_round.png" 2>/dev/null
|
||||
sips -s format png -z 48 48 "$SOURCE_ICON" --out "$ICONS_DIR/android/mipmap-mdpi/ic_launcher_foreground.png" 2>/dev/null
|
||||
|
||||
sips -s format png -z 72 72 "$SOURCE_ICON" --out "$ICONS_DIR/android/mipmap-hdpi/ic_launcher.png" 2>/dev/null
|
||||
sips -s format png -z 72 72 "$SOURCE_ICON" --out "$ICONS_DIR/android/mipmap-hdpi/ic_launcher_round.png" 2>/dev/null
|
||||
sips -s format png -z 72 72 "$SOURCE_ICON" --out "$ICONS_DIR/android/mipmap-hdpi/ic_launcher_foreground.png" 2>/dev/null
|
||||
|
||||
sips -s format png -z 96 96 "$SOURCE_ICON" --out "$ICONS_DIR/android/mipmap-xhdpi/ic_launcher.png" 2>/dev/null
|
||||
sips -s format png -z 96 96 "$SOURCE_ICON" --out "$ICONS_DIR/android/mipmap-xhdpi/ic_launcher_round.png" 2>/dev/null
|
||||
sips -s format png -z 96 96 "$SOURCE_ICON" --out "$ICONS_DIR/android/mipmap-xhdpi/ic_launcher_foreground.png" 2>/dev/null
|
||||
|
||||
sips -s format png -z 144 144 "$SOURCE_ICON" --out "$ICONS_DIR/android/mipmap-xxhdpi/ic_launcher.png" 2>/dev/null
|
||||
sips -s format png -z 144 144 "$SOURCE_ICON" --out "$ICONS_DIR/android/mipmap-xxhdpi/ic_launcher_round.png" 2>/dev/null
|
||||
sips -s format png -z 144 144 "$SOURCE_ICON" --out "$ICONS_DIR/android/mipmap-xxhdpi/ic_launcher_foreground.png" 2>/dev/null
|
||||
|
||||
sips -s format png -z 192 192 "$SOURCE_ICON" --out "$ICONS_DIR/android/mipmap-xxxhdpi/ic_launcher.png" 2>/dev/null
|
||||
sips -s format png -z 192 192 "$SOURCE_ICON" --out "$ICONS_DIR/android/mipmap-xxxhdpi/ic_launcher_round.png" 2>/dev/null
|
||||
sips -s format png -z 192 192 "$SOURCE_ICON" --out "$ICONS_DIR/android/mipmap-xxxhdpi/ic_launcher_foreground.png" 2>/dev/null
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "✅ All icons updated successfully!"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
echo "Updated:"
|
||||
echo " ✓ Liquid Glass icon bundle with all appearance variants"
|
||||
echo " ✓ macOS/Desktop fallback icons"
|
||||
echo " ✓ Windows Square logos"
|
||||
echo " ✓ iOS AppIcons (18 sizes)"
|
||||
echo " ✓ Android mipmap icons (5 densities)"
|
||||
echo ""
|
||||
echo "Next: Rebuild the app with 'cd tauri && bun run tauri build'"
|
||||
|
Before Width: | Height: | Size: 2.9 MiB |
|
Before Width: | Height: | Size: 2.6 MiB |
|
After Width: | Height: | Size: 2.1 MiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 2.9 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 2.3 MiB |
|
Before Width: | Height: | Size: 4.6 MiB After Width: | Height: | Size: 2.5 MiB |
@@ -27,10 +27,106 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "light",
|
||||
"groups" : [
|
||||
{
|
||||
"layers" : [
|
||||
{
|
||||
"blend-mode" : "normal",
|
||||
"glass" : true,
|
||||
"image-name" : "Voicebox.png",
|
||||
"name" : "Voicebox"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"appearance" : "dark",
|
||||
"groups" : [
|
||||
{
|
||||
"layers" : [
|
||||
{
|
||||
"blend-mode" : "normal",
|
||||
"glass" : true,
|
||||
"image-name" : "Voicebox-Dark.png",
|
||||
"name" : "Voicebox Dark"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"appearance" : "light",
|
||||
"contrast" : "clear",
|
||||
"groups" : [
|
||||
{
|
||||
"layers" : [
|
||||
{
|
||||
"blend-mode" : "normal",
|
||||
"glass" : true,
|
||||
"image-name" : "Voicebox-ClearLight.png",
|
||||
"name" : "Voicebox Clear Light"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"appearance" : "dark",
|
||||
"contrast" : "clear",
|
||||
"groups" : [
|
||||
{
|
||||
"layers" : [
|
||||
{
|
||||
"blend-mode" : "normal",
|
||||
"glass" : true,
|
||||
"image-name" : "Voicebox-ClearDark.png",
|
||||
"name" : "Voicebox Clear Dark"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"appearance" : "light",
|
||||
"contrast" : "tinted",
|
||||
"groups" : [
|
||||
{
|
||||
"layers" : [
|
||||
{
|
||||
"blend-mode" : "normal",
|
||||
"glass" : true,
|
||||
"image-name" : "Voicebox-TintedLight.png",
|
||||
"name" : "Voicebox Tinted Light"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"appearance" : "dark",
|
||||
"contrast" : "tinted",
|
||||
"groups" : [
|
||||
{
|
||||
"layers" : [
|
||||
{
|
||||
"blend-mode" : "normal",
|
||||
"glass" : true,
|
||||
"image-name" : "Voicebox-TintedDark.png",
|
||||
"name" : "Voicebox Tinted Dark"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"supported-platforms" : {
|
||||
"circles" : [
|
||||
"watchOS"
|
||||
],
|
||||
"squares" : "shared"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 2.1 MiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 2.9 MiB |
|
After Width: | Height: | Size: 2.5 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 2.3 MiB |
|
After Width: | Height: | Size: 2.6 MiB |
@@ -47,6 +47,15 @@ version = "1.0.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
|
||||
dependencies = [
|
||||
"derive_arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atk"
|
||||
version = "0.18.2"
|
||||
@@ -285,6 +294,12 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "cfg_aliases"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.43"
|
||||
@@ -488,6 +503,17 @@ dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_arbitrary"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "0.99.20"
|
||||
@@ -674,6 +700,12 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "fdeflate"
|
||||
version = "0.3.7"
|
||||
@@ -693,6 +725,17 @@ dependencies = [
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"libredox",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.8"
|
||||
@@ -969,8 +1012,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -980,9 +1025,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasip2",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1235,6 +1282,23 @@ dependencies = [
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-rustls"
|
||||
version = "0.27.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
|
||||
dependencies = [
|
||||
"http",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tower-service",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.19"
|
||||
@@ -1628,8 +1692,15 @@ checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"libc",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
version = "0.8.1"
|
||||
@@ -1651,6 +1722,12 @@ version = "0.4.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||
|
||||
[[package]]
|
||||
name = "lru-slab"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
|
||||
|
||||
[[package]]
|
||||
name = "mac"
|
||||
version = "0.1.1"
|
||||
@@ -1709,6 +1786,12 @@ version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "minisign-verify"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e856fdd13623a2f5f2f54676a4ee49502a96a80ef4a62bcedd23d52427c44d43"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
@@ -1991,6 +2074,18 @@ dependencies = [
|
||||
"objc2-core-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-osa-kit"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f112d1746737b0da274ef79a23aac283376f335f4095a083a267a082f21db0c0"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"objc2",
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-quartz-core"
|
||||
version = "0.3.2"
|
||||
@@ -2076,6 +2171,20 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "osakit"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b"
|
||||
dependencies = [
|
||||
"objc2",
|
||||
"objc2-foundation",
|
||||
"objc2-osa-kit",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pango"
|
||||
version = "0.18.3"
|
||||
@@ -2119,7 +2228,7 @@ checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.5.18",
|
||||
"smallvec",
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
@@ -2421,6 +2530,61 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn"
|
||||
version = "0.11.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"cfg_aliases",
|
||||
"pin-project-lite",
|
||||
"quinn-proto",
|
||||
"quinn-udp",
|
||||
"rustc-hash",
|
||||
"rustls",
|
||||
"socket2",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn-proto"
|
||||
version = "0.11.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"getrandom 0.3.4",
|
||||
"lru-slab",
|
||||
"rand 0.9.2",
|
||||
"ring",
|
||||
"rustc-hash",
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"slab",
|
||||
"thiserror 2.0.18",
|
||||
"tinyvec",
|
||||
"tracing",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn-udp"
|
||||
version = "0.5.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
|
||||
dependencies = [
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"socket2",
|
||||
"tracing",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.44"
|
||||
@@ -2461,6 +2625,16 @@ dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.2"
|
||||
@@ -2481,6 +2655,16 @@ dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
@@ -2499,6 +2683,15 @@ dependencies = [
|
||||
"getrandom 0.2.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
|
||||
dependencies = [
|
||||
"getrandom 0.3.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
@@ -2532,6 +2725,15 @@ dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.5.2"
|
||||
@@ -2606,16 +2808,21 @@ dependencies = [
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-rustls",
|
||||
"hyper-util",
|
||||
"js-sys",
|
||||
"log",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"quinn",
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tower-http",
|
||||
@@ -2625,8 +2832,29 @@ dependencies = [
|
||||
"wasm-bindgen-futures",
|
||||
"wasm-streams",
|
||||
"web-sys",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"getrandom 0.2.17",
|
||||
"libc",
|
||||
"untrusted",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
@@ -2636,6 +2864,54 @@ dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd"
|
||||
dependencies = [
|
||||
"web-time",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.103.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.22"
|
||||
@@ -3026,7 +3302,7 @@ dependencies = [
|
||||
"objc2-foundation",
|
||||
"objc2-quartz-core",
|
||||
"raw-window-handle",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.5.18",
|
||||
"tracing",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
@@ -3096,6 +3372,12 @@ version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "swift-rs"
|
||||
version = "1.0.7"
|
||||
@@ -3213,6 +3495,17 @@ dependencies = [
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tar"
|
||||
version = "0.4.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a"
|
||||
dependencies = [
|
||||
"filetime",
|
||||
"libc",
|
||||
"xattr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.12.16"
|
||||
@@ -3371,6 +3664,38 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-updater"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27cbc31740f4d507712550694749572ec0e43bdd66992db7599b89fbfd6b167b"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"dirs",
|
||||
"flate2",
|
||||
"futures-util",
|
||||
"http",
|
||||
"infer",
|
||||
"log",
|
||||
"minisign-verify",
|
||||
"osakit",
|
||||
"percent-encoding",
|
||||
"reqwest",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tar",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"tempfile",
|
||||
"thiserror 2.0.18",
|
||||
"time",
|
||||
"tokio",
|
||||
"url",
|
||||
"windows-sys 0.60.2",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime"
|
||||
version = "2.9.2"
|
||||
@@ -3472,6 +3797,19 @@ dependencies = [
|
||||
"toml 0.9.11+spec-1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.3.4",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tendril"
|
||||
version = "0.4.3"
|
||||
@@ -3564,6 +3902,21 @@ dependencies = [
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.49.0"
|
||||
@@ -3592,6 +3945,16 @@ dependencies = [
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.26.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
|
||||
dependencies = [
|
||||
"rustls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.18"
|
||||
@@ -3858,6 +4221,12 @@ version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.8"
|
||||
@@ -3928,6 +4297,7 @@ dependencies = [
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-plugin-shell",
|
||||
"tauri-plugin-updater",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
@@ -4073,6 +4443,16 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-time"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webkit2gtk"
|
||||
version = "2.0.1"
|
||||
@@ -4117,6 +4497,15 @@ dependencies = [
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webview2-com"
|
||||
version = "0.38.2"
|
||||
@@ -4347,6 +4736,15 @@ dependencies = [
|
||||
"windows-targets 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
@@ -4684,6 +5082,16 @@ dependencies = [
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xattr"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rustix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
version = "0.8.1"
|
||||
@@ -4748,6 +5156,12 @@ dependencies = [
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
|
||||
|
||||
[[package]]
|
||||
name = "zerotrie"
|
||||
version = "0.2.3"
|
||||
@@ -4781,6 +5195,18 @@ dependencies = [
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "4.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"crc32fast",
|
||||
"indexmap 2.13.0",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.16"
|
||||
|
||||
@@ -19,6 +19,9 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
||||
tauri-plugin-updater = "2.0"
|
||||
|
||||
[features]
|
||||
# This feature is used for production builds or when `devPath` points to the filesystem
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"core:webview:allow-internal-toggle-devtools",
|
||||
"shell:allow-open",
|
||||
"shell:allow-execute",
|
||||
"shell:allow-spawn"
|
||||
"shell:allow-spawn",
|
||||
"updater:default"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"default":{"identifier":"default","description":"Default permissions for voicebox","local":true,"permissions":["core:default","core:window:default","core:webview:default","core:webview:allow-internal-toggle-devtools","shell:allow-open","shell:allow-execute","shell:allow-spawn"],"platforms":["linux","macOS","windows"]}}
|
||||
{"default":{"identifier":"default","description":"Default permissions for voicebox","local":true,"permissions":["core:default","core:window:default","core:webview:default","core:webview:allow-internal-toggle-devtools","shell:allow-open","shell:allow-execute","shell:allow-spawn","updater:default"],"platforms":["linux","macOS","windows"]}}
|
||||
@@ -2419,6 +2419,60 @@
|
||||
"type": "string",
|
||||
"const": "shell:deny-stdin-write",
|
||||
"markdownDescription": "Denies the stdin_write command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "This permission set configures which kind of\nupdater functions are exposed to the frontend.\n\n#### Granted Permissions\n\nThe full workflow from checking for updates to installing them\nis enabled.\n\n\n#### This default permission set includes:\n\n- `allow-check`\n- `allow-download`\n- `allow-install`\n- `allow-download-and-install`",
|
||||
"type": "string",
|
||||
"const": "updater:default",
|
||||
"markdownDescription": "This permission set configures which kind of\nupdater functions are exposed to the frontend.\n\n#### Granted Permissions\n\nThe full workflow from checking for updates to installing them\nis enabled.\n\n\n#### This default permission set includes:\n\n- `allow-check`\n- `allow-download`\n- `allow-install`\n- `allow-download-and-install`"
|
||||
},
|
||||
{
|
||||
"description": "Enables the check command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "updater:allow-check",
|
||||
"markdownDescription": "Enables the check command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the download command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "updater:allow-download",
|
||||
"markdownDescription": "Enables the download command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the download_and_install command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "updater:allow-download-and-install",
|
||||
"markdownDescription": "Enables the download_and_install command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the install command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "updater:allow-install",
|
||||
"markdownDescription": "Enables the install command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the check command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "updater:deny-check",
|
||||
"markdownDescription": "Denies the check command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the download command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "updater:deny-download",
|
||||
"markdownDescription": "Denies the download command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the download_and_install command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "updater:deny-download-and-install",
|
||||
"markdownDescription": "Denies the download_and_install command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the install command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "updater:deny-install",
|
||||
"markdownDescription": "Denies the install command without any pre-configured scope."
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -2419,6 +2419,60 @@
|
||||
"type": "string",
|
||||
"const": "shell:deny-stdin-write",
|
||||
"markdownDescription": "Denies the stdin_write command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "This permission set configures which kind of\nupdater functions are exposed to the frontend.\n\n#### Granted Permissions\n\nThe full workflow from checking for updates to installing them\nis enabled.\n\n\n#### This default permission set includes:\n\n- `allow-check`\n- `allow-download`\n- `allow-install`\n- `allow-download-and-install`",
|
||||
"type": "string",
|
||||
"const": "updater:default",
|
||||
"markdownDescription": "This permission set configures which kind of\nupdater functions are exposed to the frontend.\n\n#### Granted Permissions\n\nThe full workflow from checking for updates to installing them\nis enabled.\n\n\n#### This default permission set includes:\n\n- `allow-check`\n- `allow-download`\n- `allow-install`\n- `allow-download-and-install`"
|
||||
},
|
||||
{
|
||||
"description": "Enables the check command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "updater:allow-check",
|
||||
"markdownDescription": "Enables the check command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the download command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "updater:allow-download",
|
||||
"markdownDescription": "Enables the download command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the download_and_install command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "updater:allow-download-and-install",
|
||||
"markdownDescription": "Enables the download_and_install command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the install command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "updater:allow-install",
|
||||
"markdownDescription": "Enables the install command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the check command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "updater:deny-check",
|
||||
"markdownDescription": "Denies the check command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the download command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "updater:deny-download",
|
||||
"markdownDescription": "Denies the download command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the download_and_install command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "updater:deny-download-and-install",
|
||||
"markdownDescription": "Denies the download_and_install command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the install command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "updater:deny-install",
|
||||
"markdownDescription": "Denies the install command without any pre-configured scope."
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 685 B After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 635 B After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 822 B After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 645 B After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 824 B After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 297 KiB |
@@ -132,6 +132,22 @@ pub fn run() {
|
||||
.manage(ServerState {
|
||||
child: Mutex::new(None),
|
||||
})
|
||||
.setup(|app| {
|
||||
#[cfg(desktop)]
|
||||
app.handle().plugin(tauri_plugin_updater::Builder::new().build())?;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
// Get all windows and open devtools on the first one
|
||||
if let Some((_, window)) = app.webview_windows().iter().next() {
|
||||
window.open_devtools();
|
||||
println!("Dev tools opened");
|
||||
} else {
|
||||
println!("No window found to open dev tools");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.invoke_handler(tauri::generate_handler![start_server, stop_server])
|
||||
.on_window_event(|window, event| {
|
||||
if let WindowEvent::CloseRequested { api, .. } = event {
|
||||
@@ -177,19 +193,6 @@ pub fn run() {
|
||||
});
|
||||
}
|
||||
})
|
||||
.setup(|_app| {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
// Get all windows and open devtools on the first one
|
||||
if let Some((_, window)) = _app.webview_windows().iter().next() {
|
||||
window.open_devtools();
|
||||
println!("Dev tools opened");
|
||||
} else {
|
||||
println!("No window found to open dev tools");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"createUpdaterArtifacts": true,
|
||||
"externalBin": [
|
||||
"binaries/voicebox-server"
|
||||
],
|
||||
@@ -56,6 +57,12 @@
|
||||
"plugins": {
|
||||
"shell": {
|
||||
"open": true
|
||||
},
|
||||
"updater": {
|
||||
"pubkey": "REPLACE_WITH_YOUR_PUBLIC_KEY",
|
||||
"endpoints": [
|
||||
"https://github.com/YOUR_USERNAME/voicebox/releases/latest/download/latest.json"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||