Compass map rotation, landscape layout, GPS placeholder
- leaflet-rotate plugin: map rotates by compass heading via deviceorientation - Landscape detection: CSS viewport rotation when phone held sideways (gamma > 50) - Bottom nav hidden in landscape mode - GPS placeholder: pixel art overlay shown until GPS signal arrives - invalidateSize() after map init to prevent black screen
This commit is contained in:
parent
ad33c6defe
commit
fda820568e
8 changed files with 2284 additions and 24 deletions
|
|
@ -1059,9 +1059,53 @@ select {
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
.rec-map {
|
||||
.rec-panel {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.rec-map-wrap {
|
||||
flex: 1;
|
||||
min-height: 300px;
|
||||
min-height: 200px;
|
||||
position: relative;
|
||||
}
|
||||
.rec-map {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
}
|
||||
.gps-placeholder {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 1000;
|
||||
background: url('../img/gps-placeholder.png') center/cover;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.gps-placeholder-text {
|
||||
background: rgba(0,0,0,0.7);
|
||||
color: var(--on-bg);
|
||||
padding: 12px 24px;
|
||||
border-radius: 8px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
/* Landscape: CSS rotation compensates physical rotation.
|
||||
flex-direction stays column: element-bottom = visual-right after rotate.
|
||||
No font-size changes — everything stays portrait-sized, just rearranged. */
|
||||
.rec-screen.landscape-right,
|
||||
.rec-screen.landscape-left {
|
||||
position: fixed;
|
||||
width: 100vh;
|
||||
height: 100vw;
|
||||
top: calc((100vh - 100vw) / 2);
|
||||
left: calc((100vw - 100vh) / 2);
|
||||
z-index: 9999;
|
||||
}
|
||||
.rec-screen.landscape-right {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
.rec-screen.landscape-left {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.rec-stats {
|
||||
|
|
|
|||
BIN
frontend/img/gps-placeholder.png
Normal file
BIN
frontend/img/gps-placeholder.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
|
|
@ -13,6 +13,7 @@
|
|||
<!-- Load order matters: db.js and bmr.js expose window.DB / window.BMR,
|
||||
then main.js uses them. Tauri injects window.__TAURI__ before page scripts. -->
|
||||
<script src="lib/leaflet.js"></script>
|
||||
<script src="lib/leaflet-rotate.js"></script>
|
||||
<script src="lib/hammer.min.js"></script>
|
||||
<script src="lib/chart.min.js"></script>
|
||||
<script src="lib/chartjs-plugin-zoom.min.js"></script>
|
||||
|
|
@ -21,6 +22,7 @@
|
|||
<script src="js/bmr.js"></script>
|
||||
<script src="js/tilecache.js"></script>
|
||||
<script src="js/gps.js"></script>
|
||||
<script src="js/sync.js"></script>
|
||||
<script src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
// BalDav main app — pure JS, no framework, no bundler.
|
||||
// Depends on window.DB (db.js) and window.BMR (bmr.js) loaded before this script.
|
||||
|
||||
// Disable leaflet-rotate's compass control on all maps by default;
|
||||
// only the recording map enables rotate: true explicitly.
|
||||
if (L && L.Map) L.Map.mergeOptions({ rotateControl: false });
|
||||
|
||||
const app = document.getElementById("app");
|
||||
|
||||
const UPDATE_BASE_URL = "https://4aiman.top/baldav";
|
||||
|
|
@ -176,6 +180,9 @@ async function init() {
|
|||
// Restore last screen (fromPopstate=true to avoid duplicate navStack push)
|
||||
renderScreen(navStack[navStack.length - 1], true);
|
||||
|
||||
// Initialize sync
|
||||
try { await Sync.init(); if (Sync.userId) Sync.now(); } catch {}
|
||||
|
||||
// Check for updates in background (non-blocking)
|
||||
checkForUpdate();
|
||||
}
|
||||
|
|
@ -185,8 +192,9 @@ async function init() {
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
function renderScreen(name, fromPopstate) {
|
||||
// Release screen wake lock when leaving recording screen
|
||||
// Release screen wake lock and compass listener when leaving recording screen
|
||||
if (window._screenLock) { try { window._screenLock.release(); } catch {} window._screenLock = null; }
|
||||
if (GPS.recording._compassCleanup) { GPS.recording._compassCleanup(); GPS.recording._compassCleanup = null; }
|
||||
|
||||
const prevScreen = state.screen;
|
||||
state.screen = name;
|
||||
|
|
@ -2733,23 +2741,32 @@ function renderRecordingInline(container) {
|
|||
|
||||
container.innerHTML = `
|
||||
<div class="rec-screen">
|
||||
<div id="rec-map" class="rec-map"></div>
|
||||
<div class="rec-hr-row" id="rec-hr-row" style="display:none">
|
||||
<span id="rec-hr-val" class="rec-hr-val">--</span>
|
||||
<span class="rec-hr-unit">bpm</span>
|
||||
<span id="rec-spo2" class="rec-hr-extra"></span>
|
||||
<span id="rec-bp" class="rec-hr-extra"></span>
|
||||
<div class="rec-map-wrap">
|
||||
<div id="rec-map" class="rec-map"></div>
|
||||
<div id="gps-placeholder" class="gps-placeholder">
|
||||
<div class="gps-placeholder-text">Поиск GPS...</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rec-stats">
|
||||
<div class="rec-stat"><span id="rec-dist" class="rec-val">0 м</span><span class="rec-lbl">Дистанция</span></div>
|
||||
<div class="rec-stat"><span id="rec-speed" class="rec-val">0</span><span class="rec-lbl">км/ч</span></div>
|
||||
<div class="rec-stat"><span id="rec-time" class="rec-val">0:00</span><span class="rec-lbl">Время</span></div>
|
||||
<div class="rec-stat"><span id="rec-elev" class="rec-val">—</span><span class="rec-lbl">Высота</span></div>
|
||||
</div>
|
||||
<div class="rec-bottom">
|
||||
<div class="rec-status" id="rec-status">${GPS.recording.state === "waiting_gps" ? "Поиск GPS..." : GPS.recording.state === "ready" ? "Начните движение..." : ""}</div>
|
||||
<button id="rec-pause" class="btn-secondary">${GPS.recording.manualPaused ? "Продолжить" : "Пауза"}</button>
|
||||
<button id="rec-stop" class="btn-primary gps-rec recording">Стоп</button>
|
||||
<div class="rec-panel">
|
||||
<div class="rec-hr-row" id="rec-hr-row" style="display:none">
|
||||
<span id="rec-hr-val" class="rec-hr-val">--</span>
|
||||
<span class="rec-hr-unit">bpm</span>
|
||||
<span id="rec-spo2" class="rec-hr-extra"></span>
|
||||
<span id="rec-bp" class="rec-hr-extra"></span>
|
||||
</div>
|
||||
<div class="rec-stats">
|
||||
<div class="rec-stat"><span id="rec-dist" class="rec-val">0 м</span><span class="rec-lbl">Дистанция</span></div>
|
||||
<div class="rec-stat"><span id="rec-speed" class="rec-val">0</span><span class="rec-lbl">км/ч</span></div>
|
||||
<div class="rec-stat"><span id="rec-time" class="rec-val">0:00</span><span class="rec-lbl">Время</span></div>
|
||||
<div class="rec-stat"><span id="rec-elev" class="rec-val">—</span><span class="rec-lbl">Высота</span></div>
|
||||
<div class="rec-stat"><span id="rec-clock" class="rec-val">${new Date().toTimeString().slice(0,5)}</span><span class="rec-lbl">Часы</span></div>
|
||||
<div class="rec-stat"><span id="rec-temp" class="rec-val">—</span><span class="rec-lbl">t°C</span></div>
|
||||
</div>
|
||||
<div class="rec-bottom">
|
||||
<div class="rec-status" id="rec-status">${GPS.recording.state === "waiting_gps" ? "Поиск GPS..." : GPS.recording.state === "ready" ? "Начните движение..." : ""}</div>
|
||||
<button id="rec-pause" class="btn-secondary">${GPS.recording.manualPaused ? "Продолжить" : "Пауза"}</button>
|
||||
<button id="rec-stop" class="btn-primary gps-rec recording">Стоп</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
|
|
@ -2758,21 +2775,75 @@ function renderRecordingInline(container) {
|
|||
if (!mapEl) return;
|
||||
|
||||
L.Icon.Default.imagePath = "lib/";
|
||||
const map = L.map(mapEl, { attributionControl: false, scrollWheelZoom: false }).setView([55.75, 37.62], 15);
|
||||
// Use last known position from profile (reliable across sessions)
|
||||
const lastPt = GPS.recording.lastMovingPoint;
|
||||
const initLat = lastPt?.lat || parseFloat(state.profile.last_lat) || 47.47;
|
||||
const initLon = lastPt?.lon || parseFloat(state.profile.last_lon) || 40.07;
|
||||
const map = L.map(mapEl, { attributionControl: false, scrollWheelZoom: false, rotate: true, bearing: 0, compassBearing: false }).setView([initLat, initLon], 15);
|
||||
mapEl.addEventListener("wheel", (e) => {
|
||||
if (e.ctrlKey) { e.preventDefault(); map.setZoom(map.getZoom() + (e.deltaY < 0 ? 1 : -1)); }
|
||||
}, { passive: false });
|
||||
addZoomDisplay(map);
|
||||
const CachedLayer = TileCache.createLayer();
|
||||
new CachedLayer({ maxZoom: 19 }).addTo(map);
|
||||
// Force recalc after flex layout settles — fixes black screen on init
|
||||
setTimeout(() => map.invalidateSize(), 200);
|
||||
|
||||
const borderLine = L.polyline([], { color: "#ffffff", weight: 8, opacity: 0.8 }).addTo(map);
|
||||
const trailLine = L.polyline([], { color: "#bb86fc", weight: 5 }).addTo(map);
|
||||
|
||||
// Compass heading + landscape detection from device orientation
|
||||
let currentLandscape = null; // null | 'right' | 'left'
|
||||
const recScreen = document.querySelector('.rec-screen');
|
||||
function handleOrientation(e) {
|
||||
// Compass heading
|
||||
const heading = e.webkitCompassHeading || e.alpha || 0;
|
||||
const gamma = e.gamma || 0;
|
||||
|
||||
// Landscape detection: |gamma| > 50 = phone held sideways
|
||||
const threshold = 50;
|
||||
let newLandscape = null;
|
||||
if (gamma > threshold) newLandscape = 'right';
|
||||
else if (gamma < -threshold) newLandscape = 'left';
|
||||
|
||||
if (newLandscape !== currentLandscape) {
|
||||
currentLandscape = newLandscape;
|
||||
if (recScreen) {
|
||||
recScreen.classList.remove('landscape-right', 'landscape-left');
|
||||
if (newLandscape) recScreen.classList.add('landscape-' + newLandscape);
|
||||
}
|
||||
// Hide/show bottom nav — it's outside rec-screen, CSS can't reach it
|
||||
const nav = document.querySelector('.bottom-nav');
|
||||
if (nav) nav.style.display = newLandscape ? 'none' : '';
|
||||
// Leaflet needs to recalculate container size after CSS change
|
||||
setTimeout(() => map.invalidateSize(), 100);
|
||||
}
|
||||
|
||||
// Set map bearing: compass heading + compensation for CSS viewport rotation
|
||||
// CSS rotate(-90deg) for landscape-right, rotate(90deg) for landscape-left
|
||||
// The CSS rotation rotates the visual output, so the map bearing must compensate
|
||||
let bearingOffset = 0;
|
||||
if (currentLandscape === 'right') bearingOffset = 90;
|
||||
else if (currentLandscape === 'left') bearingOffset = -90;
|
||||
map.setBearing(heading + bearingOffset);
|
||||
}
|
||||
const throttledOrientation = L.Util.throttle(handleOrientation, 100);
|
||||
const orientEvent = 'ondeviceorientationabsolute' in window
|
||||
? 'deviceorientationabsolute' : 'deviceorientation';
|
||||
window.addEventListener(orientEvent, throttledOrientation);
|
||||
GPS.recording._compassCleanup = () => {
|
||||
window.removeEventListener(orientEvent, throttledOrientation);
|
||||
if (recScreen) recScreen.classList.remove('landscape-right', 'landscape-left');
|
||||
const nav = document.querySelector('.bottom-nav');
|
||||
if (nav) nav.style.display = '';
|
||||
};
|
||||
let posMarker = null;
|
||||
|
||||
// State changes
|
||||
GPS.recording.onStateChange = (state, p) => {
|
||||
if (state === "ready") {
|
||||
const ph = document.getElementById('gps-placeholder');
|
||||
if (ph) ph.remove();
|
||||
statusEl.textContent = "GPS OK. Начните движение...";
|
||||
statusEl.style.color = "#03dac6";
|
||||
map.setView([p.lat, p.lon], 16);
|
||||
|
|
@ -2796,10 +2867,15 @@ function renderRecordingInline(container) {
|
|||
const speedBuf = [];
|
||||
|
||||
GPS.recording.onPoint = (p) => {
|
||||
const ph = document.getElementById('gps-placeholder');
|
||||
if (ph) ph.remove();
|
||||
const ll = [p.lat, p.lon];
|
||||
borderLine.addLatLng(ll);
|
||||
trailLine.addLatLng(ll);
|
||||
map.panTo(ll);
|
||||
// Save position for next session start (avoid black screen)
|
||||
DB.setProfileValue("last_lat", String(p.lat));
|
||||
DB.setProfileValue("last_lon", String(p.lon));
|
||||
|
||||
if (posMarker) map.removeLayer(posMarker);
|
||||
posMarker = L.circleMarker(ll, { radius: 6, color: "#4285f4", fillColor: "#4285f4", fillOpacity: 1, weight: 2 }).addTo(map);
|
||||
|
|
@ -2871,8 +2947,23 @@ function renderRecordingInline(container) {
|
|||
(GPS.recording.pauseStart ? Date.now() - GPS.recording.pauseStart.getTime() : 0);
|
||||
const sec = Math.max(0, Math.round(activeMs / 1000));
|
||||
if (timeEl) timeEl.textContent = GPS.formatDuration(sec);
|
||||
// Update clock
|
||||
const clockEl = document.querySelector("#rec-clock");
|
||||
if (clockEl) clockEl.textContent = new Date().toTimeString().slice(0, 5);
|
||||
}, 1000);
|
||||
|
||||
// Fetch temperature
|
||||
(async () => {
|
||||
try {
|
||||
const pos = GPS.recording.lastMovingPoint || { lat: 55.75, lon: 37.62 };
|
||||
const url = `https://api.open-meteo.com/v1/forecast?latitude=${pos.lat.toFixed(2)}&longitude=${pos.lon.toFixed(2)}¤t=temperature_2m`;
|
||||
const resp = await window.__TAURI__.core.invoke("http_request", { url, method: "GET", body: null });
|
||||
const data = JSON.parse(resp);
|
||||
const tempEl = document.querySelector("#rec-temp");
|
||||
if (tempEl && data.current) tempEl.textContent = Math.round(data.current.temperature_2m) + "°";
|
||||
} catch (e) { console.log("[Weather]", e.message || e); }
|
||||
})();
|
||||
|
||||
// Pause button
|
||||
container.querySelector("#rec-pause").onclick = () => {
|
||||
if (GPS.recording.manualPaused) {
|
||||
|
|
@ -2890,6 +2981,7 @@ function renderRecordingInline(container) {
|
|||
|
||||
// Stop button
|
||||
container.querySelector("#rec-stop").onclick = async () => {
|
||||
if (GPS.recording._compassCleanup) GPS.recording._compassCleanup();
|
||||
await GPS.stopRecording();
|
||||
clearInterval(timer);
|
||||
renderScreen("gps");
|
||||
|
|
@ -4407,6 +4499,31 @@ async function renderSettings(container) {
|
|||
<div id="s-ble-results" style="padding:0 14px"></div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<div class="settings-section-title">Синхронизация</div>
|
||||
<div class="settings-item">
|
||||
<div class="settings-item-left">
|
||||
<div class="settings-item-title" id="s-sync-status">${Sync.userId ? "Подключено" : "Не настроено"}</div>
|
||||
<div class="settings-item-desc" id="s-sync-desc">${Sync.userId ? (state.profile.sync_last_time || "Не синхронизировано") : "Привяжите устройство"}</div>
|
||||
</div>
|
||||
<button class="btn-primary" id="s-sync-now" style="padding:6px 12px;font-size:13px">${Sync.userId ? "Синхр." : "Настроить"}</button>
|
||||
</div>
|
||||
<div id="s-sync-setup" style="padding:0 14px;display:${Sync.userId ? "none" : ""}">
|
||||
<div class="form-group" style="margin-top:8px">
|
||||
<label>Код привязки (с другого устройства)</label>
|
||||
<div style="display:flex;gap:6px">
|
||||
<input id="s-sync-code" type="text" maxlength="6" placeholder="ABC123" style="flex:1;text-transform:uppercase" />
|
||||
<button id="s-sync-pair" class="btn-primary" style="padding:6px 12px;font-size:13px">Привязать</button>
|
||||
</div>
|
||||
</div>
|
||||
<button id="s-sync-register" class="btn-secondary full-width" style="margin-top:8px;font-size:13px">Создать новый аккаунт</button>
|
||||
</div>
|
||||
<div id="s-sync-info" style="padding:0 14px;display:${Sync.userId ? "" : "none"}">
|
||||
<button id="s-sync-show-code" class="btn-secondary full-width" style="margin-top:8px;font-size:13px">Показать код для привязки</button>
|
||||
<div id="s-sync-code-display" style="display:none;margin-top:8px;text-align:center;font-size:28px;font-weight:bold;letter-spacing:4px;color:var(--primary)"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<div class="settings-section-title">О приложении</div>
|
||||
<div class="settings-item" id="s-about">
|
||||
|
|
@ -4599,6 +4716,57 @@ async function renderSettings(container) {
|
|||
};
|
||||
}
|
||||
|
||||
// Sync handlers
|
||||
const syncNowBtn = container.querySelector("#s-sync-now");
|
||||
if (syncNowBtn) {
|
||||
syncNowBtn.onclick = async () => {
|
||||
if (!Sync.userId) {
|
||||
// Show setup
|
||||
container.querySelector("#s-sync-setup").style.display = "";
|
||||
return;
|
||||
}
|
||||
syncNowBtn.textContent = "...";
|
||||
syncNowBtn.disabled = true;
|
||||
const r = await Sync.now();
|
||||
container.querySelector("#s-sync-desc").textContent = `Отправлено: ${r.pushed}, получено: ${r.pulled}`;
|
||||
syncNowBtn.textContent = "Синхр.";
|
||||
syncNowBtn.disabled = false;
|
||||
};
|
||||
}
|
||||
container.querySelector("#s-sync-register")?.addEventListener("click", async () => {
|
||||
try {
|
||||
const code = await Sync.register();
|
||||
container.querySelector("#s-sync-status").textContent = "Подключено";
|
||||
container.querySelector("#s-sync-setup").style.display = "none";
|
||||
container.querySelector("#s-sync-info").style.display = "";
|
||||
container.querySelector("#s-sync-code-display").style.display = "";
|
||||
container.querySelector("#s-sync-code-display").textContent = code;
|
||||
syncNowBtn.textContent = "Синхр.";
|
||||
showToast("Аккаунт создан. Код: " + code);
|
||||
} catch (e) { showToast("Ошибка: " + e.message); }
|
||||
});
|
||||
container.querySelector("#s-sync-pair")?.addEventListener("click", async () => {
|
||||
const code = container.querySelector("#s-sync-code").value.trim().toUpperCase();
|
||||
if (code.length !== 6) { showToast("Введите 6-символьный код"); return; }
|
||||
try {
|
||||
await Sync.pair(code);
|
||||
container.querySelector("#s-sync-status").textContent = "Подключено";
|
||||
container.querySelector("#s-sync-setup").style.display = "none";
|
||||
container.querySelector("#s-sync-info").style.display = "";
|
||||
syncNowBtn.textContent = "Синхр.";
|
||||
showToast("Устройство привязано!");
|
||||
await Sync.now();
|
||||
} catch (e) { showToast("Ошибка: " + e.message); }
|
||||
});
|
||||
container.querySelector("#s-sync-show-code")?.addEventListener("click", async () => {
|
||||
try {
|
||||
const code = await Sync.newCode();
|
||||
const el = container.querySelector("#s-sync-code-display");
|
||||
el.style.display = "";
|
||||
el.textContent = code;
|
||||
} catch (e) { showToast("Ошибка: " + e.message); }
|
||||
});
|
||||
|
||||
// App version info + update check
|
||||
try {
|
||||
const info = await window.__TAURI__.core.invoke("get_app_info");
|
||||
|
|
|
|||
1936
frontend/lib/leaflet-rotate.js
Normal file
1936
frontend/lib/leaflet-rotate.js
Normal file
File diff suppressed because it is too large
Load diff
111
src-tauri/Cargo.lock
generated
111
src-tauri/Cargo.lock
generated
|
|
@ -139,7 +139,7 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
|||
|
||||
[[package]]
|
||||
name = "baldav"
|
||||
version = "0.1.244"
|
||||
version = "0.1.262"
|
||||
dependencies = [
|
||||
"btleplug",
|
||||
"lazy_static",
|
||||
|
|
@ -151,6 +151,7 @@ dependencies = [
|
|||
"tauri-plugin-sql",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"ureq",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
|
|
@ -3198,6 +3199,20 @@ dependencies = [
|
|||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"getrandom 0.2.17",
|
||||
"libc",
|
||||
"untrusted",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rkyv"
|
||||
version = "0.7.46"
|
||||
|
|
@ -3306,6 +3321,41 @@ dependencies = [
|
|||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9"
|
||||
dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.103.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.22"
|
||||
|
|
@ -4893,6 +4943,41 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "ureq"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dea7109cdcd5864d4eeb1b58a1648dc9bf520360d7af16ec26d0a9354bafcfc0"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"flate2",
|
||||
"log",
|
||||
"percent-encoding",
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"ureq-proto",
|
||||
"utf8-zero",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ureq-proto"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"http",
|
||||
"httparse",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.8"
|
||||
|
|
@ -4924,6 +5009,12 @@ version = "0.7.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||
|
||||
[[package]]
|
||||
name = "utf8-zero"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e"
|
||||
|
||||
[[package]]
|
||||
name = "utf8_iter"
|
||||
version = "1.0.4"
|
||||
|
|
@ -5198,6 +5289,15 @@ dependencies = [
|
|||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webview2-com"
|
||||
version = "0.38.2"
|
||||
|
|
@ -5447,6 +5547,15 @@ dependencies = [
|
|||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "baldav"
|
||||
version = "0.1.244"
|
||||
version = "0.1.262"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
|
@ -18,6 +18,7 @@ serde_json = "1"
|
|||
rusqlite = { version = "0.31", features = ["bundled"] }
|
||||
|
||||
lazy_static = "1"
|
||||
ureq = "3"
|
||||
|
||||
[target.'cfg(not(target_os = "android"))'.dependencies]
|
||||
btleplug = { version = "0.11", features = ["serde"] }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"$schema": "https://raw.githubusercontent.com/nicegui/tauri-v2/refs/heads/main/tooling/cli/schema.json",
|
||||
"productName": "BalDav",
|
||||
"version": "0.1.244",
|
||||
"version": "0.1.262",
|
||||
"identifier": "dev.baldav.app",
|
||||
"build": {
|
||||
"frontendDist": "../frontend"
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
"app": {
|
||||
"withGlobalTauri": true,
|
||||
"security": {
|
||||
"csp": "default-src 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self' https://4aiman.top https://*.tile.openstreetmap.org https://*.tile.thunderforest.com https://api.open-meteo.com; img-src 'self' blob: data: https://*.tile.openstreetmap.org https://*.tile.thunderforest.com"
|
||||
"csp": "default-src 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self' https://4aiman.top https://*.tile.openstreetmap.org https://*.tile.thunderforest.com https://api.open-meteo.com http://192.168.1.1:88; img-src 'self' blob: data: https://*.tile.openstreetmap.org https://*.tile.thunderforest.com"
|
||||
},
|
||||
"windows": [
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue