Compare commits
No commits in common. "main" and "v0.0.15" have entirely different histories.
7 changed files with 447 additions and 686 deletions
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "has",
|
||||
"private": true,
|
||||
"version": "0.0.19",
|
||||
"version": "0.0.15",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "has"
|
||||
version = "0.0.19"
|
||||
version = "0.0.15"
|
||||
description = "has"
|
||||
authors = ["autli"]
|
||||
edition = "2024"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "has",
|
||||
"version": "0.0.19",
|
||||
"version": "0.0.15",
|
||||
"identifier": "com.has.tauri-app",
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
|
|
|
|||
31
src/App.tsx
31
src/App.tsx
|
|
@ -27,6 +27,8 @@ const isTauri = () => {
|
|||
// Helper for Smart TV / Android TV detection
|
||||
const detectTvEnvironment = (): boolean => {
|
||||
if (typeof window === "undefined") return false;
|
||||
const saved = localStorage.getItem("has_tv_mode");
|
||||
if (saved !== null) return saved === "true";
|
||||
const ua = (navigator.userAgent || "").toLowerCase();
|
||||
const isTvUa =
|
||||
ua.includes("android tv") ||
|
||||
|
|
@ -53,17 +55,6 @@ const detectTvEnvironment = (): boolean => {
|
|||
const isAndroid = ua.includes("android");
|
||||
const noTouch = !("ontouchstart" in window) && navigator.maxTouchPoints === 0;
|
||||
if (isAndroid && noTouch) return true;
|
||||
|
||||
// On pure desktop (macOS / Windows / Desktop Linux), default to desktop PC mode
|
||||
const isDesktop =
|
||||
(ua.includes("windows nt") || ua.includes("macintosh") || (ua.includes("linux") && !ua.includes("android"))) &&
|
||||
!isTvUa;
|
||||
if (isDesktop) {
|
||||
return localStorage.getItem("has_tv_mode_manual") === "true";
|
||||
}
|
||||
|
||||
const saved = localStorage.getItem("has_tv_mode");
|
||||
if (saved !== null) return saved === "true";
|
||||
return false;
|
||||
};
|
||||
|
||||
|
|
@ -153,6 +144,21 @@ export default function App() {
|
|||
checkDatabase();
|
||||
}, [isTvEnvironment]);
|
||||
|
||||
// Activate TV mode immediately upon any remote control key press
|
||||
useEffect(() => {
|
||||
const handleRemoteKey = (e: KeyboardEvent) => {
|
||||
const isRemoteKey =
|
||||
[19, 20, 21, 22, 23, 4, 82, 85, 179].includes(e.keyCode) ||
|
||||
["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key);
|
||||
if (isRemoteKey && !isTvEnvironment) {
|
||||
setIsTvEnvironment(true);
|
||||
localStorage.setItem("has_tv_mode", "true");
|
||||
}
|
||||
};
|
||||
window.addEventListener("keydown", handleRemoteKey);
|
||||
return () => window.removeEventListener("keydown", handleRemoteKey);
|
||||
}, [isTvEnvironment]);
|
||||
|
||||
// Countdown timer for OTP re-send in resetStage 2
|
||||
useEffect(() => {
|
||||
if (resetStage !== 2) return;
|
||||
|
|
@ -519,7 +525,6 @@ export default function App() {
|
|||
dbInfo={dbInfo}
|
||||
dbStatus={dbStatus}
|
||||
onLogout={handleLogout}
|
||||
isTvEnvironment={isTvEnvironment}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
@ -537,7 +542,6 @@ export default function App() {
|
|||
onSwitchToDesktop={() => {
|
||||
setIsTvEnvironment(false);
|
||||
localStorage.setItem("has_tv_mode", "false");
|
||||
localStorage.setItem("has_tv_mode_manual", "false");
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
|
|
@ -808,7 +812,6 @@ export default function App() {
|
|||
onClick={() => {
|
||||
setIsTvEnvironment(true);
|
||||
localStorage.setItem("has_tv_mode", "true");
|
||||
localStorage.setItem("has_tv_mode_manual", "true");
|
||||
}}
|
||||
title="Перейти в режим Android TV (выбор профилей)"
|
||||
style={{
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ interface UpdaterBannerProps {
|
|||
// Helper for Smart TV / Android TV detection
|
||||
const detectTvEnvironment = (): boolean => {
|
||||
if (typeof window === "undefined") return false;
|
||||
const saved = localStorage.getItem("has_tv_mode");
|
||||
if (saved !== null) return saved === "true";
|
||||
const ua = (navigator.userAgent || "").toLowerCase();
|
||||
const isTvUa =
|
||||
ua.includes("android tv") ||
|
||||
|
|
@ -48,17 +50,6 @@ const detectTvEnvironment = (): boolean => {
|
|||
const isAndroid = ua.includes("android");
|
||||
const noTouch = !("ontouchstart" in window) && navigator.maxTouchPoints === 0;
|
||||
if (isAndroid && noTouch) return true;
|
||||
|
||||
// On pure desktop (macOS / Windows / Desktop Linux), default to desktop PC mode
|
||||
const isDesktop =
|
||||
(ua.includes("windows nt") || ua.includes("macintosh") || (ua.includes("linux") && !ua.includes("android"))) &&
|
||||
!isTvUa;
|
||||
if (isDesktop) {
|
||||
return localStorage.getItem("has_tv_mode_manual") === "true";
|
||||
}
|
||||
|
||||
const saved = localStorage.getItem("has_tv_mode");
|
||||
if (saved !== null) return saved === "true";
|
||||
return false;
|
||||
};
|
||||
|
||||
|
|
@ -97,7 +88,7 @@ const isNewerSemver = (remote: string, current: string): boolean => {
|
|||
|
||||
export function UpdaterBanner({ isTvEnvironment }: UpdaterBannerProps = {}) {
|
||||
const [isTv, setIsTv] = useState<boolean>(() => isTvEnvironment ?? detectTvEnvironment());
|
||||
const [currentAppVersion, setCurrentAppVersion] = useState<string>("0.0.19");
|
||||
const [currentAppVersion, setCurrentAppVersion] = useState<string>("0.0.15");
|
||||
const [updateAvailable, setUpdateAvailable] = useState(false);
|
||||
const [updateInfo, setUpdateInfo] = useState<UpdateInfo | null>(null);
|
||||
const [downloading, setDownloading] = useState(false);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -55,7 +55,6 @@ interface DashboardProps {
|
|||
dbInfo: SafeDbInfo | null;
|
||||
dbStatus: DbStatus | null;
|
||||
onLogout: () => void;
|
||||
isTvEnvironment?: boolean;
|
||||
}
|
||||
|
||||
type NavTab = "cinema" | "home" | "users" | "settings" | "profile" | "help";
|
||||
|
|
@ -63,6 +62,8 @@ type NavTab = "cinema" | "home" | "users" | "settings" | "profile" | "help";
|
|||
// Helper for Smart TV / Android TV detection
|
||||
const detectTvEnvironment = (): boolean => {
|
||||
if (typeof window === "undefined") return false;
|
||||
const saved = localStorage.getItem("has_tv_mode");
|
||||
if (saved !== null) return saved === "true";
|
||||
const ua = (navigator.userAgent || "").toLowerCase();
|
||||
const isTvUa =
|
||||
ua.includes("android tv") ||
|
||||
|
|
@ -89,17 +90,6 @@ const detectTvEnvironment = (): boolean => {
|
|||
const isAndroid = ua.includes("android");
|
||||
const noTouch = !("ontouchstart" in window) && navigator.maxTouchPoints === 0;
|
||||
if (isAndroid && noTouch) return true;
|
||||
|
||||
// On pure desktop (macOS / Windows / Desktop Linux), default to desktop PC mode
|
||||
const isDesktop =
|
||||
(ua.includes("windows nt") || ua.includes("macintosh") || (ua.includes("linux") && !ua.includes("android"))) &&
|
||||
!isTvUa;
|
||||
if (isDesktop) {
|
||||
return localStorage.getItem("has_tv_mode_manual") === "true";
|
||||
}
|
||||
|
||||
const saved = localStorage.getItem("has_tv_mode");
|
||||
if (saved !== null) return saved === "true";
|
||||
return false;
|
||||
};
|
||||
|
||||
|
|
@ -108,23 +98,13 @@ export default function Dashboard({
|
|||
dbInfo,
|
||||
dbStatus,
|
||||
onLogout,
|
||||
isTvEnvironment: propIsTv,
|
||||
}: DashboardProps) {
|
||||
const [currentUser, setCurrentUser] = useState<UserDto>(user);
|
||||
useEffect(() => {
|
||||
setCurrentUser(user);
|
||||
}, [user]);
|
||||
|
||||
const [isTvEnvironment, setIsTvEnvironment] = useState<boolean>(() => {
|
||||
return propIsTv !== undefined ? propIsTv : detectTvEnvironment();
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (propIsTv !== undefined && propIsTv !== isTvEnvironment) {
|
||||
setIsTvEnvironment(propIsTv);
|
||||
}
|
||||
}, [propIsTv, isTvEnvironment]);
|
||||
|
||||
const [isTvEnvironment, setIsTvEnvironment] = useState<boolean>(detectTvEnvironment);
|
||||
const [activeTab, setActiveTab] = useState<NavTab>("cinema");
|
||||
const [serverUsers, setServerUsers] = useState<ServerUserDto[]>([]);
|
||||
const [loadingUsers, setLoadingUsers] = useState(false);
|
||||
|
|
@ -133,6 +113,21 @@ export default function Dashboard({
|
|||
});
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||
|
||||
// Dynamic D-Pad Remote Control Key Listener (Auto-detects TV when user presses remote buttons)
|
||||
useEffect(() => {
|
||||
const handleRemoteDpadKey = (e: KeyboardEvent) => {
|
||||
const isRemoteKey =
|
||||
[19, 20, 21, 22, 23, 4, 82, 85, 179].includes(e.keyCode) ||
|
||||
["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key);
|
||||
if (isRemoteKey && !isTvEnvironment) {
|
||||
setIsTvEnvironment(true);
|
||||
localStorage.setItem("has_tv_mode", "true");
|
||||
}
|
||||
};
|
||||
window.addEventListener("keydown", handleRemoteDpadKey);
|
||||
return () => window.removeEventListener("keydown", handleRemoteDpadKey);
|
||||
}, [isTvEnvironment]);
|
||||
|
||||
const handleNavClick = (tab: NavTab) => {
|
||||
setActiveTab(tab);
|
||||
setMobileMenuOpen(false);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue