Compare commits
5 Commits
master
...
a2753bcf66
| Author | SHA1 | Date | |
|---|---|---|---|
| a2753bcf66 | |||
| e36bb1ab55 | |||
| c5dc6b9dd4 | |||
| c09b05b7e7 | |||
| b99d9ce524 |
11
android/README.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
This folder is not a full Android Studio project.
|
||||||
|
|
||||||
|
The buildable Android Studio/Gradle project is generated by Tauri at:
|
||||||
|
|
||||||
|
- src-tauri/gen/android
|
||||||
|
|
||||||
|
If you haven't generated it yet, run from the repo root:
|
||||||
|
|
||||||
|
- .\node_modules\.bin\tauri.cmd android init --ci
|
||||||
|
|
||||||
|
Then open `src-tauri/gen/android` in Android Studio and build the APK/AAB.
|
||||||
BIN
android/app/src/main/assets/assets/appIcon.png
Normal file
|
After Width: | Height: | Size: 682 KiB |
BIN
android/app/src/main/assets/assets/favicon_io.zip
Normal file
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 290 KiB |
BIN
android/app/src/main/assets/assets/favicon_io/app-icon.png
Normal file
|
After Width: | Height: | Size: 290 KiB |
|
After Width: | Height: | Size: 49 KiB |
BIN
android/app/src/main/assets/assets/favicon_io/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 859 B |
BIN
android/app/src/main/assets/assets/favicon_io/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
android/app/src/main/assets/assets/favicon_io/icon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1 @@
|
|||||||
|
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
|
||||||
1
android/app/src/main/assets/assets/javascript.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="32" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path fill="#F7DF1E" d="M0 0h256v256H0V0Z"></path><path d="m67.312 213.932l19.59-11.856c3.78 6.701 7.218 12.371 15.465 12.371c7.905 0 12.89-3.092 12.89-15.12v-81.798h24.057v82.138c0 24.917-14.606 36.259-35.916 36.259c-19.245 0-30.416-9.967-36.087-21.996m85.07-2.576l19.588-11.341c5.157 8.421 11.859 14.607 23.715 14.607c9.969 0 16.325-4.984 16.325-11.858c0-8.248-6.53-11.17-17.528-15.98l-6.013-2.58c-17.357-7.387-28.87-16.667-28.87-36.257c0-18.044 13.747-31.792 35.228-31.792c15.294 0 26.292 5.328 34.196 19.247l-18.732 12.03c-4.125-7.389-8.591-10.31-15.465-10.31c-7.046 0-11.514 4.468-11.514 10.31c0 7.217 4.468 10.14 14.778 14.608l6.014 2.577c20.45 8.765 31.963 17.7 31.963 37.804c0 21.654-17.012 33.51-39.867 33.51c-22.339 0-36.774-10.654-43.819-24.574"></path></svg>
|
||||||
|
After Width: | Height: | Size: 995 B |
4
android/app/src/main/assets/assets/tauri.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="206" height="231" viewBox="0 0 206 231">
|
||||||
|
<!-- Wrapper SVG that embeds the PNG app icon so existing references to tauri.svg render the PNG -->
|
||||||
|
<image href="appIcon.png" width="206" height="231" preserveAspectRatio="xMidYMid slice" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 289 B |
158
android/app/src/main/assets/index.html
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Radio Player</title>
|
||||||
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
<script src="main.js" defer type="module"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="app-container">
|
||||||
|
<div class="bg-shape shape-1"></div>
|
||||||
|
<div class="bg-shape shape-2"></div>
|
||||||
|
|
||||||
|
<main class="glass-card">
|
||||||
|
<header data-tauri-drag-region>
|
||||||
|
<button id="menu-btn" class="icon-btn" aria-label="Menu">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||||
|
stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<line x1="3" y1="12" x2="21" y2="12"></line>
|
||||||
|
<line x1="3" y1="6" x2="21" y2="6"></line>
|
||||||
|
<line x1="3" y1="18" x2="21" y2="18"></line>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div class="header-info" data-tauri-drag-region>
|
||||||
|
<span class="app-title">Radio1 Player</span>
|
||||||
|
<span class="status-indicator" id="status-indicator">
|
||||||
|
<span class="status-dot"></span> <span id="status-text">Ready</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="header-buttons">
|
||||||
|
<button id="cast-toggle-btn" class="icon-btn" aria-label="Cast">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||||
|
stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M2 16.1A5 5 0 0 1 5.9 20M2 12.05A9 9 0 0 1 9.95 20M2 8V6a14 14 0 0 1 14 14h-2" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button id="close-btn" class="icon-btn close-btn" aria-label="Close">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||||
|
stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||||
|
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section class="artwork-section">
|
||||||
|
<div class="artwork-container">
|
||||||
|
<div class="artwork-placeholder">
|
||||||
|
<!-- Gooey SVG filter for fluid blob blending -->
|
||||||
|
<svg width="0" height="0" style="position:absolute">
|
||||||
|
<defs>
|
||||||
|
<filter id="goo">
|
||||||
|
<!-- increased blur for smoother, more transparent blending -->
|
||||||
|
<feGaussianBlur in="SourceGraphic" stdDeviation="18" result="blur" />
|
||||||
|
<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7" result="goo" />
|
||||||
|
<feBlend in="SourceGraphic" in2="goo" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<div class="logo-blobs" aria-hidden="true">
|
||||||
|
<span class="blob b1"></span>
|
||||||
|
<span class="blob b2"></span>
|
||||||
|
<span class="blob b3"></span>
|
||||||
|
<span class="blob b4"></span>
|
||||||
|
<span class="blob b5"></span>
|
||||||
|
<span class="blob b6"></span>
|
||||||
|
<span class="blob b7"></span>
|
||||||
|
<span class="blob b8"></span>
|
||||||
|
<span class="blob b9"></span>
|
||||||
|
<span class="blob b10"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<img id="station-logo-img" class="station-logo-img hidden" alt="station logo">
|
||||||
|
<span class="station-logo-text">1</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="track-info">
|
||||||
|
<h2 id="station-name"></h2>
|
||||||
|
<p id="station-subtitle"></p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Visual Progress Bar (Live) -->
|
||||||
|
<div class="progress-container">
|
||||||
|
<div class="progress-bar">
|
||||||
|
<div class="progress-fill"></div>
|
||||||
|
<div class="progress-handle"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="controls-section">
|
||||||
|
<button id="prev-btn" class="control-btn secondary" aria-label="Previous Station">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
|
||||||
|
<path d="M6 6h2v12H6zm3.5 6l8.5 6V6z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button id="play-btn" class="control-btn primary" aria-label="Play">
|
||||||
|
<div class="icon-container">
|
||||||
|
<!-- Play Icon -->
|
||||||
|
<svg id="icon-play" width="32" height="32" viewBox="0 0 24 24" fill="currentColor">
|
||||||
|
<path d="M8 5v14l11-7z" />
|
||||||
|
</svg>
|
||||||
|
<!-- Stop/Pause Icon (Hidden by default) -->
|
||||||
|
<svg id="icon-stop" class="hidden" width="32" height="32" viewBox="0 0 24 24" fill="currentColor">
|
||||||
|
<path d="M6 6h12v12H6z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button id="next-btn" class="control-btn secondary" aria-label="Next Station">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
|
||||||
|
<path d="M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="volume-section">
|
||||||
|
<button id="mute-btn" class="icon-btn small">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon>
|
||||||
|
<path d="M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div class="slider-container">
|
||||||
|
<input type="range" id="volume-slider" min="0" max="100" value="50">
|
||||||
|
</div>
|
||||||
|
<span id="volume-value">50%</span>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Hidden Cast Overlay (Beautified) -->
|
||||||
|
<div id="cast-overlay" class="overlay hidden" aria-hidden="true" data-tauri-drag-region>
|
||||||
|
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="deviceTitle">
|
||||||
|
<h2 id="deviceTitle">Choose</h2>
|
||||||
|
|
||||||
|
<ul id="device-list" class="device-list">
|
||||||
|
<!-- Render device items here -->
|
||||||
|
<li class="device">
|
||||||
|
<div class="device-main">Scanning...</div>
|
||||||
|
<div class="device-sub">Searching for speakers</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<button id="close-overlay" class="btn cancel" type="button">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
355
android/app/src/main/assets/main.js
Normal file
@@ -0,0 +1,355 @@
|
|||||||
|
const { invoke } = window.__TAURI__.core;
|
||||||
|
const { getCurrentWindow } = window.__TAURI__.window;
|
||||||
|
|
||||||
|
// State
|
||||||
|
let stations = [];
|
||||||
|
let currentIndex = 0;
|
||||||
|
let isPlaying = false;
|
||||||
|
let currentMode = 'local'; // 'local' | 'cast'
|
||||||
|
let currentCastDevice = null;
|
||||||
|
const audio = new Audio();
|
||||||
|
|
||||||
|
// UI Elements
|
||||||
|
const stationNameEl = document.getElementById('station-name');
|
||||||
|
const stationSubtitleEl = document.getElementById('station-subtitle');
|
||||||
|
const statusTextEl = document.getElementById('status-text');
|
||||||
|
const statusDotEl = document.querySelector('.status-dot');
|
||||||
|
const playBtn = document.getElementById('play-btn');
|
||||||
|
const iconPlay = document.getElementById('icon-play');
|
||||||
|
const iconStop = document.getElementById('icon-stop');
|
||||||
|
const prevBtn = document.getElementById('prev-btn');
|
||||||
|
const nextBtn = document.getElementById('next-btn');
|
||||||
|
const volumeSlider = document.getElementById('volume-slider');
|
||||||
|
const volumeValue = document.getElementById('volume-value');
|
||||||
|
const castBtn = document.getElementById('cast-toggle-btn');
|
||||||
|
const castOverlay = document.getElementById('cast-overlay');
|
||||||
|
const closeOverlayBtn = document.getElementById('close-overlay');
|
||||||
|
const deviceListEl = document.getElementById('device-list');
|
||||||
|
const logoTextEl = document.querySelector('.station-logo-text');
|
||||||
|
const logoImgEl = document.getElementById('station-logo-img');
|
||||||
|
|
||||||
|
// Init
|
||||||
|
async function init() {
|
||||||
|
await loadStations();
|
||||||
|
setupEventListeners();
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadStations() {
|
||||||
|
try {
|
||||||
|
const resp = await fetch('stations.json');
|
||||||
|
const raw = await resp.json();
|
||||||
|
|
||||||
|
// Normalize station objects so the rest of the app can rely on `name` and `url`.
|
||||||
|
stations = raw
|
||||||
|
.map((s) => {
|
||||||
|
// If already in the old format, keep as-is
|
||||||
|
if (s.name && s.url) return s;
|
||||||
|
|
||||||
|
const name = s.title || s.id || s.name || 'Unknown';
|
||||||
|
// Prefer liveAudio, fall back to liveVideo or any common fields
|
||||||
|
const url = s.liveAudio || s.liveVideo || s.liveStream || s.url || '';
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: s.id || name,
|
||||||
|
name,
|
||||||
|
url,
|
||||||
|
logo: s.logo || s.poster || '',
|
||||||
|
enabled: typeof s.enabled === 'boolean' ? s.enabled : true,
|
||||||
|
raw: s,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
// Filter out disabled stations and those without a stream URL
|
||||||
|
.filter((s) => s.enabled !== false && s.url && s.url.length > 0);
|
||||||
|
|
||||||
|
if (stations.length > 0) {
|
||||||
|
currentIndex = 0;
|
||||||
|
loadStation(currentIndex);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to load stations', e);
|
||||||
|
statusTextEl.textContent = 'Error loading stations';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupEventListeners() {
|
||||||
|
playBtn.addEventListener('click', togglePlay);
|
||||||
|
prevBtn.addEventListener('click', playPrev);
|
||||||
|
nextBtn.addEventListener('click', playNext);
|
||||||
|
|
||||||
|
volumeSlider.addEventListener('input', handleVolumeInput);
|
||||||
|
|
||||||
|
castBtn.addEventListener('click', openCastOverlay);
|
||||||
|
closeOverlayBtn.addEventListener('click', closeCastOverlay);
|
||||||
|
|
||||||
|
// Close overlay on background click
|
||||||
|
castOverlay.addEventListener('click', (e) => {
|
||||||
|
if (e.target === castOverlay) closeCastOverlay();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close button
|
||||||
|
document.getElementById('close-btn').addEventListener('click', async () => {
|
||||||
|
const appWindow = getCurrentWindow();
|
||||||
|
await appWindow.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Menu button - explicit functionality or placeholder?
|
||||||
|
// For now just log or maybe show about
|
||||||
|
document.getElementById('menu-btn').addEventListener('click', () => {
|
||||||
|
openStationsOverlay();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Hotkeys?
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadStation(index) {
|
||||||
|
if (index < 0 || index >= stations.length) return;
|
||||||
|
const station = stations[index];
|
||||||
|
|
||||||
|
stationNameEl.textContent = station.name;
|
||||||
|
stationSubtitleEl.textContent = currentMode === 'cast' ? `Casting to ${currentCastDevice}` : 'Live Stream';
|
||||||
|
|
||||||
|
// Update Logo Text (First letter or number)
|
||||||
|
// Simple heuristic: if name has a number, use it, else first letter
|
||||||
|
// If station has a logo URL, show the image; otherwise show the text fallback
|
||||||
|
if (station.logo && station.logo.length > 0) {
|
||||||
|
logoImgEl.src = station.logo;
|
||||||
|
logoImgEl.classList.remove('hidden');
|
||||||
|
logoTextEl.classList.add('hidden');
|
||||||
|
} else {
|
||||||
|
// Fallback to single-letter/logo text
|
||||||
|
logoImgEl.src = '';
|
||||||
|
logoImgEl.classList.add('hidden');
|
||||||
|
const numberMatch = station.name.match(/\d+/);
|
||||||
|
if (numberMatch) {
|
||||||
|
logoTextEl.textContent = numberMatch[0];
|
||||||
|
} else {
|
||||||
|
logoTextEl.textContent = station.name.charAt(0).toUpperCase();
|
||||||
|
}
|
||||||
|
logoTextEl.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function togglePlay() {
|
||||||
|
if (isPlaying) {
|
||||||
|
await stop();
|
||||||
|
} else {
|
||||||
|
await play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function play() {
|
||||||
|
const station = stations[currentIndex];
|
||||||
|
if (!station) return;
|
||||||
|
|
||||||
|
statusTextEl.textContent = 'Buffering...';
|
||||||
|
statusDotEl.style.backgroundColor = 'var(--text-muted)'; // Grey/Yellow while loading
|
||||||
|
|
||||||
|
if (currentMode === 'local') {
|
||||||
|
audio.src = station.url;
|
||||||
|
audio.volume = volumeSlider.value / 100;
|
||||||
|
try {
|
||||||
|
await audio.play();
|
||||||
|
isPlaying = true;
|
||||||
|
updateUI();
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Playback failed', e);
|
||||||
|
statusTextEl.textContent = 'Error';
|
||||||
|
}
|
||||||
|
} else if (currentMode === 'cast' && currentCastDevice) {
|
||||||
|
// Cast logic
|
||||||
|
try {
|
||||||
|
await invoke('cast_play', { deviceName: currentCastDevice, url: station.url });
|
||||||
|
isPlaying = true;
|
||||||
|
// Sync volume
|
||||||
|
const vol = volumeSlider.value / 100;
|
||||||
|
invoke('cast_set_volume', { deviceName: currentCastDevice, volume: vol });
|
||||||
|
updateUI();
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Cast failed', e);
|
||||||
|
statusTextEl.textContent = 'Cast Error';
|
||||||
|
currentMode = 'local'; // Fallback
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function stop() {
|
||||||
|
if (currentMode === 'local') {
|
||||||
|
audio.pause();
|
||||||
|
audio.src = '';
|
||||||
|
} else if (currentMode === 'cast' && currentCastDevice) {
|
||||||
|
try {
|
||||||
|
await invoke('cast_stop', { deviceName: currentCastDevice });
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isPlaying = false;
|
||||||
|
updateUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function playNext() {
|
||||||
|
if (stations.length === 0) return;
|
||||||
|
|
||||||
|
// If playing, stop first? Or seamless?
|
||||||
|
// For radio, seamless switch requires stop then play new URL
|
||||||
|
const wasPlaying = isPlaying;
|
||||||
|
|
||||||
|
if (wasPlaying) await stop();
|
||||||
|
|
||||||
|
currentIndex = (currentIndex + 1) % stations.length;
|
||||||
|
loadStation(currentIndex);
|
||||||
|
|
||||||
|
if (wasPlaying) await play();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function playPrev() {
|
||||||
|
if (stations.length === 0) return;
|
||||||
|
|
||||||
|
const wasPlaying = isPlaying;
|
||||||
|
|
||||||
|
if (wasPlaying) await stop();
|
||||||
|
|
||||||
|
currentIndex = (currentIndex - 1 + stations.length) % stations.length;
|
||||||
|
loadStation(currentIndex);
|
||||||
|
|
||||||
|
if (wasPlaying) await play();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateUI() {
|
||||||
|
// Play/Stop Button
|
||||||
|
if (isPlaying) {
|
||||||
|
iconPlay.classList.add('hidden');
|
||||||
|
iconStop.classList.remove('hidden');
|
||||||
|
playBtn.classList.add('playing'); // Add pulsing ring animation
|
||||||
|
statusTextEl.textContent = 'Playing';
|
||||||
|
statusDotEl.style.backgroundColor = 'var(--success)';
|
||||||
|
stationSubtitleEl.textContent = currentMode === 'cast' ? `Casting to ${currentCastDevice}` : 'Live Stream';
|
||||||
|
} else {
|
||||||
|
iconPlay.classList.remove('hidden');
|
||||||
|
iconStop.classList.add('hidden');
|
||||||
|
playBtn.classList.remove('playing'); // Remove pulsing ring
|
||||||
|
statusTextEl.textContent = 'Ready';
|
||||||
|
statusDotEl.style.backgroundColor = 'var(--text-muted)';
|
||||||
|
stationSubtitleEl.textContent = currentMode === 'cast' ? `Connected to ${currentCastDevice}` : 'Live Stream';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleVolumeInput() {
|
||||||
|
const val = volumeSlider.value;
|
||||||
|
volumeValue.textContent = `${val}%`;
|
||||||
|
const decimals = val / 100;
|
||||||
|
|
||||||
|
if (currentMode === 'local') {
|
||||||
|
audio.volume = decimals;
|
||||||
|
} else if (currentMode === 'cast' && currentCastDevice) {
|
||||||
|
invoke('cast_set_volume', { deviceName: currentCastDevice, volume: decimals });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cast Logic
|
||||||
|
async function openCastOverlay() {
|
||||||
|
castOverlay.classList.remove('hidden');
|
||||||
|
castOverlay.setAttribute('aria-hidden', 'false');
|
||||||
|
deviceListEl.innerHTML = '<li class="device"><div class="device-main">Scanning...</div><div class="device-sub">Searching for speakers</div></li>';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const devices = await invoke('list_cast_devices');
|
||||||
|
deviceListEl.innerHTML = '';
|
||||||
|
|
||||||
|
// Add "This Computer" option
|
||||||
|
const localLi = document.createElement('li');
|
||||||
|
localLi.className = 'device' + (currentMode === 'local' ? ' selected' : '');
|
||||||
|
localLi.innerHTML = '<div class="device-main">This Computer</div><div class="device-sub">Local Playback</div>';
|
||||||
|
localLi.onclick = () => selectCastDevice(null);
|
||||||
|
deviceListEl.appendChild(localLi);
|
||||||
|
|
||||||
|
if (devices.length > 0) {
|
||||||
|
devices.forEach(d => {
|
||||||
|
const li = document.createElement('li');
|
||||||
|
li.className = 'device' + (currentMode === 'cast' && currentCastDevice === d ? ' selected' : '');
|
||||||
|
li.innerHTML = `<div class="device-main">${d}</div><div class="device-sub">Google Cast Speaker</div>`;
|
||||||
|
li.onclick = () => selectCastDevice(d);
|
||||||
|
deviceListEl.appendChild(li);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
deviceListEl.innerHTML = `<li class="device"><div class="device-main">Error</div><div class="device-sub">${e}</div></li>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeCastOverlay() {
|
||||||
|
castOverlay.classList.add('hidden');
|
||||||
|
castOverlay.setAttribute('aria-hidden', 'true');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function selectCastDevice(deviceName) {
|
||||||
|
closeCastOverlay();
|
||||||
|
|
||||||
|
// If checking same device, do nothing
|
||||||
|
if (deviceName === currentCastDevice) return;
|
||||||
|
|
||||||
|
// If switching mode, stop current playback
|
||||||
|
if (isPlaying) {
|
||||||
|
await stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deviceName) {
|
||||||
|
currentMode = 'cast';
|
||||||
|
currentCastDevice = deviceName;
|
||||||
|
castBtn.style.color = 'var(--success)';
|
||||||
|
} else {
|
||||||
|
currentMode = 'local';
|
||||||
|
currentCastDevice = null;
|
||||||
|
castBtn.style.color = 'var(--text-main)';
|
||||||
|
}
|
||||||
|
|
||||||
|
updateUI();
|
||||||
|
|
||||||
|
// Auto-play if we were playing? Let's stay stopped to be safe/explicit
|
||||||
|
// Or auto-play for better UX?
|
||||||
|
// Let's prompt user to play.
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('DOMContentLoaded', init);
|
||||||
|
|
||||||
|
// Open overlay and show list of stations (used by menu/hamburger)
|
||||||
|
function openStationsOverlay() {
|
||||||
|
castOverlay.classList.remove('hidden');
|
||||||
|
castOverlay.setAttribute('aria-hidden', 'false');
|
||||||
|
deviceListEl.innerHTML = '<li class="device"><div class="device-main">Loading...</div><div class="device-sub">Preparing stations</div></li>';
|
||||||
|
|
||||||
|
// If stations not loaded yet, show message
|
||||||
|
if (!stations || stations.length === 0) {
|
||||||
|
deviceListEl.innerHTML = '<li class="device"><div class="device-main">No stations found</div><div class="device-sub">Check your stations.json</div></li>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceListEl.innerHTML = '';
|
||||||
|
|
||||||
|
stations.forEach((s, idx) => {
|
||||||
|
const li = document.createElement('li');
|
||||||
|
li.className = 'device' + (currentIndex === idx ? ' selected' : '');
|
||||||
|
const subtitle = (s.raw && s.raw.www) ? s.raw.www : (s.id || '');
|
||||||
|
li.innerHTML = `<div class="device-main">${s.name}</div><div class="device-sub">${subtitle}</div>`;
|
||||||
|
li.onclick = async () => {
|
||||||
|
// Always switch to local playback when selecting from stations menu
|
||||||
|
currentMode = 'local';
|
||||||
|
currentCastDevice = null;
|
||||||
|
castBtn.style.color = 'var(--text-main)';
|
||||||
|
|
||||||
|
// Select and play
|
||||||
|
currentIndex = idx;
|
||||||
|
loadStation(currentIndex);
|
||||||
|
closeCastOverlay();
|
||||||
|
try {
|
||||||
|
await play();
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to play station from menu', e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
deviceListEl.appendChild(li);
|
||||||
|
});
|
||||||
|
}
|
||||||
1342
android/app/src/main/assets/stations.json
Normal file
606
android/app/src/main/assets/styles.css
Normal file
@@ -0,0 +1,606 @@
|
|||||||
|
:root {
|
||||||
|
--bg-gradient: linear-gradient(135deg, #7b7fd8, #b57cf2);
|
||||||
|
--glass-bg: rgba(255, 255, 255, 0.1);
|
||||||
|
--glass-border: rgba(255, 255, 255, 0.2);
|
||||||
|
--accent: #dfa6ff;
|
||||||
|
--accent-glow: rgba(223, 166, 255, 0.5);
|
||||||
|
--text-main: #ffffff;
|
||||||
|
--text-muted: rgba(255, 255, 255, 0.7);
|
||||||
|
--danger: #cf6679;
|
||||||
|
--success: #7dffb3;
|
||||||
|
--card-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-drag: none;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide Scrollbars */
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100vh;
|
||||||
|
width: 100vw;
|
||||||
|
background: linear-gradient(-45deg, #7b7fd8, #b57cf2, #8b5cf6, #6930c3, #7b7fd8);
|
||||||
|
background-size: 400% 400%;
|
||||||
|
animation: gradientShift 12s ease-in-out infinite;
|
||||||
|
font-family: 'Segoe UI', system-ui, sans-serif;
|
||||||
|
color: var(--text-main);
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes gradientShift {
|
||||||
|
0% {
|
||||||
|
background-position: 0% 50%;
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
background-position: 100% 50%;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
background-position: 50% 100%;
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
background-position: 100% 50%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position: 0% 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Background Blobs */
|
||||||
|
.bg-shape {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
filter: blur(60px);
|
||||||
|
z-index: 0;
|
||||||
|
opacity: 0.6;
|
||||||
|
animation: float 10s infinite alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape-1 {
|
||||||
|
width: 300px;
|
||||||
|
height: 300px;
|
||||||
|
background: #5e60ce;
|
||||||
|
top: -50px;
|
||||||
|
left: -50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape-2 {
|
||||||
|
width: 250px;
|
||||||
|
height: 250px;
|
||||||
|
background: #ff6bf0;
|
||||||
|
bottom: -50px;
|
||||||
|
right: -50px;
|
||||||
|
animation-delay: -5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes float {
|
||||||
|
0% { transform: translate(0, 0); }
|
||||||
|
100% { transform: translate(30px, 30px); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
padding: 10px; /* Slight padding from window edges if desired, or 0 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.glass-card {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: var(--glass-bg);
|
||||||
|
border: 1px solid var(--glass-border);
|
||||||
|
backdrop-filter: blur(24px);
|
||||||
|
border-radius: var(--card-radius);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 24px;
|
||||||
|
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
|
header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
-webkit-app-region: drag; /* Draggable area */
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-info {
|
||||||
|
text-align: center;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-title {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 1rem;
|
||||||
|
color: var(--text-main);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-indicator {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--success);
|
||||||
|
margin-top: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-dot {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
background-color: var(--success);
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: 0 0 8px var(--success);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: var(--text-main);
|
||||||
|
padding: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: background 0.2s;
|
||||||
|
-webkit-app-region: no-drag; /* Buttons clickable */
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-btn:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
align-items: center;
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-btn:hover {
|
||||||
|
background: rgba(207, 102, 121, 0.3) !important;
|
||||||
|
color: var(--danger);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Artwork */
|
||||||
|
.artwork-section {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.artwork-container {
|
||||||
|
width: 220px;
|
||||||
|
height: 220px;
|
||||||
|
border-radius: 24px;
|
||||||
|
padding: 6px; /* spacing for ring */
|
||||||
|
background: linear-gradient(135deg, rgba(255,255,255,0.1), rgba(255,255,255,0));
|
||||||
|
box-shadow: 5px 5px 15px rgba(0,0,0,0.1), inset 1px 1px 2px rgba(255,255,255,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.artwork-placeholder {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(135deg, #4ea8de, #6930c3);
|
||||||
|
border-radius: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: inset 0 0 20px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.artwork-placeholder {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(135deg, #4ea8de, #6930c3);
|
||||||
|
border-radius: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: inset 0 0 20px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.station-logo-text {
|
||||||
|
font-size: 5rem;
|
||||||
|
font-weight: 800;
|
||||||
|
font-style: italic;
|
||||||
|
color: rgba(255,255,255,0.9);
|
||||||
|
text-shadow: 0 4px 10px rgba(0,0,0,0.3);
|
||||||
|
position: relative;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.station-logo-img {
|
||||||
|
/* Fill the artwork placeholder while keeping aspect ratio and inner padding */
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
display: block;
|
||||||
|
padding: 12px; /* inner spacing from rounded edges */
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 8px 20px rgba(0,0,0,0.35);
|
||||||
|
position: relative;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Logo blobs container sits behind logo but inside artwork placeholder */
|
||||||
|
.logo-blobs {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
filter: url(#goo);
|
||||||
|
z-index: 1;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blob {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
/* more transparent overall */
|
||||||
|
opacity: 0.18;
|
||||||
|
/* slightly smaller blur for subtle definition */
|
||||||
|
filter: blur(6px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.b1 { width: 110px; height: 110px; left: 8%; top: 20%; background: radial-gradient(circle at 30% 30%, #c77dff, #8b5cf6); animation: float1 6s ease-in-out infinite; }
|
||||||
|
.b2 { width: 85px; height: 85px; right: 6%; top: 10%; background: radial-gradient(circle at 30% 30%, #7bffd1, #7dffb3); animation: float2 5.5s ease-in-out infinite; }
|
||||||
|
.b3 { width: 95px; height: 95px; left: 20%; bottom: 12%; background: radial-gradient(circle at 20% 20%, #ffd07a, #ff6bf0); animation: float3 7s ease-in-out infinite; }
|
||||||
|
.b4 { width: 70px; height: 70px; right: 24%; bottom: 18%; background: radial-gradient(circle at 30% 30%, #6bd3ff, #4ea8de); animation: float4 6.5s ease-in-out infinite; }
|
||||||
|
.b5 { width: 50px; height: 50px; left: 46%; top: 36%; background: radial-gradient(circle at 40% 40%, #ffa6d6, #c77dff); animation: float5 8s ease-in-out infinite; }
|
||||||
|
|
||||||
|
/* Additional blobs */
|
||||||
|
.b6 { width: 75px; height: 75px; left: 12%; top: 48%; background: radial-gradient(circle at 30% 30%, #bde7ff, #6bd3ff); animation: float6 6.8s ease-in-out infinite; }
|
||||||
|
.b7 { width: 42px; height: 42px; right: 10%; top: 42%; background: radial-gradient(circle at 40% 40%, #ffd9b3, #ffd07a); animation: float7 7.2s ease-in-out infinite; }
|
||||||
|
.b8 { width: 70px; height: 70px; left: 34%; bottom: 8%; background: radial-gradient(circle at 30% 30%, #e3b6ff, #c77dff); animation: float8 6.4s ease-in-out infinite; }
|
||||||
|
.b9 { width: 36px; height: 36px; right: 34%; bottom: 6%; background: radial-gradient(circle at 30% 30%, #9ef7d3, #7bffd1); animation: float9 8.4s ease-in-out infinite; }
|
||||||
|
.b10 { width: 30px; height: 30px; left: 52%; bottom: 28%; background: radial-gradient(circle at 30% 30%, #ffd0f0, #ffa6d6); animation: float10 5.8s ease-in-out infinite; }
|
||||||
|
|
||||||
|
@keyframes float1 { 0% { transform: translateY(0) translateX(0) scale(1); } 50% { transform: translateY(12px) translateX(8px) scale(1.06); } 100% { transform: translateY(0) translateX(0) scale(1); } }
|
||||||
|
@keyframes float2 { 0% { transform: translateY(0) translateX(0) scale(1); } 50% { transform: translateY(-10px) translateX(-6px) scale(1.04); } 100% { transform: translateY(0) translateX(0) scale(1); } }
|
||||||
|
@keyframes float3 { 0% { transform: translateY(0) translateX(0) scale(1); } 50% { transform: translateY(8px) translateX(-10px) scale(1.05); } 100% { transform: translateY(0) translateX(0) scale(1); } }
|
||||||
|
@keyframes float4 { 0% { transform: translateY(0) translateX(0) scale(1); } 50% { transform: translateY(-6px) translateX(10px) scale(1.03); } 100% { transform: translateY(0) translateX(0) scale(1); } }
|
||||||
|
@keyframes float5 { 0% { transform: translateY(0) translateX(0) scale(1); } 50% { transform: translateY(-12px) translateX(4px) scale(1.07); } 100% { transform: translateY(0) translateX(0) scale(1); } }
|
||||||
|
@keyframes float6 { 0% { transform: translateY(0) translateX(0) scale(1); } 50% { transform: translateY(-8px) translateX(6px) scale(1.05); } 100% { transform: translateY(0) translateX(0) scale(1); } }
|
||||||
|
@keyframes float7 { 0% { transform: translateY(0) translateX(0) scale(1); } 50% { transform: translateY(10px) translateX(-6px) scale(1.04); } 100% { transform: translateY(0) translateX(0) scale(1); } }
|
||||||
|
@keyframes float8 { 0% { transform: translateY(0) translateX(0) scale(1); } 50% { transform: translateY(-6px) translateX(10px) scale(1.03); } 100% { transform: translateY(0) translateX(0) scale(1); } }
|
||||||
|
@keyframes float9 { 0% { transform: translateY(0) translateX(0) scale(1); } 50% { transform: translateY(12px) translateX(-4px) scale(1.06); } 100% { transform: translateY(0) translateX(0) scale(1); } }
|
||||||
|
@keyframes float10 { 0% { transform: translateY(0) translateX(0) scale(1); } 50% { transform: translateY(-10px) translateX(2px) scale(1.04); } 100% { transform: translateY(0) translateX(0) scale(1); } }
|
||||||
|
|
||||||
|
/* Slightly darken backdrop gradient so blobs read better */
|
||||||
|
.artwork-placeholder::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: linear-gradient(180deg, rgba(0,0,0,0.06), rgba(0,0,0,0.12));
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Track Info */
|
||||||
|
.track-info {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.track-info h2 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
text-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.track-info p {
|
||||||
|
margin: 6px 0 0;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Progress Bar (Visual) */
|
||||||
|
.progress-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 4px;
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
border-radius: 2px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-fill {
|
||||||
|
width: 100%; /* Live always full or pulsing */
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, var(--accent), #fff);
|
||||||
|
border-radius: 2px;
|
||||||
|
opacity: 0.8;
|
||||||
|
box-shadow: 0 0 10px var(--accent-glow);
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-handle {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(50%, -50%);
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: 0 0 10px rgba(255,255,255,0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Controls */
|
||||||
|
.controls-section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 30px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: var(--text-main);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.1s, opacity 0.2s;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-btn:active {
|
||||||
|
transform: scale(0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-btn.secondary {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(255,255,255,0.05);
|
||||||
|
border: 1px solid rgba(255,255,255,0.1);
|
||||||
|
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-btn.primary {
|
||||||
|
width: 72px;
|
||||||
|
height: 72px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: linear-gradient(135deg, rgba(255,255,255,0.2), rgba(255,255,255,0.05));
|
||||||
|
border: 1px solid rgba(255,255,255,0.3);
|
||||||
|
box-shadow: 0 8px 20px rgba(0,0,0,0.2), inset 0 0 10px rgba(255,255,255,0.1);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-btn.primary svg {
|
||||||
|
filter: drop-shadow(0 0 5px var(--accent-glow));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Playing state - pulsing glow ring */
|
||||||
|
.control-btn.primary.playing {
|
||||||
|
animation: pulse-ring 2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse-ring {
|
||||||
|
0%, 100% {
|
||||||
|
box-shadow: 0 8px 20px rgba(0,0,0,0.2),
|
||||||
|
inset 0 0 10px rgba(255,255,255,0.1),
|
||||||
|
0 0 0 0 rgba(223, 166, 255, 0.7);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
box-shadow: 0 8px 20px rgba(0,0,0,0.2),
|
||||||
|
inset 0 0 10px rgba(255,255,255,0.1),
|
||||||
|
0 0 0 8px rgba(223, 166, 255, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icon container prevents layout jump */
|
||||||
|
.icon-container {
|
||||||
|
position: relative;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-container svg {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Volume */
|
||||||
|
.volume-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: auto;
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider-container {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=range] {
|
||||||
|
width: 100%;
|
||||||
|
background: transparent;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=range]::-webkit-slider-runnable-track {
|
||||||
|
width: 100%;
|
||||||
|
height: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
background: rgba(255,255,255,0.2);
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=range]::-webkit-slider-thumb {
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #ffffff;
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin-top: -6px; /* align with track */
|
||||||
|
box-shadow: 0 0 10px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#volume-value {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 500;
|
||||||
|
width: 30px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-btn.small {
|
||||||
|
padding: 0;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cast Overlay (Beautified as per layout2_plan.md) */
|
||||||
|
.overlay {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(20, 10, 35, 0.45);
|
||||||
|
backdrop-filter: blur(14px);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 1000;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay:not(.hidden) {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modal */
|
||||||
|
.modal {
|
||||||
|
width: min(420px, calc(100vw - 48px));
|
||||||
|
padding: 22px;
|
||||||
|
border-radius: 22px;
|
||||||
|
background: rgba(30, 30, 40, 0.82);
|
||||||
|
border: 1px solid rgba(255,255,255,0.12);
|
||||||
|
box-shadow: 0 30px 80px rgba(0,0,0,0.6);
|
||||||
|
color: #fff;
|
||||||
|
animation: pop 0.22s ease;
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pop {
|
||||||
|
from { transform: scale(0.94); opacity: 0; }
|
||||||
|
to { transform: scale(1); opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal h2 {
|
||||||
|
margin: 0 0 14px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Device list */
|
||||||
|
.device-list {
|
||||||
|
list-style: none;
|
||||||
|
padding: 10px 5px;
|
||||||
|
margin: 0 0 18px;
|
||||||
|
max-height: 360px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Device row */
|
||||||
|
.device {
|
||||||
|
padding: 12px 14px;
|
||||||
|
border-radius: 14px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
background: rgba(255,255,255,0.05);
|
||||||
|
transition: transform 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.device:hover {
|
||||||
|
background: rgba(255,255,255,0.10);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.device .device-main {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-main);
|
||||||
|
}
|
||||||
|
|
||||||
|
.device .device-sub {
|
||||||
|
margin-top: 3px;
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0.7;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Selected device */
|
||||||
|
.device.selected {
|
||||||
|
background: linear-gradient(135deg, #c77dff, #8b5cf6);
|
||||||
|
box-shadow: 0 0 18px rgba(199,125,255,0.65);
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
.device.selected .device-main,
|
||||||
|
.device.selected .device-sub {
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
.device.selected .device-sub {
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cancel button */
|
||||||
|
.btn.cancel {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: none;
|
||||||
|
background: #d16b7d;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 15px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.15s ease, background 0.2s;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.cancel:hover {
|
||||||
|
transform: scale(1.02);
|
||||||
|
background: #e17c8d;
|
||||||
|
}
|
||||||
BIN
android/app/src/main/jniLibs/arm64-v8a/libradio_tauri_lib.so
Normal file
BIN
android/app/src/main/jniLibs/armeabi-v7a/libradio_tauri_lib.so
Normal file
@@ -1,8 +1,8 @@
|
|||||||
# Radio1 Player – Glassmorphism UI Redesign (Tauri + HTML)
|
# Radio Player – Glassmorphism UI Redesign (Tauri + HTML)
|
||||||
|
|
||||||
## Objective
|
## Objective
|
||||||
|
|
||||||
Redesign the **Radio1 Player** UI to match a **modern glassmorphism style** inspired by high-end music player apps.
|
Redesign the **Radio Player** UI to match a **modern glassmorphism style** inspired by high-end music player apps.
|
||||||
|
|
||||||
The app is built with:
|
The app is built with:
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ Single centered player card:
|
|||||||
|
|
||||||
```
|
```
|
||||||
┌──────────────────────────────┐
|
┌──────────────────────────────┐
|
||||||
│ Radio1 Player │
|
│ Radio Player │
|
||||||
│ ● Playing / Ready │
|
│ ● Playing / Ready │
|
||||||
│ │
|
│ │
|
||||||
│ [ Station Artwork / Logo ] │
|
│ [ Station Artwork / Logo ] │
|
||||||
@@ -52,7 +52,7 @@ Single centered player card:
|
|||||||
│ │
|
│ │
|
||||||
│ ────────●──────── │
|
│ ────────●──────── │
|
||||||
│ │
|
│ │
|
||||||
│ ⏮ ▶ / ⏸ ⏭ │
|
│ ⏮ ▶ / ⏸ ⏭ │
|
||||||
│ │
|
│ │
|
||||||
│ 🔊 ─────●──── 50% │
|
│ 🔊 ─────●──── 50% │
|
||||||
└──────────────────────────────┘
|
└──────────────────────────────┘
|
||||||
@@ -64,7 +64,7 @@ Single centered player card:
|
|||||||
|
|
||||||
### Header
|
### Header
|
||||||
|
|
||||||
* Title: `Radio1 Player`
|
* Title: `RadioPlayer`
|
||||||
* Status indicator:
|
* Status indicator:
|
||||||
|
|
||||||
* `● Ready`
|
* `● Ready`
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
<img src="assets/logo.svg" alt="Radio Player" />
|
<img src="assets/logo.svg" alt="Radio Player" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p id="station">Radio 1 – Live Stream</p>
|
<p id="station">Radio – Live Stream</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="receiver.js"></script>
|
<script src="receiver.js"></script>
|
||||||
|
|||||||
206
scripts/build-android.ps1
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
<#
|
||||||
|
Build helper for Android (Windows PowerShell)
|
||||||
|
|
||||||
|
What it does:
|
||||||
|
- Checks for required commands (`npm`, `rustup`, `cargo`, `cargo-ndk`)
|
||||||
|
- Builds frontend (runs `npm run build` if `dist`/`build` not present)
|
||||||
|
- Copies frontend files from `dist` or `src` into `android/app/src/main/assets`
|
||||||
|
- Builds Rust native libs using `cargo-ndk` (if available) for `aarch64` and `armv7`
|
||||||
|
- Copies produced `.so` files into `android/app/src/main/jniLibs/*`
|
||||||
|
|
||||||
|
Note: This script prepares the Android project. To produce the APK, open `android/` in Android Studio and run Build -> Assemble, or run `gradlew assembleDebug` locally.
|
||||||
|
#>
|
||||||
|
|
||||||
|
Set-StrictMode -Version Latest
|
||||||
|
|
||||||
|
function Check-Command($name) {
|
||||||
|
$which = Get-Command $name -ErrorAction SilentlyContinue
|
||||||
|
return $which -ne $null
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output "Starting Android prep script..."
|
||||||
|
|
||||||
|
if (-not (Check-Command npm)) { Write-Warning "npm not found in PATH. Install Node.js to build frontend." }
|
||||||
|
if (-not (Check-Command rustup)) { Write-Warning "rustup not found in PATH. Install Rust toolchain." }
|
||||||
|
if (-not (Check-Command cargo)) { Write-Warning "cargo not found in PATH." }
|
||||||
|
|
||||||
|
$cargoNdkAvailable = Check-Command cargo-ndk
|
||||||
|
if (-not $cargoNdkAvailable) { Write-Warning "cargo-ndk not found. Native libs will not be built. Install via 'cargo install cargo-ndk'" }
|
||||||
|
|
||||||
|
# Determine repository root (parent of the scripts folder)
|
||||||
|
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||||
|
$root = Split-Path -Parent $scriptDir
|
||||||
|
Push-Location $root
|
||||||
|
|
||||||
|
# Prefer Tauri-generated Android Studio project (tauri android init)
|
||||||
|
$androidRoot = Join-Path $root 'src-tauri\gen\android'
|
||||||
|
if (-not (Test-Path $androidRoot)) {
|
||||||
|
# Legacy fallback (non-Tauri project)
|
||||||
|
$androidRoot = Join-Path $root 'android'
|
||||||
|
}
|
||||||
|
|
||||||
|
function Escape-LocalPropertiesPath([string]$p) {
|
||||||
|
# local.properties expects ':' escaped and backslashes doubled on Windows.
|
||||||
|
# Use plain string replacements to avoid regex escaping pitfalls.
|
||||||
|
return ($p.Replace('\', '\\').Replace(':', '\:'))
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ensure Android SDK/NDK locations are set for Gradle (local.properties)
|
||||||
|
$sdkRoot = $env:ANDROID_SDK_ROOT
|
||||||
|
if (-not $sdkRoot) { $sdkRoot = $env:ANDROID_HOME }
|
||||||
|
if (-not $sdkRoot) { $sdkRoot = Join-Path $env:LOCALAPPDATA 'Android\Sdk' }
|
||||||
|
|
||||||
|
$ndkRoot = $env:ANDROID_NDK_ROOT
|
||||||
|
if (-not $ndkRoot) { $ndkRoot = $env:ANDROID_NDK_HOME }
|
||||||
|
if (-not $ndkRoot -and (Test-Path (Join-Path $sdkRoot 'ndk'))) {
|
||||||
|
$ndkVersions = Get-ChildItem -Path (Join-Path $sdkRoot 'ndk') -Directory -ErrorAction SilentlyContinue | Sort-Object Name -Descending
|
||||||
|
if ($ndkVersions -and (@($ndkVersions)).Count -gt 0) { $ndkRoot = @($ndkVersions)[0].FullName }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Test-Path $androidRoot) {
|
||||||
|
$localPropsPath = Join-Path $androidRoot 'local.properties'
|
||||||
|
$lines = @()
|
||||||
|
if ($sdkRoot) { $lines += "sdk.dir=$(Escape-LocalPropertiesPath $sdkRoot)" }
|
||||||
|
if ($ndkRoot) { $lines += "ndk.dir=$(Escape-LocalPropertiesPath $ndkRoot)" }
|
||||||
|
if ($lines.Count -gt 0) {
|
||||||
|
Set-Content -Path $localPropsPath -Value ($lines -join "`n") -Encoding ASCII
|
||||||
|
Write-Output "Wrote Android SDK/NDK config to: $localPropsPath"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build frontend (optional)
|
||||||
|
Write-Output "Preparing frontend files..."
|
||||||
|
$distDirs = @('dist','build')
|
||||||
|
$foundDist = $null
|
||||||
|
foreach ($d in $distDirs) {
|
||||||
|
if (Test-Path (Join-Path $root $d)) { $foundDist = $d; break }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $foundDist) {
|
||||||
|
# IMPORTANT: `npm run build` in this repo runs `tauri build`, which is a desktop bundling step.
|
||||||
|
# For Android prep we only need web assets, so we fall back to copying `src/` as assets.
|
||||||
|
Write-Warning "No dist/build output found — copying `src/` as assets (skipping `npm run build` to avoid desktop bundling)."
|
||||||
|
}
|
||||||
|
|
||||||
|
$assetsDst = Join-Path $androidRoot 'app\src\main\assets'
|
||||||
|
if (-not (Test-Path $assetsDst)) { New-Item -ItemType Directory -Path $assetsDst -Force | Out-Null }
|
||||||
|
|
||||||
|
if ($foundDist) {
|
||||||
|
Write-Output "Copying frontend from '$foundDist' to Android assets..."
|
||||||
|
robocopy (Join-Path $root $foundDist) $assetsDst /MIR | Out-Null
|
||||||
|
} else {
|
||||||
|
Write-Output "Copying raw 'src' to Android assets..."
|
||||||
|
robocopy (Join-Path $root 'src') $assetsDst /MIR | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build native libs if cargo-ndk available
|
||||||
|
if ($cargoNdkAvailable) {
|
||||||
|
Write-Output "Building Rust native libs via cargo-ndk from project root: $root"
|
||||||
|
try {
|
||||||
|
# Build from the Rust crate directory `src-tauri`
|
||||||
|
$crateDir = Join-Path $root 'src-tauri'
|
||||||
|
if (-not (Test-Path (Join-Path $crateDir 'Cargo.toml'))) {
|
||||||
|
Write-Warning "Cargo.toml not found in src-tauri; skipping native build."
|
||||||
|
} else {
|
||||||
|
# Prefer Ninja generator for CMake if available (avoids Visual Studio generator issues)
|
||||||
|
# Restore env vars at the end so we don't pollute the current PowerShell session.
|
||||||
|
$oldCmakeGenerator = $env:CMAKE_GENERATOR
|
||||||
|
$oldCmakeMakeProgram = $env:CMAKE_MAKE_PROGRAM
|
||||||
|
$ninjaCmd = Get-Command ninja -ErrorAction SilentlyContinue
|
||||||
|
if ($ninjaCmd) {
|
||||||
|
Write-Output "Ninja detected at $($ninjaCmd.Source); setting CMake generator to Ninja."
|
||||||
|
$env:CMAKE_GENERATOR = 'Ninja'
|
||||||
|
$env:CMAKE_MAKE_PROGRAM = $ninjaCmd.Source
|
||||||
|
} else {
|
||||||
|
Write-Warning "Ninja not found in PATH. Installing Ninja or adding it to PATH is strongly recommended to avoid Visual Studio CMake generator on Windows."
|
||||||
|
}
|
||||||
|
|
||||||
|
# Attempt to locate Android NDK if environment variables are not set
|
||||||
|
if (-not $env:ANDROID_NDK_ROOT -and -not $env:ANDROID_NDK_HOME) {
|
||||||
|
$candidates = @()
|
||||||
|
if ($env:ANDROID_SDK_ROOT) { $candidates += Join-Path $env:ANDROID_SDK_ROOT 'ndk' }
|
||||||
|
if ($env:ANDROID_HOME) { $candidates += Join-Path $env:ANDROID_HOME 'ndk' }
|
||||||
|
$candidates += Join-Path $env:LOCALAPPDATA 'Android\sdk\ndk'
|
||||||
|
$candidates += Join-Path $env:USERPROFILE 'AppData\Local\Android\sdk\ndk'
|
||||||
|
$candidates += 'C:\Program Files (x86)\Android\AndroidNDK'
|
||||||
|
|
||||||
|
foreach ($cand in $candidates) {
|
||||||
|
if (Test-Path $cand) {
|
||||||
|
$versions = Get-ChildItem -Path $cand -Directory -ErrorAction SilentlyContinue | Sort-Object Name -Descending
|
||||||
|
if ($versions -and (@($versions)).Count -gt 0) {
|
||||||
|
$ndkPath = @($versions)[0].FullName
|
||||||
|
Write-Output "Detected Android NDK at: $ndkPath"
|
||||||
|
$env:ANDROID_NDK_ROOT = $ndkPath
|
||||||
|
$env:ANDROID_NDK = $ndkPath
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (-not $env:ANDROID_NDK_ROOT) { Write-Warning "ANDROID_NDK_ROOT/ANDROID_NDK not set and no NDK found in common locations. Set ANDROID_NDK_ROOT to your NDK path." }
|
||||||
|
} else {
|
||||||
|
Write-Output "Using existing ANDROID_NDK_ROOT: $($env:ANDROID_NDK_ROOT)"
|
||||||
|
if (-not $env:ANDROID_NDK) { $env:ANDROID_NDK = $env:ANDROID_NDK_ROOT }
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ensure expected external binary placeholders exist so Tauri bundling doesn't fail
|
||||||
|
$binariesDir = Join-Path $crateDir 'binaries'
|
||||||
|
if (-not (Test-Path $binariesDir)) { New-Item -ItemType Directory -Path $binariesDir -Force | Out-Null }
|
||||||
|
$placeholder1 = Join-Path $binariesDir 'RadioPlayer-aarch64-linux-android'
|
||||||
|
$placeholder2 = Join-Path $binariesDir 'RadioPlayer-armv7-linux-androideabi'
|
||||||
|
if (-not (Test-Path $placeholder1)) { New-Item -ItemType File -Path $placeholder1 -Force | Out-Null; Write-Output "Created placeholder: $placeholder1" }
|
||||||
|
if (-not (Test-Path $placeholder2)) { New-Item -ItemType File -Path $placeholder2 -Force | Out-Null; Write-Output "Created placeholder: $placeholder2" }
|
||||||
|
|
||||||
|
# If a previous build used a different CMake generator (e.g., Visual Studio), aws-lc-sys can fail with
|
||||||
|
# "Does not match the generator used previously". Clean only the aws-lc-sys CMake build dirs.
|
||||||
|
$awsLcBuildDirs = Get-ChildItem -Path (Join-Path $crateDir 'target') -Recurse -Directory -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object { $_.Name -like 'aws-lc-sys-*' }
|
||||||
|
foreach ($d in @($awsLcBuildDirs)) {
|
||||||
|
$cmakeBuildDir = Join-Path $d.FullName 'out\build'
|
||||||
|
$cmakeCache = Join-Path $cmakeBuildDir 'CMakeCache.txt'
|
||||||
|
if (Test-Path $cmakeCache) {
|
||||||
|
Write-Output "Cleaning stale CMake cache for aws-lc-sys: $cmakeBuildDir"
|
||||||
|
Remove-Item -Path $cmakeBuildDir -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Push-Location $crateDir
|
||||||
|
try {
|
||||||
|
# Use API 24 to ensure libc symbols like getifaddrs/freeifaddrs are available.
|
||||||
|
# Build only the library to avoid linking the desktop binary for Android.
|
||||||
|
Write-Output "Running: cargo ndk -t arm64-v8a -t armeabi-v7a -P 24 build --release --lib (in $crateDir)"
|
||||||
|
cargo ndk -t arm64-v8a -t armeabi-v7a -P 24 build --release --lib
|
||||||
|
} finally {
|
||||||
|
Pop-Location
|
||||||
|
if ($null -eq $oldCmakeGenerator) { Remove-Item Env:\CMAKE_GENERATOR -ErrorAction SilentlyContinue } else { $env:CMAKE_GENERATOR = $oldCmakeGenerator }
|
||||||
|
if ($null -eq $oldCmakeMakeProgram) { Remove-Item Env:\CMAKE_MAKE_PROGRAM -ErrorAction SilentlyContinue } else { $env:CMAKE_MAKE_PROGRAM = $oldCmakeMakeProgram }
|
||||||
|
}
|
||||||
|
|
||||||
|
# Search for produced .so files under src-tauri/target
|
||||||
|
$soFiles = Get-ChildItem -Path (Join-Path $crateDir 'target') -Recurse -Filter "*.so" -ErrorAction SilentlyContinue
|
||||||
|
if (-not $soFiles) {
|
||||||
|
Write-Warning "No .so files found after build. Check cargo-ndk output above for errors."
|
||||||
|
} else {
|
||||||
|
foreach ($f in @($soFiles)) {
|
||||||
|
$full = $f.FullName
|
||||||
|
if ($full -match 'aarch64|aarch64-linux-android|arm64-v8a') { $abi = 'arm64-v8a' }
|
||||||
|
elseif ($full -match 'armv7|armv7-linux-androideabi|armeabi-v7a') { $abi = 'armeabi-v7a' }
|
||||||
|
else { continue }
|
||||||
|
|
||||||
|
$dst = Join-Path $androidRoot "app\src\main\jniLibs\$abi"
|
||||||
|
if (-not (Test-Path $dst)) { New-Item -ItemType Directory -Path $dst -Force | Out-Null }
|
||||||
|
Copy-Item $full -Destination $dst -Force
|
||||||
|
Write-Output "Copied $($f.Name) -> $dst"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Warning "cargo-ndk build failed. Exception: $($_.Exception.Message)"
|
||||||
|
if ($_.ScriptStackTrace) { Write-Output $_.ScriptStackTrace }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Warning "Skipping native lib build (cargo-ndk missing)."
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output "Android prep complete. Open '$androidRoot' in Android Studio and build the APK (or run './gradlew assembleDebug' in that folder)."
|
||||||
|
|
||||||
|
Pop-Location
|
||||||
45
scripts/build-android.sh
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Cross-platform helper for Unix-like shells
|
||||||
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
cd "$ROOT"
|
||||||
|
|
||||||
|
echo "Preparing Android assets and native libs..."
|
||||||
|
|
||||||
|
if command -v npm >/dev/null 2>&1; then
|
||||||
|
echo "Running npm install & build"
|
||||||
|
npm install
|
||||||
|
npm run build || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
DIST_DIR="dist"
|
||||||
|
if [ ! -d "$DIST_DIR" ]; then DIST_DIR="build"; fi
|
||||||
|
if [ -d "$DIST_DIR" ]; then
|
||||||
|
echo "Copying $DIST_DIR -> android/app/src/main/assets"
|
||||||
|
mkdir -p android/app/src/main/assets
|
||||||
|
rsync -a --delete "$DIST_DIR/" android/app/src/main/assets/
|
||||||
|
else
|
||||||
|
echo "No dist/build found, copying src/ -> android assets"
|
||||||
|
mkdir -p android/app/src/main/assets
|
||||||
|
rsync -a --delete src/ android/app/src/main/assets/
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v cargo-ndk >/dev/null 2>&1; then
|
||||||
|
echo "Building native libs with cargo-ndk"
|
||||||
|
cargo-ndk -t aarch64 -t armv7 build --release || true
|
||||||
|
# copy so files
|
||||||
|
find target -type f -name "*.so" | while read -r f; do
|
||||||
|
if [[ "$f" =~ aarch64|aarch64-linux-android ]]; then abi=arm64-v8a; fi
|
||||||
|
if [[ "$f" =~ armv7|armv7-linux-androideabi ]]; then abi=armeabi-v7a; fi
|
||||||
|
if [ -n "${abi-}" ]; then
|
||||||
|
mkdir -p android/app/src/main/jniLibs/$abi
|
||||||
|
cp "$f" android/app/src/main/jniLibs/$abi/
|
||||||
|
echo "Copied $f -> android/app/src/main/jniLibs/$abi/"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo "cargo-ndk not found; skipping native lib build"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Prepared Android project. Open android/ in Android Studio to build the APK (or run ./gradlew assembleDebug)."
|
||||||
@@ -175,7 +175,7 @@ function loadMedia(url) {
|
|||||||
streamType: 'LIVE',
|
streamType: 'LIVE',
|
||||||
metadata: {
|
metadata: {
|
||||||
metadataType: 0,
|
metadataType: 0,
|
||||||
title: 'Radio 1'
|
title: 'RadioPlayer'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
461
src-tauri/Cargo.lock
generated
@@ -550,7 +550,7 @@ dependencies = [
|
|||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"core-foundation 0.10.1",
|
"core-foundation 0.10.1",
|
||||||
"core-graphics-types",
|
"core-graphics-types",
|
||||||
"foreign-types",
|
"foreign-types 0.5.0",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -837,7 +837,7 @@ dependencies = [
|
|||||||
"rustc_version",
|
"rustc_version",
|
||||||
"toml 0.9.10+spec-1.1.0",
|
"toml 0.9.10+spec-1.1.0",
|
||||||
"vswhom",
|
"vswhom",
|
||||||
"winreg",
|
"winreg 0.55.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -988,6 +988,15 @@ version = "1.0.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||||
|
dependencies = [
|
||||||
|
"foreign-types-shared 0.1.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foreign-types"
|
name = "foreign-types"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@@ -995,7 +1004,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
|
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"foreign-types-macros",
|
"foreign-types-macros",
|
||||||
"foreign-types-shared",
|
"foreign-types-shared 0.3.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1009,6 +1018,12 @@ dependencies = [
|
|||||||
"syn 2.0.111",
|
"syn 2.0.111",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types-shared"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foreign-types-shared"
|
name = "foreign-types-shared"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@@ -1425,6 +1440,25 @@ dependencies = [
|
|||||||
"syn 2.0.111",
|
"syn 2.0.111",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h2"
|
||||||
|
version = "0.3.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-util",
|
||||||
|
"http 0.2.12",
|
||||||
|
"indexmap 2.12.1",
|
||||||
|
"slab",
|
||||||
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.12.3"
|
version = "0.12.3"
|
||||||
@@ -1482,6 +1516,17 @@ dependencies = [
|
|||||||
"match_token",
|
"match_token",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http"
|
||||||
|
version = "0.2.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"itoa",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@@ -1492,6 +1537,17 @@ dependencies = [
|
|||||||
"itoa",
|
"itoa",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http-body"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"http 0.2.12",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http-body"
|
name = "http-body"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@@ -1499,7 +1555,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
|
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"http",
|
"http 1.4.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1510,8 +1566,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"http",
|
"http 1.4.0",
|
||||||
"http-body",
|
"http-body 1.0.1",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1521,6 +1577,36 @@ version = "1.10.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpdate"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper"
|
||||||
|
version = "0.14.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"h2",
|
||||||
|
"http 0.2.12",
|
||||||
|
"http-body 0.4.6",
|
||||||
|
"httparse",
|
||||||
|
"httpdate",
|
||||||
|
"itoa",
|
||||||
|
"pin-project-lite",
|
||||||
|
"socket2 0.5.10",
|
||||||
|
"tokio",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
"want",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.8.1"
|
version = "1.8.1"
|
||||||
@@ -1531,8 +1617,8 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"http",
|
"http 1.4.0",
|
||||||
"http-body",
|
"http-body 1.0.1",
|
||||||
"httparse",
|
"httparse",
|
||||||
"itoa",
|
"itoa",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
@@ -1542,6 +1628,33 @@ dependencies = [
|
|||||||
"want",
|
"want",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-rustls"
|
||||||
|
version = "0.24.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
|
||||||
|
dependencies = [
|
||||||
|
"futures-util",
|
||||||
|
"http 0.2.12",
|
||||||
|
"hyper 0.14.32",
|
||||||
|
"rustls 0.21.12",
|
||||||
|
"tokio",
|
||||||
|
"tokio-rustls",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-tls"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"hyper 0.14.32",
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-util"
|
name = "hyper-util"
|
||||||
version = "0.1.19"
|
version = "0.1.19"
|
||||||
@@ -1553,14 +1666,14 @@ dependencies = [
|
|||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http 1.4.0",
|
||||||
"http-body",
|
"http-body 1.0.1",
|
||||||
"hyper",
|
"hyper 1.8.1",
|
||||||
"ipnet",
|
"ipnet",
|
||||||
"libc",
|
"libc",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2",
|
"socket2 0.6.1",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
"tracing",
|
"tracing",
|
||||||
@@ -2039,7 +2152,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"mio",
|
"mio",
|
||||||
"socket-pktinfo",
|
"socket-pktinfo",
|
||||||
"socket2",
|
"socket2 0.6.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2106,6 +2219,23 @@ dependencies = [
|
|||||||
"windows-sys 0.60.2",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "native-tls"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"openssl",
|
||||||
|
"openssl-probe",
|
||||||
|
"openssl-sys",
|
||||||
|
"schannel",
|
||||||
|
"security-framework",
|
||||||
|
"security-framework-sys",
|
||||||
|
"tempfile",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ndk"
|
name = "ndk"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@@ -2428,12 +2558,50 @@ dependencies = [
|
|||||||
"pathdiff",
|
"pathdiff",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl"
|
||||||
|
version = "0.10.75"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.10.0",
|
||||||
|
"cfg-if",
|
||||||
|
"foreign-types 0.3.2",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"openssl-macros",
|
||||||
|
"openssl-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-macros"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.111",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-probe"
|
name = "openssl-probe"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-sys"
|
||||||
|
version = "0.9.111"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "option-ext"
|
name = "option-ext"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@@ -2907,6 +3075,7 @@ name = "radio-tauri"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"mdns-sd",
|
"mdns-sd",
|
||||||
|
"reqwest 0.11.27",
|
||||||
"rust_cast",
|
"rust_cast",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -3073,6 +3242,50 @@ version = "0.8.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "reqwest"
|
||||||
|
version = "0.11.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.21.7",
|
||||||
|
"bytes",
|
||||||
|
"encoding_rs",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"h2",
|
||||||
|
"http 0.2.12",
|
||||||
|
"http-body 0.4.6",
|
||||||
|
"hyper 0.14.32",
|
||||||
|
"hyper-rustls",
|
||||||
|
"hyper-tls",
|
||||||
|
"ipnet",
|
||||||
|
"js-sys",
|
||||||
|
"log",
|
||||||
|
"mime",
|
||||||
|
"native-tls",
|
||||||
|
"once_cell",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite",
|
||||||
|
"rustls 0.21.12",
|
||||||
|
"rustls-pemfile 1.0.4",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_urlencoded",
|
||||||
|
"sync_wrapper 0.1.2",
|
||||||
|
"system-configuration",
|
||||||
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
|
"tokio-rustls",
|
||||||
|
"tower-service",
|
||||||
|
"url",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
"web-sys",
|
||||||
|
"webpki-roots",
|
||||||
|
"winreg 0.50.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.12.28"
|
version = "0.12.28"
|
||||||
@@ -3083,10 +3296,10 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http 1.4.0",
|
||||||
"http-body",
|
"http-body 1.0.1",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper",
|
"hyper 1.8.1",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
@@ -3095,7 +3308,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"sync_wrapper",
|
"sync_wrapper 1.0.2",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tower",
|
"tower",
|
||||||
@@ -3132,7 +3345,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"protobuf",
|
"protobuf",
|
||||||
"protobuf-codegen",
|
"protobuf-codegen",
|
||||||
"rustls",
|
"rustls 0.23.35",
|
||||||
"rustls-native-certs",
|
"rustls-native-certs",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
@@ -3174,6 +3387,18 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls"
|
||||||
|
version = "0.21.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"ring",
|
||||||
|
"rustls-webpki 0.101.7",
|
||||||
|
"sct",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.23.35"
|
version = "0.23.35"
|
||||||
@@ -3184,7 +3409,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"rustls-webpki",
|
"rustls-webpki 0.103.8",
|
||||||
"subtle",
|
"subtle",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
@@ -3196,12 +3421,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5"
|
checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"openssl-probe",
|
"openssl-probe",
|
||||||
"rustls-pemfile",
|
"rustls-pemfile 2.2.0",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"schannel",
|
"schannel",
|
||||||
"security-framework",
|
"security-framework",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-pemfile"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.21.7",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-pemfile"
|
name = "rustls-pemfile"
|
||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
@@ -3220,6 +3454,16 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-webpki"
|
||||||
|
version = "0.101.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
|
||||||
|
dependencies = [
|
||||||
|
"ring",
|
||||||
|
"untrusted",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-webpki"
|
name = "rustls-webpki"
|
||||||
version = "0.103.8"
|
version = "0.103.8"
|
||||||
@@ -3319,6 +3563,16 @@ version = "1.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sct"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
|
||||||
|
dependencies = [
|
||||||
|
"ring",
|
||||||
|
"untrusted",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "2.11.1"
|
version = "2.11.1"
|
||||||
@@ -3636,10 +3890,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "927136cc2ae6a1b0e66ac6b1210902b75c3f726db004a73bc18686dcd0dcd22f"
|
checksum = "927136cc2ae6a1b0e66ac6b1210902b75c3f726db004a73bc18686dcd0dcd22f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"socket2",
|
"socket2 0.6.1",
|
||||||
"windows-sys 0.60.2",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.5.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.6.1"
|
version = "0.6.1"
|
||||||
@@ -3789,6 +4053,12 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sync_wrapper"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sync_wrapper"
|
name = "sync_wrapper"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
@@ -3809,6 +4079,27 @@ dependencies = [
|
|||||||
"syn 2.0.111",
|
"syn 2.0.111",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "system-configuration"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"core-foundation 0.9.4",
|
||||||
|
"system-configuration-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "system-configuration-sys"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "system-deps"
|
name = "system-deps"
|
||||||
version = "6.2.2"
|
version = "6.2.2"
|
||||||
@@ -3895,7 +4186,7 @@ dependencies = [
|
|||||||
"glob",
|
"glob",
|
||||||
"gtk",
|
"gtk",
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"http",
|
"http 1.4.0",
|
||||||
"jni",
|
"jni",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
@@ -3909,7 +4200,7 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"plist",
|
"plist",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"reqwest",
|
"reqwest 0.12.28",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_repr",
|
"serde_repr",
|
||||||
@@ -4062,7 +4353,7 @@ dependencies = [
|
|||||||
"cookie",
|
"cookie",
|
||||||
"dpi",
|
"dpi",
|
||||||
"gtk",
|
"gtk",
|
||||||
"http",
|
"http 1.4.0",
|
||||||
"jni",
|
"jni",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-ui-kit",
|
"objc2-ui-kit",
|
||||||
@@ -4085,7 +4376,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "187a3f26f681bdf028f796ccf57cf478c1ee422c50128e5a0a6ebeb3f5910065"
|
checksum = "187a3f26f681bdf028f796ccf57cf478c1ee422c50128e5a0a6ebeb3f5910065"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gtk",
|
"gtk",
|
||||||
"http",
|
"http 1.4.0",
|
||||||
"jni",
|
"jni",
|
||||||
"log",
|
"log",
|
||||||
"objc2",
|
"objc2",
|
||||||
@@ -4118,7 +4409,7 @@ dependencies = [
|
|||||||
"dunce",
|
"dunce",
|
||||||
"glob",
|
"glob",
|
||||||
"html5ever",
|
"html5ever",
|
||||||
"http",
|
"http 1.4.0",
|
||||||
"infer",
|
"infer",
|
||||||
"json-patch",
|
"json-patch",
|
||||||
"kuchikiki",
|
"kuchikiki",
|
||||||
@@ -4271,7 +4562,7 @@ dependencies = [
|
|||||||
"parking_lot",
|
"parking_lot",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"socket2",
|
"socket2 0.6.1",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
@@ -4287,6 +4578,26 @@ dependencies = [
|
|||||||
"syn 2.0.111",
|
"syn 2.0.111",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-native-tls"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||||
|
dependencies = [
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-rustls"
|
||||||
|
version = "0.24.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
|
||||||
|
dependencies = [
|
||||||
|
"rustls 0.21.12",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-util"
|
name = "tokio-util"
|
||||||
version = "0.7.17"
|
version = "0.7.17"
|
||||||
@@ -4405,7 +4716,7 @@ dependencies = [
|
|||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"sync_wrapper",
|
"sync_wrapper 1.0.2",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower-layer",
|
"tower-layer",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
@@ -4420,8 +4731,8 @@ dependencies = [
|
|||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http 1.4.0",
|
||||||
"http-body",
|
"http-body 1.0.1",
|
||||||
"iri-string",
|
"iri-string",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"tower",
|
"tower",
|
||||||
@@ -4630,6 +4941,12 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vcpkg"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version-compare"
|
name = "version-compare"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
@@ -4827,6 +5144,12 @@ dependencies = [
|
|||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "webpki-roots"
|
||||||
|
version = "0.25.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webview2-com"
|
name = "webview2-com"
|
||||||
version = "0.38.0"
|
version = "0.38.0"
|
||||||
@@ -5069,6 +5392,15 @@ dependencies = [
|
|||||||
"windows-targets 0.42.2",
|
"windows-targets 0.42.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.48.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
@@ -5120,6 +5452,21 @@ dependencies = [
|
|||||||
"windows_x86_64_msvc 0.42.2",
|
"windows_x86_64_msvc 0.42.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm 0.48.5",
|
||||||
|
"windows_aarch64_msvc 0.48.5",
|
||||||
|
"windows_i686_gnu 0.48.5",
|
||||||
|
"windows_i686_msvc 0.48.5",
|
||||||
|
"windows_x86_64_gnu 0.48.5",
|
||||||
|
"windows_x86_64_gnullvm 0.48.5",
|
||||||
|
"windows_x86_64_msvc 0.48.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@@ -5177,6 +5524,12 @@ version = "0.42.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@@ -5195,6 +5548,12 @@ version = "0.42.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@@ -5213,6 +5572,12 @@ version = "0.42.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@@ -5243,6 +5608,12 @@ version = "0.42.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@@ -5261,6 +5632,12 @@ version = "0.42.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@@ -5279,6 +5656,12 @@ version = "0.42.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@@ -5297,6 +5680,12 @@ version = "0.42.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
@@ -5327,6 +5716,16 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winreg"
|
||||||
|
version = "0.50.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winreg"
|
name = "winreg"
|
||||||
version = "0.55.0"
|
version = "0.55.0"
|
||||||
@@ -5365,7 +5764,7 @@ dependencies = [
|
|||||||
"gdkx11",
|
"gdkx11",
|
||||||
"gtk",
|
"gtk",
|
||||||
"html5ever",
|
"html5ever",
|
||||||
"http",
|
"http 1.4.0",
|
||||||
"javascriptcore-rs",
|
"javascriptcore-rs",
|
||||||
"jni",
|
"jni",
|
||||||
"kuchikiki",
|
"kuchikiki",
|
||||||
|
|||||||
@@ -26,4 +26,5 @@ rust_cast = "0.19.0"
|
|||||||
mdns-sd = "0.17.1"
|
mdns-sd = "0.17.1"
|
||||||
tokio = { version = "1.48.0", features = ["full"] }
|
tokio = { version = "1.48.0", features = ["full"] }
|
||||||
tauri-plugin-shell = "2.3.3"
|
tauri-plugin-shell = "2.3.3"
|
||||||
|
reqwest = { version = "0.11", features = ["json", "rustls-tls"] }
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Checking radio-tauri v0.1.0 (D:\Sites\Work\Radio1\radio-tauri\src-tauri)
|
Checking radio-tauri v0.1.0 (D:\Sites\Work\RadioPlayer\radio-tauri\src-tauri)
|
||||||
warning: variable does not need to be mutable
|
warning: variable does not need to be mutable
|
||||||
--> src\lib.rs:38:9
|
--> src\lib.rs:38:9
|
||||||
|
|
|
|
||||||
|
|||||||
12
src-tauri/gen/android/.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# EditorConfig is awesome: https://EditorConfig.org
|
||||||
|
|
||||||
|
# top-most EditorConfig file
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
insert_final_newline = false
|
||||||
19
src-tauri/gen/android/.gitignore
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
*.iml
|
||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
/.idea/caches
|
||||||
|
/.idea/libraries
|
||||||
|
/.idea/modules.xml
|
||||||
|
/.idea/workspace.xml
|
||||||
|
/.idea/navEditor.xml
|
||||||
|
/.idea/assetWizardSettings.xml
|
||||||
|
.DS_Store
|
||||||
|
build
|
||||||
|
/captures
|
||||||
|
.externalNativeBuild
|
||||||
|
.cxx
|
||||||
|
local.properties
|
||||||
|
key.properties
|
||||||
|
|
||||||
|
/.tauri
|
||||||
|
/tauri.settings.gradle
|
||||||
6
src-tauri/gen/android/app/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/src/main/java/si/klevze/radioPlayer/generated
|
||||||
|
/src/main/jniLibs/**/*.so
|
||||||
|
/src/main/assets/tauri.conf.json
|
||||||
|
/tauri.build.gradle.kts
|
||||||
|
/proguard-tauri.pro
|
||||||
|
/tauri.properties
|
||||||
64
src-tauri/gen/android/app/build.gradle.kts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import java.util.Properties
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("com.android.application")
|
||||||
|
id("org.jetbrains.kotlin.android")
|
||||||
|
}
|
||||||
|
|
||||||
|
val tauriProperties = Properties().apply {
|
||||||
|
val propFile = file("tauri.properties")
|
||||||
|
if (propFile.exists()) {
|
||||||
|
propFile.inputStream().use { load(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdk = 36
|
||||||
|
namespace = "si.klevze.radioPlayer"
|
||||||
|
defaultConfig {
|
||||||
|
manifestPlaceholders["usesCleartextTraffic"] = "false"
|
||||||
|
applicationId = "si.klevze.radioPlayer"
|
||||||
|
minSdk = 24
|
||||||
|
targetSdk = 36
|
||||||
|
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
|
||||||
|
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
|
||||||
|
}
|
||||||
|
buildTypes {
|
||||||
|
getByName("debug") {
|
||||||
|
manifestPlaceholders["usesCleartextTraffic"] = "true"
|
||||||
|
isDebuggable = true
|
||||||
|
isJniDebuggable = true
|
||||||
|
isMinifyEnabled = false
|
||||||
|
packaging { jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so")
|
||||||
|
jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so")
|
||||||
|
jniLibs.keepDebugSymbols.add("*/x86/*.so")
|
||||||
|
jniLibs.keepDebugSymbols.add("*/x86_64/*.so")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getByName("release") {
|
||||||
|
isMinifyEnabled = true
|
||||||
|
proguardFiles(
|
||||||
|
*fileTree(".") { include("**/*.pro") }
|
||||||
|
.plus(getDefaultProguardFile("proguard-android-optimize.txt"))
|
||||||
|
.toList().toTypedArray()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "1.8"
|
||||||
|
}
|
||||||
|
buildFeatures {
|
||||||
|
buildConfig = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation("androidx.constraintlayout:constraintlayout:2.2.1")
|
||||||
|
implementation("androidx.webkit:webkit:1.14.0")
|
||||||
|
implementation("androidx.appcompat:appcompat:1.7.1")
|
||||||
|
implementation("androidx.activity:activity-ktx:1.10.1")
|
||||||
|
implementation("com.google.android.material:material:1.12.0")
|
||||||
|
testImplementation("junit:junit:4.13.2")
|
||||||
|
androidTestImplementation("androidx.test.ext:junit:1.1.4")
|
||||||
|
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
|
||||||
|
}
|
||||||
21
src-tauri/gen/android/app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
||||||
37
src-tauri/gen/android/app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
|
<!-- AndroidTV support -->
|
||||||
|
<uses-feature android:name="android.software.leanback" android:required="false" />
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/Theme.radio_tauri"
|
||||||
|
android:usesCleartextTraffic="${usesCleartextTraffic}">
|
||||||
|
<activity
|
||||||
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
|
||||||
|
android:launchMode="singleTask"
|
||||||
|
android:label="@string/main_activity_title"
|
||||||
|
android:name=".MainActivity"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
<!-- AndroidTV support -->
|
||||||
|
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name="androidx.core.content.FileProvider"
|
||||||
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/file_paths" />
|
||||||
|
</provider>
|
||||||
|
</application>
|
||||||
|
</manifest>
|
||||||
225
src-tauri/gen/android/app/src/main/assets/builder-debug.yml
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
x64:
|
||||||
|
firstOrDefaultFilePatterns:
|
||||||
|
- '!**/node_modules'
|
||||||
|
- '!build{,/**/*}'
|
||||||
|
- '!dist{,/**/*}'
|
||||||
|
- electron/**/*
|
||||||
|
- src/**/*
|
||||||
|
- receiver/**/*
|
||||||
|
- package.json
|
||||||
|
- '!**/*.{iml,hprof,orig,pyc,pyo,rbc,swp,csproj,sln,suo,xproj,cc,d.ts,mk,a,o,forge-meta,pdb}'
|
||||||
|
- '!**/._*'
|
||||||
|
- '!**/electron-builder.{yaml,yml,json,json5,toml,ts}'
|
||||||
|
- '!**/{.git,.hg,.svn,CVS,RCS,SCCS,__pycache__,.DS_Store,thumbs.db,.gitignore,.gitkeep,.gitattributes,.npmignore,.idea,.vs,.flowconfig,.jshintrc,.eslintrc,.circleci,.yarn-integrity,.yarn-metadata.json,yarn-error.log,yarn.lock,package-lock.json,npm-debug.log,appveyor.yml,.travis.yml,circle.yml,.nyc_output,.husky,.github,electron-builder.env}'
|
||||||
|
- '!.yarn{,/**/*}'
|
||||||
|
- '!.editorconfig'
|
||||||
|
- '!.yarnrc.yml'
|
||||||
|
nodeModuleFilePatterns:
|
||||||
|
- '**/*'
|
||||||
|
- electron/**/*
|
||||||
|
- src/**/*
|
||||||
|
- receiver/**/*
|
||||||
|
- package.json
|
||||||
|
nsis:
|
||||||
|
script: |-
|
||||||
|
!include "D:\Sites\Work\RadioCast\node_modules\app-builder-lib\templates\nsis\include\StdUtils.nsh"
|
||||||
|
!addincludedir "D:\Sites\Work\RadioCast\node_modules\app-builder-lib\templates\nsis\include"
|
||||||
|
!macro _isUpdated _a _b _t _f
|
||||||
|
${StdUtils.TestParameter} $R9 "updated"
|
||||||
|
StrCmp "$R9" "true" `${_t}` `${_f}`
|
||||||
|
!macroend
|
||||||
|
!define isUpdated `"" isUpdated ""`
|
||||||
|
|
||||||
|
!macro _isForceRun _a _b _t _f
|
||||||
|
${StdUtils.TestParameter} $R9 "force-run"
|
||||||
|
StrCmp "$R9" "true" `${_t}` `${_f}`
|
||||||
|
!macroend
|
||||||
|
!define isForceRun `"" isForceRun ""`
|
||||||
|
|
||||||
|
!macro _isKeepShortcuts _a _b _t _f
|
||||||
|
${StdUtils.TestParameter} $R9 "keep-shortcuts"
|
||||||
|
StrCmp "$R9" "true" `${_t}` `${_f}`
|
||||||
|
!macroend
|
||||||
|
!define isKeepShortcuts `"" isKeepShortcuts ""`
|
||||||
|
|
||||||
|
!macro _isNoDesktopShortcut _a _b _t _f
|
||||||
|
${StdUtils.TestParameter} $R9 "no-desktop-shortcut"
|
||||||
|
StrCmp "$R9" "true" `${_t}` `${_f}`
|
||||||
|
!macroend
|
||||||
|
!define isNoDesktopShortcut `"" isNoDesktopShortcut ""`
|
||||||
|
|
||||||
|
!macro _isDeleteAppData _a _b _t _f
|
||||||
|
${StdUtils.TestParameter} $R9 "delete-app-data"
|
||||||
|
StrCmp "$R9" "true" `${_t}` `${_f}`
|
||||||
|
!macroend
|
||||||
|
!define isDeleteAppData `"" isDeleteAppData ""`
|
||||||
|
|
||||||
|
!macro _isForAllUsers _a _b _t _f
|
||||||
|
${StdUtils.TestParameter} $R9 "allusers"
|
||||||
|
StrCmp "$R9" "true" `${_t}` `${_f}`
|
||||||
|
!macroend
|
||||||
|
!define isForAllUsers `"" isForAllUsers ""`
|
||||||
|
|
||||||
|
!macro _isForCurrentUser _a _b _t _f
|
||||||
|
${StdUtils.TestParameter} $R9 "currentuser"
|
||||||
|
StrCmp "$R9" "true" `${_t}` `${_f}`
|
||||||
|
!macroend
|
||||||
|
!define isForCurrentUser `"" isForCurrentUser ""`
|
||||||
|
|
||||||
|
!macro addLangs
|
||||||
|
!insertmacro MUI_LANGUAGE "English"
|
||||||
|
!insertmacro MUI_LANGUAGE "German"
|
||||||
|
!insertmacro MUI_LANGUAGE "French"
|
||||||
|
!insertmacro MUI_LANGUAGE "SpanishInternational"
|
||||||
|
!insertmacro MUI_LANGUAGE "SimpChinese"
|
||||||
|
!insertmacro MUI_LANGUAGE "TradChinese"
|
||||||
|
!insertmacro MUI_LANGUAGE "Japanese"
|
||||||
|
!insertmacro MUI_LANGUAGE "Korean"
|
||||||
|
!insertmacro MUI_LANGUAGE "Italian"
|
||||||
|
!insertmacro MUI_LANGUAGE "Dutch"
|
||||||
|
!insertmacro MUI_LANGUAGE "Danish"
|
||||||
|
!insertmacro MUI_LANGUAGE "Swedish"
|
||||||
|
!insertmacro MUI_LANGUAGE "Norwegian"
|
||||||
|
!insertmacro MUI_LANGUAGE "Finnish"
|
||||||
|
!insertmacro MUI_LANGUAGE "Russian"
|
||||||
|
!insertmacro MUI_LANGUAGE "Portuguese"
|
||||||
|
!insertmacro MUI_LANGUAGE "PortugueseBR"
|
||||||
|
!insertmacro MUI_LANGUAGE "Polish"
|
||||||
|
!insertmacro MUI_LANGUAGE "Ukrainian"
|
||||||
|
!insertmacro MUI_LANGUAGE "Czech"
|
||||||
|
!insertmacro MUI_LANGUAGE "Slovak"
|
||||||
|
!insertmacro MUI_LANGUAGE "Hungarian"
|
||||||
|
!insertmacro MUI_LANGUAGE "Arabic"
|
||||||
|
!insertmacro MUI_LANGUAGE "Turkish"
|
||||||
|
!insertmacro MUI_LANGUAGE "Thai"
|
||||||
|
!insertmacro MUI_LANGUAGE "Vietnamese"
|
||||||
|
!macroend
|
||||||
|
|
||||||
|
!include "C:\Users\Gregor\AppData\Local\Temp\t-6x2nSt\0-messages.nsh"
|
||||||
|
!addplugindir /x86-unicode "C:\Users\Gregor\AppData\Local\electron-builder\Cache\nsis\nsis-resources-3.4.1\plugins\x86-unicode"
|
||||||
|
|
||||||
|
Var newStartMenuLink
|
||||||
|
Var oldStartMenuLink
|
||||||
|
Var newDesktopLink
|
||||||
|
Var oldDesktopLink
|
||||||
|
Var oldShortcutName
|
||||||
|
Var oldMenuDirectory
|
||||||
|
|
||||||
|
!include "common.nsh"
|
||||||
|
!include "MUI2.nsh"
|
||||||
|
!include "multiUser.nsh"
|
||||||
|
!include "allowOnlyOneInstallerInstance.nsh"
|
||||||
|
|
||||||
|
!ifdef INSTALL_MODE_PER_ALL_USERS
|
||||||
|
!ifdef BUILD_UNINSTALLER
|
||||||
|
RequestExecutionLevel user
|
||||||
|
!else
|
||||||
|
RequestExecutionLevel admin
|
||||||
|
!endif
|
||||||
|
!else
|
||||||
|
RequestExecutionLevel user
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!ifdef BUILD_UNINSTALLER
|
||||||
|
SilentInstall silent
|
||||||
|
!else
|
||||||
|
Var appExe
|
||||||
|
Var launchLink
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!ifdef ONE_CLICK
|
||||||
|
!include "oneClick.nsh"
|
||||||
|
!else
|
||||||
|
!include "assistedInstaller.nsh"
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!insertmacro addLangs
|
||||||
|
|
||||||
|
!ifmacrodef customHeader
|
||||||
|
!insertmacro customHeader
|
||||||
|
!endif
|
||||||
|
|
||||||
|
Function .onInit
|
||||||
|
Call setInstallSectionSpaceRequired
|
||||||
|
|
||||||
|
SetOutPath $INSTDIR
|
||||||
|
${LogSet} on
|
||||||
|
|
||||||
|
!ifmacrodef preInit
|
||||||
|
!insertmacro preInit
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!ifdef DISPLAY_LANG_SELECTOR
|
||||||
|
!insertmacro MUI_LANGDLL_DISPLAY
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!ifdef BUILD_UNINSTALLER
|
||||||
|
WriteUninstaller "${UNINSTALLER_OUT_FILE}"
|
||||||
|
!insertmacro quitSuccess
|
||||||
|
!else
|
||||||
|
!insertmacro check64BitAndSetRegView
|
||||||
|
|
||||||
|
!ifdef ONE_CLICK
|
||||||
|
!insertmacro ALLOW_ONLY_ONE_INSTALLER_INSTANCE
|
||||||
|
!else
|
||||||
|
${IfNot} ${UAC_IsInnerInstance}
|
||||||
|
!insertmacro ALLOW_ONLY_ONE_INSTALLER_INSTANCE
|
||||||
|
${EndIf}
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!insertmacro initMultiUser
|
||||||
|
|
||||||
|
!ifmacrodef customInit
|
||||||
|
!insertmacro customInit
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!ifmacrodef addLicenseFiles
|
||||||
|
InitPluginsDir
|
||||||
|
!insertmacro addLicenseFiles
|
||||||
|
!endif
|
||||||
|
!endif
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
!ifndef BUILD_UNINSTALLER
|
||||||
|
!include "installUtil.nsh"
|
||||||
|
!endif
|
||||||
|
|
||||||
|
Section "install" INSTALL_SECTION_ID
|
||||||
|
!ifndef BUILD_UNINSTALLER
|
||||||
|
# If we're running a silent upgrade of a per-machine installation, elevate so extracting the new app will succeed.
|
||||||
|
# For a non-silent install, the elevation will be triggered when the install mode is selected in the UI,
|
||||||
|
# but that won't be executed when silent.
|
||||||
|
!ifndef INSTALL_MODE_PER_ALL_USERS
|
||||||
|
!ifndef ONE_CLICK
|
||||||
|
${if} $hasPerMachineInstallation == "1" # set in onInit by initMultiUser
|
||||||
|
${andIf} ${Silent}
|
||||||
|
${ifNot} ${UAC_IsAdmin}
|
||||||
|
ShowWindow $HWNDPARENT ${SW_HIDE}
|
||||||
|
!insertmacro UAC_RunElevated
|
||||||
|
${Switch} $0
|
||||||
|
${Case} 0
|
||||||
|
${Break}
|
||||||
|
${Case} 1223 ;user aborted
|
||||||
|
${Break}
|
||||||
|
${Default}
|
||||||
|
MessageBox mb_IconStop|mb_TopMost|mb_SetForeground "Unable to elevate, error $0"
|
||||||
|
${Break}
|
||||||
|
${EndSwitch}
|
||||||
|
Quit
|
||||||
|
${else}
|
||||||
|
!insertmacro setInstallModePerAllUsers
|
||||||
|
${endIf}
|
||||||
|
${endIf}
|
||||||
|
!endif
|
||||||
|
!endif
|
||||||
|
!include "installSection.nsh"
|
||||||
|
!endif
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Function setInstallSectionSpaceRequired
|
||||||
|
!insertmacro setSpaceRequired ${INSTALL_SECTION_ID}
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
!ifdef BUILD_UNINSTALLER
|
||||||
|
!include "uninstaller.nsh"
|
||||||
|
!endif
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
directories:
|
||||||
|
output: dist
|
||||||
|
buildResources: build
|
||||||
|
appId: si.klevze.radioPlayer
|
||||||
|
productName: RadioPlayer
|
||||||
|
files:
|
||||||
|
- filter:
|
||||||
|
- electron/**/*
|
||||||
|
- src/**/*
|
||||||
|
- receiver/**/*
|
||||||
|
- package.json
|
||||||
|
win:
|
||||||
|
target:
|
||||||
|
- nsis
|
||||||
|
signAndEditExecutable: false
|
||||||
|
icon: src-tauri/icons/icon.ico
|
||||||
|
mac:
|
||||||
|
target:
|
||||||
|
- dmg
|
||||||
|
icon: src-tauri/icons/icon.icns
|
||||||
|
linux:
|
||||||
|
target:
|
||||||
|
- AppImage
|
||||||
|
icon: src-tauri/icons
|
||||||
|
electronVersion: 30.5.1
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
Copyright (c) Electron contributors
|
||||||
|
Copyright (c) 2013-2020 GitHub Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||