/** * VideoCharm - Main Application * Core application logic and initialization */ const App = (function() { // DOM Elements let loadingScreen; let toast; let navItems; let screens; let historyList; let favoritesList; let emptyHistory; let emptyFavorites; let clearHistoryBtn; let clearFavoritesBtn; let likesCount; let favoritesCount; let viewsCount; let swipeIndicator; let profileActions; /** * Initialize the application */ function init() { // Get DOM elements loadingScreen = document.getElementById('loadingScreen'); toast = document.getElementById('toast'); navItems = document.querySelectorAll('.nav-item'); screens = document.querySelectorAll('.screen'); historyList = document.getElementById('historyList'); favoritesList = document.getElementById('favoritesList'); emptyHistory = document.getElementById('emptyHistory'); emptyFavorites = document.getElementById('emptyFavorites'); clearHistoryBtn = document.getElementById('clearHistoryBtn'); clearFavoritesBtn = document.getElementById('clearFavoritesBtn'); likesCount = document.getElementById('likesCount'); favoritesCount = document.getElementById('favoritesCount'); viewsCount = document.getElementById('viewsCount'); swipeIndicator = document.getElementById('swipeIndicator'); profileActions = document.querySelectorAll('.action-row'); // Initialize storage StorageManager.init(); // Initialize video player VideoPlayer.init(); // Set up event listeners setupEventListeners(); // Load initial video and start playing immediately VideoPlayer.loadVideos(1, true).then(() => { // Show swipe indicator after initial load setTimeout(() => { swipeIndicator.style.display = 'flex'; setTimeout(() => { swipeIndicator.style.opacity = '0'; setTimeout(() => { swipeIndicator.style.display = 'none'; }, 500); }, 3000); }, 500); // Load more videos in background for smooth experience setTimeout(() => { VideoPlayer.loadVideos(3, false); }, 1000); }); // Update statistics updateStats(); } /** * Set up event listeners */ function setupEventListeners() { // Navigation navItems.forEach(item => { item.addEventListener('click', function() { const targetScreen = this.getAttribute('data-screen'); switchToScreen(targetScreen); }); }); // Clear history button clearHistoryBtn.addEventListener('click', function() { if (confirm('确定要清空所有观看历史吗?')) { StorageManager.clearHistory(); loadHistoryList(); updateStats(); showToast('历史记录已清空'); } }); // Clear favorites button clearFavoritesBtn.addEventListener('click', function() { if (confirm('确定要清空所有收藏吗?')) { StorageManager.clearFavorites(); loadFavoritesList(); updateStats(); showToast('收藏夹已清空'); } }); // Profile actions profileActions.forEach(action => { action.addEventListener('click', function() { const actionType = this.getAttribute('data-action'); handleProfileAction(actionType); }); }); // Comment button document.getElementById('commentButton').addEventListener('click', function() { showToast('评论功能开发中,敬请期待!'); }); // Share button document.getElementById('shareButton').addEventListener('click', function() { showToast('分享功能开发中,敬请期待!'); }); } /** * Switch to a different screen * @param {String} screenId ID of screen to switch to */ function switchToScreen(screenId) { // Update navigation navItems.forEach(item => { item.classList.remove('active'); if (item.getAttribute('data-screen') === screenId) { item.classList.add('active'); } }); // Update screens screens.forEach(screen => { screen.classList.remove('active'); if (screen.id === screenId) { screen.classList.add('active'); } }); // Handle specific screen actions if (screenId === 'historyScreen') { loadHistoryList(); } else if (screenId === 'favoritesScreen') { loadFavoritesList(); } } /** * Load history list from storage */ function loadHistoryList() { const history = StorageManager.getHistory(); // Clear list historyList.innerHTML = ''; if (history.length === 0) { // Show empty state emptyHistory.style.display = 'flex'; historyList.style.display = 'none'; } else { // Hide empty state emptyHistory.style.display = 'none'; historyList.style.display = 'grid'; // Add history items history.forEach(item => { const videoItem = createVideoListItem(item, 'history'); historyList.appendChild(videoItem); }); } } /** * Load favorites list from storage */ function loadFavoritesList() { const favorites = StorageManager.getFavorites(); // Clear list favoritesList.innerHTML = ''; if (favorites.length === 0) { // Show empty state emptyFavorites.style.display = 'flex'; favoritesList.style.display = 'none'; } else { // Hide empty state emptyFavorites.style.display = 'none'; favoritesList.style.display = 'grid'; // Add favorite items favorites.forEach(item => { const videoItem = createVideoListItem(item, 'favorite'); favoritesList.appendChild(videoItem); }); } } /** * Create a video list item for history or favorites * @param {Object} videoData Video data * @param {String} type Item type ('history' or 'favorite') * @returns {HTMLElement} Video list item element */ function createVideoListItem(videoData, type) { const videoItem = document.createElement('div'); videoItem.className = 'video-item'; videoItem.setAttribute('data-id', videoData.id); // Use thumbnail if available, otherwise use placeholder let thumbnailUrl; if (videoData.thumbnail) { thumbnailUrl = videoData.thumbnail; } else { thumbnailUrl = generatePlaceholderImage(videoData.id); } videoItem.innerHTML = `
${videoData.title}
${formatDuration(videoData.duration)}
${videoData.title}
${formatTimeAgo(videoData.timestamp)}
`; // Add click event videoItem.addEventListener('click', function() { VideoPlayer.playVideoFromLibrary(videoData); showToast(`正在播放${type === 'favorite' ? '收藏' : '历史'}视频`); }); return videoItem; } /** * Update profile statistics */ function updateStats() { const likes = StorageManager.getLikes().length; const favorites = StorageManager.getFavorites().length; const views = StorageManager.getViews(); likesCount.textContent = likes; favoritesCount.textContent = favorites; viewsCount.textContent = views; } /** * Handle profile action * @param {String} actionType Type of action */ function handleProfileAction(actionType) { switch (actionType) { case 'settings': case 'preferences': case 'about': showToast(`${actionType} 功能开发中,敬请期待`); break; case 'logout': if (confirm('确定要退出登录吗?')) { showToast('退出登录成功'); } break; } } /** * Show loading screen */ function showLoading() { loadingScreen.style.display = 'flex'; } /** * Hide loading screen */ function hideLoading() { loadingScreen.style.display = 'none'; } /** * Show toast message * @param {String} message Message to show * @param {Number} duration Duration in ms */ function showToast(message, duration = 2000) { toast.textContent = message; toast.classList.add('show'); setTimeout(() => { toast.classList.remove('show'); }, duration); } /** * Format duration in seconds to MM:SS * @param {Number} seconds Duration in seconds * @returns {String} Formatted duration */ function formatDuration(seconds) { if (!seconds) return '00:00'; const minutes = Math.floor(seconds / 60); const remainingSeconds = Math.floor(seconds % 60); return `${minutes < 10 ? '0' : ''}${minutes}:${remainingSeconds < 10 ? '0' : ''}${remainingSeconds}`; } /** * Format timestamp to relative time * @param {Number} timestamp Timestamp * @returns {String} Formatted time */ function formatTimeAgo(timestamp) { const now = new Date().getTime(); const diff = now - timestamp; // Less than 1 minute if (diff < 60 * 1000) { return "刚刚"; } // Less than 1 hour if (diff < 60 * 60 * 1000) { return Math.floor(diff / (60 * 1000)) + "分钟前"; } // Less than 24 hours if (diff < 24 * 60 * 60 * 1000) { return Math.floor(diff / (60 * 60 * 1000)) + "小时前"; } // Less than 7 days if (diff < 7 * 24 * 60 * 60 * 1000) { return Math.floor(diff / (24 * 60 * 60 * 1000)) + "天前"; } // Format as date const date = new Date(timestamp); return `${date.getMonth() + 1}月${date.getDate()}日`; } /** * Generate consistent placeholder image URL based on ID * @param {String} id Item ID for consistent image generation * @returns {String} Image URL */ function generatePlaceholderImage(id) { // Generate a deterministic number from the string ID let hash = 0; if (id && id.length > 0) { for (let i = 0; i < id.length; i++) { hash = ((hash << 5) - hash) + id.charCodeAt(i); hash |= 0; // Convert to 32bit integer } } const randomId = Math.abs(hash % 1000); // Ensure positive return `https://picsum.photos/seed/${randomId}/300/500`; } // Public API return { init: init, showLoading: showLoading, hideLoading: hideLoading, showToast: showToast, switchToScreen: switchToScreen, updateStats: updateStats }; })(); // Initialize application when DOM is loaded document.addEventListener('DOMContentLoaded', function() { App.init(); });