Compare commits
10 Commits
v0.1
...
f2732b36f2
| Author | SHA1 | Date | |
|---|---|---|---|
| f2732b36f2 | |||
| 7c0a202f16 | |||
| cb01a59051 | |||
| c3f594d102 | |||
| a2753bcf66 | |||
| e36bb1ab55 | |||
| c5dc6b9dd4 | |||
| c09b05b7e7 | |||
| b99d9ce524 | |||
| ff9209062e |
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
629
android/app/src/main/assets/styles.css
Normal file
@@ -0,0 +1,629 @@
|
||||
: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;
|
||||
}
|
||||
|
||||
/* Show pointer cursor for interactive / clickable elements (override global default) */
|
||||
a, a[href], button, input[type="button"], input[type="submit"],
|
||||
[role="button"], [onclick], .clickable, .icon-btn, .control-btn, label[for],
|
||||
.station-item, [tabindex]:not([tabindex="-1"]) {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Make artwork/logo clickable: show pointer cursor */
|
||||
.artwork-placeholder,
|
||||
.artwork-placeholder:hover,
|
||||
.station-logo-img,
|
||||
.station-logo-text {
|
||||
cursor: pointer !important;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* Subtle hover affordance to make clickability clearer */
|
||||
.artwork-placeholder:hover .station-logo-img,
|
||||
.artwork-placeholder:hover .station-logo-text {
|
||||
transform: scale(1.03);
|
||||
transition: transform 160ms ease;
|
||||
}
|
||||
|
||||
.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
|
||||
|
||||
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:
|
||||
|
||||
@@ -42,7 +42,7 @@ Single centered player card:
|
||||
|
||||
```
|
||||
┌──────────────────────────────┐
|
||||
│ Radio1 Player │
|
||||
│ Radio Player │
|
||||
│ ● Playing / Ready │
|
||||
│ │
|
||||
│ [ Station Artwork / Logo ] │
|
||||
@@ -52,7 +52,7 @@ Single centered player card:
|
||||
│ │
|
||||
│ ────────●──────── │
|
||||
│ │
|
||||
│ ⏮ ▶ / ⏸ ⏭ │
|
||||
│ ⏮ ▶ / ⏸ ⏭ │
|
||||
│ │
|
||||
│ 🔊 ─────●──── 50% │
|
||||
└──────────────────────────────┘
|
||||
@@ -64,7 +64,7 @@ Single centered player card:
|
||||
|
||||
### Header
|
||||
|
||||
* Title: `Radio1 Player`
|
||||
* Title: `RadioPlayer`
|
||||
* Status indicator:
|
||||
|
||||
* `● Ready`
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<img src="assets/logo.svg" alt="Radio Player" />
|
||||
</div>
|
||||
|
||||
<p id="station">Radio 1 – Live Stream</p>
|
||||
<p id="station">Radio – Live Stream</p>
|
||||
</div>
|
||||
|
||||
<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',
|
||||
metadata: {
|
||||
metadataType: 0,
|
||||
title: 'Radio 1'
|
||||
title: 'RadioPlayer'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
461
src-tauri/Cargo.lock
generated
@@ -550,7 +550,7 @@ dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"core-foundation 0.10.1",
|
||||
"core-graphics-types",
|
||||
"foreign-types",
|
||||
"foreign-types 0.5.0",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@@ -837,7 +837,7 @@ dependencies = [
|
||||
"rustc_version",
|
||||
"toml 0.9.10+spec-1.1.0",
|
||||
"vswhom",
|
||||
"winreg",
|
||||
"winreg 0.55.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -988,6 +988,15 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "foreign-types"
|
||||
version = "0.5.0"
|
||||
@@ -995,7 +1004,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
|
||||
dependencies = [
|
||||
"foreign-types-macros",
|
||||
"foreign-types-shared",
|
||||
"foreign-types-shared 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1009,6 +1018,12 @@ dependencies = [
|
||||
"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]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.3.1"
|
||||
@@ -1425,6 +1440,25 @@ dependencies = [
|
||||
"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]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
@@ -1482,6 +1516,17 @@ dependencies = [
|
||||
"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]]
|
||||
name = "http"
|
||||
version = "1.4.0"
|
||||
@@ -1492,6 +1537,17 @@ dependencies = [
|
||||
"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]]
|
||||
name = "http-body"
|
||||
version = "1.0.1"
|
||||
@@ -1499,7 +1555,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http",
|
||||
"http 1.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1510,8 +1566,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"http",
|
||||
"http-body",
|
||||
"http 1.4.0",
|
||||
"http-body 1.0.1",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
@@ -1521,6 +1577,36 @@ version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "hyper"
|
||||
version = "1.8.1"
|
||||
@@ -1531,8 +1617,8 @@ dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"http",
|
||||
"http-body",
|
||||
"http 1.4.0",
|
||||
"http-body 1.0.1",
|
||||
"httparse",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
@@ -1542,6 +1628,33 @@ dependencies = [
|
||||
"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]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.19"
|
||||
@@ -1553,14 +1666,14 @@ dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"http 1.4.0",
|
||||
"http-body 1.0.1",
|
||||
"hyper 1.8.1",
|
||||
"ipnet",
|
||||
"libc",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"socket2 0.6.1",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@@ -2039,7 +2152,7 @@ dependencies = [
|
||||
"log",
|
||||
"mio",
|
||||
"socket-pktinfo",
|
||||
"socket2",
|
||||
"socket2 0.6.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2106,6 +2219,23 @@ dependencies = [
|
||||
"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]]
|
||||
name = "ndk"
|
||||
version = "0.9.0"
|
||||
@@ -2428,12 +2558,50 @@ dependencies = [
|
||||
"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]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
@@ -2907,6 +3075,7 @@ name = "radio-tauri"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"mdns-sd",
|
||||
"reqwest 0.11.27",
|
||||
"rust_cast",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -3073,6 +3242,50 @@ version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "reqwest"
|
||||
version = "0.12.28"
|
||||
@@ -3083,10 +3296,10 @@ dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http 1.4.0",
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper 1.8.1",
|
||||
"hyper-util",
|
||||
"js-sys",
|
||||
"log",
|
||||
@@ -3095,7 +3308,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper",
|
||||
"sync_wrapper 1.0.2",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
@@ -3132,7 +3345,7 @@ dependencies = [
|
||||
"log",
|
||||
"protobuf",
|
||||
"protobuf-codegen",
|
||||
"rustls",
|
||||
"rustls 0.23.35",
|
||||
"rustls-native-certs",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
@@ -3174,6 +3387,18 @@ dependencies = [
|
||||
"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]]
|
||||
name = "rustls"
|
||||
version = "0.23.35"
|
||||
@@ -3184,7 +3409,7 @@ dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki",
|
||||
"rustls-webpki 0.103.8",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
@@ -3196,12 +3421,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5"
|
||||
dependencies = [
|
||||
"openssl-probe",
|
||||
"rustls-pemfile",
|
||||
"rustls-pemfile 2.2.0",
|
||||
"rustls-pki-types",
|
||||
"schannel",
|
||||
"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]]
|
||||
name = "rustls-pemfile"
|
||||
version = "2.2.0"
|
||||
@@ -3220,6 +3454,16 @@ dependencies = [
|
||||
"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]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.103.8"
|
||||
@@ -3319,6 +3563,16 @@ version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "security-framework"
|
||||
version = "2.11.1"
|
||||
@@ -3636,10 +3890,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "927136cc2ae6a1b0e66ac6b1210902b75c3f726db004a73bc18686dcd0dcd22f"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"socket2",
|
||||
"socket2 0.6.1",
|
||||
"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]]
|
||||
name = "socket2"
|
||||
version = "0.6.1"
|
||||
@@ -3789,6 +4053,12 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "1.0.2"
|
||||
@@ -3809,6 +4079,27 @@ dependencies = [
|
||||
"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]]
|
||||
name = "system-deps"
|
||||
version = "6.2.2"
|
||||
@@ -3895,7 +4186,7 @@ dependencies = [
|
||||
"glob",
|
||||
"gtk",
|
||||
"heck 0.5.0",
|
||||
"http",
|
||||
"http 1.4.0",
|
||||
"jni",
|
||||
"libc",
|
||||
"log",
|
||||
@@ -3909,7 +4200,7 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
"plist",
|
||||
"raw-window-handle",
|
||||
"reqwest",
|
||||
"reqwest 0.12.28",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
@@ -4062,7 +4353,7 @@ dependencies = [
|
||||
"cookie",
|
||||
"dpi",
|
||||
"gtk",
|
||||
"http",
|
||||
"http 1.4.0",
|
||||
"jni",
|
||||
"objc2",
|
||||
"objc2-ui-kit",
|
||||
@@ -4085,7 +4376,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "187a3f26f681bdf028f796ccf57cf478c1ee422c50128e5a0a6ebeb3f5910065"
|
||||
dependencies = [
|
||||
"gtk",
|
||||
"http",
|
||||
"http 1.4.0",
|
||||
"jni",
|
||||
"log",
|
||||
"objc2",
|
||||
@@ -4118,7 +4409,7 @@ dependencies = [
|
||||
"dunce",
|
||||
"glob",
|
||||
"html5ever",
|
||||
"http",
|
||||
"http 1.4.0",
|
||||
"infer",
|
||||
"json-patch",
|
||||
"kuchikiki",
|
||||
@@ -4271,7 +4562,7 @@ dependencies = [
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"socket2 0.6.1",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
@@ -4287,6 +4578,26 @@ dependencies = [
|
||||
"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]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.17"
|
||||
@@ -4405,7 +4716,7 @@ dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"pin-project-lite",
|
||||
"sync_wrapper",
|
||||
"sync_wrapper 1.0.2",
|
||||
"tokio",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
@@ -4420,8 +4731,8 @@ dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http 1.4.0",
|
||||
"http-body 1.0.1",
|
||||
"iri-string",
|
||||
"pin-project-lite",
|
||||
"tower",
|
||||
@@ -4630,6 +4941,12 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version-compare"
|
||||
version = "0.2.1"
|
||||
@@ -4827,6 +5144,12 @@ dependencies = [
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.25.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
|
||||
|
||||
[[package]]
|
||||
name = "webview2-com"
|
||||
version = "0.38.0"
|
||||
@@ -5069,6 +5392,15 @@ dependencies = [
|
||||
"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]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
@@ -5120,6 +5452,21 @@ dependencies = [
|
||||
"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]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
@@ -5177,6 +5524,12 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
@@ -5195,6 +5548,12 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
@@ -5213,6 +5572,12 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
@@ -5243,6 +5608,12 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
@@ -5261,6 +5632,12 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
@@ -5279,6 +5656,12 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
@@ -5297,6 +5680,12 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
@@ -5327,6 +5716,16 @@ dependencies = [
|
||||
"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]]
|
||||
name = "winreg"
|
||||
version = "0.55.0"
|
||||
@@ -5365,7 +5764,7 @@ dependencies = [
|
||||
"gdkx11",
|
||||
"gtk",
|
||||
"html5ever",
|
||||
"http",
|
||||
"http 1.4.0",
|
||||
"javascriptcore-rs",
|
||||
"jni",
|
||||
"kuchikiki",
|
||||
|
||||
@@ -26,4 +26,5 @@ rust_cast = "0.19.0"
|
||||
mdns-sd = "0.17.1"
|
||||
tokio = { version = "1.48.0", features = ["full"] }
|
||||
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
|
||||
--> 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.
|
||||