Code edit (5 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Uncaught ReferenceError: categoryBtnsBottomY is not defined' in or related to this line: 'confirmBtn.y = categoryBtnsBottomY + 150;' Line Number: 1572
Code edit (1 edits merged)
Please save this source code
User prompt
There are 3 major issues remaining. Please read carefully and fix them all: --- 🛠️ 1. EDIT PANEL ISSUE: When the user clicks the "Edit" button: - DO NOT open the Publish panel immediately. - Just mark the video as edited (e.g., `state = "edited"`), close the Edit panel. - Enable the YouTube Studio App icon so the player can click it manually. - Only when the player clicks the YouTube Studio App, then the Publish panel should open. Right now, this behavior is wrong — the game skips the user action. --- 🛠️ 2. PUBLISH BUT NO VIEWS ISSUE: When the player clicks "Publish Now": - The video should be added to the YouTube video list ✔️ - AND it must also be added to the system that increases views over time. - Currently, published videos are not gaining views. This breaks core game logic. - Make sure the published video is added to the "view loop" mechanic properly. --- 🛠️ 3. RECORD APP DOESN’T RESET: After a video is published: - The Record App should become clickable (enabled) again. - The system must allow the player to record a new video. - Reset the state machine so the full cycle can repeat again. --- Make sure all 3 are fully functional before returning confirmation. Log the video state at each step to verify progress. Fix all of this now — these are critical to making the game playable.
User prompt
The Edit Panel is now opening, but there is a logic issue: When the user clicks the "Edit" button: - It should NOT immediately open the YouTube Studio (Publish) Panel. - Instead, the Edit panel should simply CLOSE. - Then, the user must manually click the "YouTube Studio App" icon to open the Publish panel. Fix the logic so that: 1. Clicking the Edit button finishes editing and closes the Edit panel. 2. After editing is done, the YouTube Studio app icon becomes clickable (enabled). 3. Only when the user clicks the YouTube Studio app icon, the Publish panel should open. Do not automatically open the publish panel. Let the player control the flow step-by-step.
User prompt
The Edit Panel still does not open. Please do the following: 1. Log the latest video object after recording. I need to see if state === "recorded" and finished === false. 2. Check the logic that opens the Edit Panel. Print why it's not opening. If state or finished condition is not met, log it. 3. Fix the condition and make sure that Edit Panel opens IMMEDIATELY after clicking the Editing App, IF the latest video has state "recorded" and finished false. Also: Prevent duplicate videos in uploadedVideos. Ensure one video at a time. Do not mark this as fixed until the Edit Panel visibly opens and logic confirms the state conditions are satisfied.
User prompt
The edit panel still doesn't open. I checked your logic and found that the video object never has `state = "recorded"` after recording is finished. Please make sure that after recording, the video object is added to `window.uploadedVideos` with `state: "recorded"` and `finished: false`. Only then the edit panel logic will work. Fix this first.
User prompt
STOP. Please fix the core issue. Right now the app flow is broken. The panels and apps (Record, Edit, Studio) must follow a strict UI state logic. Let me explain it as a UI STATE MACHINE. Please implement exactly this: INITIAL STATE: - Record App: ENABLED - Editing App: DISABLED - YouTube Studio App: DISABLED WHEN USER CLICKS RECORD APP: - Show the Record Video Panel - After recording is finished: - Disable Record App - Enable Editing App WHEN USER CLICKS EDITING APP: - Show Edit Video Panel - After editing is finished: - Disable Editing App - Enable YouTube Studio App WHEN USER CLICKS YOUTUBE STUDIO APP: - Show the Publish Panel - After publishing: - Add the video to the video list in YouTube app - Enable Record App again - Disable YouTube Studio App RULES: - Only ONE video in progress at a time - Do NOT allow Record App to be clicked again until the previous video is published - Do NOT enable YouTube Studio before Edit step is done - Reset the full state after publishing the video FIX THIS NOW. NOTHING should happen outside this logic. UI state must strictly follow this flow.
User prompt
You're misunderstanding the video creation flow. Let me explain it again, step-by-step. Please follow this exact logic: 1. When the user clicks the "Record App", a Record Video Panel should appear. 2. In the Record Video Panel, the user completes the recording. Once recording is done: - The Record App should be disabled (grayed out). - The Editing App should become enabled (clickable). 3. When the user clicks the "Editing App", the Edit Video Panel should appear. - After editing is complete, the Editing App should be disabled. - The YouTube Studio App should now be enabled (clickable). 4. When the user clicks the "YouTube Studio App", a Publish Panel should appear. - The user can now publish the video. - After publishing: - The video should appear in the YouTube video list. - The YouTube Studio App should be disabled. - The Record App should be enabled again to start a new video cycle. !!️ Rules: - Never allow the user to skip a step. - Never enable YouTube Studio before editing is complete. - Never allow creating another video before the current one is published. - Only ONE video should be in progress at any time. - Reset the flow after each publishing. Fix the logic and UI behavior accordingly. This is a critical bug. Don't make any assumptions. Follow the instructions exactly.
User prompt
I need a step-by-step logic flow for my game. Please follow these rules and structure for the video creation process in my game: 1. When the user clicks the "Record App", it should open the Record Video Panel. 2. After recording is finished, the user should click on the "Editing App". This should open the Edit Video Panel. 3. Once the user finishes editing, the "YouTube Studio App" should become clickable (active). 4. Clicking the "YouTube Studio App" should open a Publish Panel, where the user can publish the edited video. 5. After publishing, the video should be added to the "YouTube App" video list and start gaining views over time. 6. Once a video is published, the user should be able to create a new video by clicking on the "Record App" again. 7. While a video is still unpublished (not edited or not published), the "Record App" should be disabled to prevent making another video before finishing the current one. 8. Each panel (Record, Edit, Publish) should only appear when the previous one is completed. Make sure all buttons and UI panels only become active when the previous step is completed. Follow this strict order and update the video status across the system properly. Let me know if any part of this logic is unclear.
User prompt
video çektikten sonraki aşamaya hala geçemiyoruz edit paneli açılmıyor
User prompt
hala düzelmedi video çekmeden sonrasına geçemiyorum hala
User prompt
hala düzelmedi (video çektikten sonra uygulama listesindeki editing uygulamasına tıkladığımda edit panel açılmıyor bu aşamada kaldık)
User prompt
hala düzelmedi (şuanki sorun video çektikten sonra edit paneli açılmıyor)
User prompt
hala düzelmedi
User prompt
hala düzelmedi
User prompt
hala düzelmedi
User prompt
oyunda bir video çekildikten sonra o videonun editlenmesini ve publishlenmesini sağla ve bunları record uygulamasıyla - editing uygulamasıyla - youtube studio uygulamasıyla yapılmasını sağla. şuan herhangi bir şekilde bu hiyerarşiyi yönetemedim ve sana demek istediğim şeyi anlatamıyorum oyun devam etmiyor
User prompt
bir video yüklendikten sonra edit uygulamasına basıldığında edit ekranının açılmasını sağla.
User prompt
bir video çekildikten sonra edit uygulamasına tıkladığımda record ikon büyüyüp küçülüyor ve ekrana edit paneli gelmiyor bunu düzelt edit ekranının açılması gerek ve video çekme ikonununda bir değişiklik olmaması gerek.
User prompt
record uygulamasında açılan ekranda record butonuna basılınca editing uygulamasına tıklanınca edit ekranının açılmasını sağla.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Energy bar class var EnergyBar = Container.expand(function () { var self = Container.call(this); self.bg = self.attachAsset('energyBarBg', { anchorX: 0, anchorY: 0.5 }); self.fill = self.attachAsset('energyBarFill', { anchorX: 0, anchorY: 0.5 }); self.fill.x = 0; self.bg.x = 0; self.bg.y = 0; self.fill.y = 0; self.maxWidth = self.fill.width; self.set = function (ratio) { if (ratio < 0) { ratio = 0; } if (ratio > 1) { ratio = 1; } self.fill.width = self.maxWidth * ratio; }; return self; }); // --- Finance Panel Class --- var FinancePanel = Container.expand(function () { var self = Container.call(this); // Yellow background, same size/position as computerscreen self.bg = self.attachAsset('upgradeBtn', { anchorX: 0.5, anchorY: 0.5, x: computerScreen.x, y: computerScreen.y }); self.bg.width = computerScreen.width; self.bg.height = computerScreen.height; self.bg.x = computerScreen.x; self.bg.y = computerScreen.y; self.bg.alpha = 0.98; self.addChild(self.bg); // Money text (white, large, centered) self.moneyTxt = new Text2("", { size: 120, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); self.moneyTxt.anchor.set(0.5, 0); // Place at the very top inside the finance panel, with a margin self.moneyTxt.x = computerScreen.x; self.moneyTxt.y = computerScreen.y - computerScreen.height / 2 + 60; self.addChild(self.moneyTxt); // Helper to update money display self.updateMoney = function () { // Truncate to 2 decimals var moneyDisplay = Math.floor(money * 100) / 100; self.moneyTxt.setText("$" + formatNumber(moneyDisplay)); // --- Daily Money Flow Graph (like statistics panel) --- // Remove previous stats label/graph if exists if (self.moneyStatsTxt) { try { self.moneyStatsTxt.destroy(); } catch (e) {} self.moneyStatsTxt = null; } if (self.moneyStatsGraphNodes && self.moneyStatsGraphNodes.length) { for (var i = 0; i < self.moneyStatsGraphNodes.length; i++) { try { self.moneyStatsGraphNodes[i].destroy(); } catch (e) {} } self.moneyStatsGraphNodes = []; } // Show daily money flow as a graph, like in statistics, but here: end-of-day money per day if (typeof statsMoneyPerDay !== "undefined" && statsMoneyPerDay.length > 0) { // Only show up to last 7 days, most recent last var maxDays = 7; var startIdx = Math.max(0, statsMoneyPerDay.length - maxDays); var data = []; for (var i = startIdx; i < statsMoneyPerDay.length; i++) { // Always show 2 decimals for money var dayMoney = Math.floor(statsMoneyPerDay[i] * 100) / 100; data.push(dayMoney); } // Graph area sizing var graphW = self.bg.width - 180; var graphH = 260; var graphStartX = computerScreen.x - graphW / 2; var graphStartY = self.moneyTxt.y + self.moneyTxt.height + 60; // Draw card background var cardBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0, x: computerScreen.x, y: graphStartY }); cardBg.width = graphW + 60; cardBg.height = graphH + 60; cardBg.alpha = 0.93; self.addChild(cardBg); // Draw label var labelTxt = new Text2("Günlük Para Akışı", { size: 54, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 6, dropShadowDistance: 2 }); labelTxt.anchor.set(0, 0.5); labelTxt.x = graphStartX + 20; labelTxt.y = graphStartY + 36; self.addChild(labelTxt); // Find max value for scaling var maxVal = 1; for (var i = 0; i < data.length; i++) { if (data[i] > maxVal) maxVal = data[i]; } // Draw line graph: connect points with rectangles (simulate lines) var prevX = null, prevY = null; self.moneyStatsGraphNodes = [cardBg, labelTxt]; for (var i = 0; i < data.length; i++) { var x0 = graphStartX + i / Math.max(1, data.length - 1) * graphW; var y0 = graphStartY + 80 + graphH - data[i] / maxVal * (graphH - 30); // Draw a small circle at each data point var point = LK.getAsset('loadingbarfull', { anchorX: 0.5, anchorY: 0.5, x: x0, y: y0 }); point.width = 18; point.height = 18; point.tint = 0xfa4b00; self.addChild(point); self.moneyStatsGraphNodes.push(point); // Draw value label for each day var displayValue = Math.floor(data[i] * 100) / 100; displayValue = displayValue.toFixed(2); var valTxt = new Text2("" + displayValue, { size: 36, fill: "#fff" }); valTxt.anchor.set(0.5, 1); valTxt.x = x0; valTxt.y = y0 - 8; self.addChild(valTxt); self.moneyStatsGraphNodes.push(valTxt); // Draw a "line" between previous and current point using a thin rectangle if (prevX !== null && prevY !== null) { var dx = x0 - prevX; var dy = y0 - prevY; var dist = Math.sqrt(dx * dx + dy * dy); var angle = Math.atan2(dy, dx); var line = LK.getAsset('loadingbarfull', { anchorX: 0, anchorY: 0.5, x: prevX, y: prevY }); line.width = dist; line.height = 8; line.tint = 0xfa4b00; line.rotation = angle; self.addChild(line); self.moneyStatsGraphNodes.push(line); } prevX = x0; prevY = y0; } } }; // Update on creation self.updateMoney(); return self; }); // Global variable to track finance panel instance // Button class for all clickable actions var GameButton = Container.expand(function () { var self = Container.call(this); self.bg = null; self.label = null; self.action = null; self.enabled = true; self.setButton = function (assetId, labelText, color, width, height) { self.bg = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); self.bg.width = width; self.bg.height = height; // Modern look: more pronounced rounded corners and soft drop shadow self.bg.cornerRadius = Math.min(width, height) * 0.28; self.bg.shadow = { color: 0x111111, blur: 36, offsetX: 0, offsetY: 16, alpha: 0.32 }; self.label = new Text2(labelText, { size: 80, fill: color, font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 12, dropShadowDistance: 2 }); self.label.anchor.set(0.5, 0.5); self.addChild(self.label); }; self.setEnabled = function (val) { self.enabled = val; if (self.bg) { self.bg.alpha = val ? 1 : 0.4; } }; self.down = function (x, y, obj) { if (!self.enabled) { return; } if (typeof self.action === 'function') { self.action(); } }; return self; }); // VideoListItem: displays a video in the list with title, state, and stats var VideoListItem = Container.expand(function () { var self = Container.call(this); self.bg = self.attachAsset('loadingbarempty', { anchorX: 0, anchorY: 0.5 }); self.bg.width = 1200; self.bg.height = 120; self.bg.alpha = 0.92; self.titleTxt = new Text2("", { size: 56, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); self.titleTxt.anchor.set(0, 0.5); self.titleTxt.x = 40; self.titleTxt.y = 0; self.addChild(self.titleTxt); self.stateTxt = new Text2("", { size: 44, fill: "#ff0", font: "Arial, Helvetica, sans-serif" }); self.stateTxt.anchor.set(0, 0.5); self.stateTxt.x = 500; self.stateTxt.y = 0; self.addChild(self.stateTxt); self.statsTxt = new Text2("", { size: 44, fill: "#0ff", font: "Arial, Helvetica, sans-serif" }); self.statsTxt.anchor.set(0, 0.5); self.statsTxt.x = 800; self.statsTxt.y = 0; self.addChild(self.statsTxt); self.setVideo = function (videoObj) { self.titleTxt.setText(videoObj.title || "Untitled"); // State: Recording, Gaining Views, Finished if (videoObj.hour === 0 && !videoObj.finished) { self.stateTxt.setText("Just Published"); } else if (!videoObj.finished) { self.stateTxt.setText("Gaining Views"); } else { self.stateTxt.setText("Finished"); } // Stats: views, money, subs var stats = formatNumber(videoObj.totalViews) + " views"; // Truncate money to 2 decimal digits for display in video list var moneyDisplay = Math.floor(videoObj.totalMoney * 100) / 100; stats += " | $" + formatNumber(moneyDisplay); stats += " | " + formatNumber(videoObj.totalSubs) + " subs"; if (videoObj.trending) { stats += " | 🔥"; } self.statsTxt.setText(stats); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // (Removed: Video Type Explanations below each button. Only technique explanations remain.) // --- Trending Category State --- // Global variable to track finance panel instance var financePanel = null; var videoCategories = ["Vlog", "Challenge", "Reaction", "Tutorial", "Unboxing", "Gaming", "Music", "Comedy", "Q&A"]; var selectedCategoryIdx = 0; // Studio background (simple box for now) // --- Game State Variables --- // Pick a random trending category at game start var trendingCategoryIdx = Math.floor(Math.random() * videoCategories.length); var trendingCategoryDay = 1; // The day this trending category started function updateTrendingCategory() { // Pick a new trending category index, different from the current one if possible var oldIdx = trendingCategoryIdx; if (videoCategories && videoCategories.length > 1) { var newIdx; do { newIdx = Math.floor(Math.random() * videoCategories.length); } while (newIdx === oldIdx); trendingCategoryIdx = newIdx; } else { trendingCategoryIdx = 0; } trendingCategoryDay = gameDay; // Set next change day if not already set if (typeof trendingCategoryNextChangeDay === "undefined") { trendingCategoryNextChangeDay = trendingCategoryDay + 7 + Math.floor(Math.random() * 24); // 7-30 days } } // If the record video panel is open, update the trending label text if it exists if (typeof isRecordPanelOpen !== "undefined" && isRecordPanelOpen && typeof categoryBtns !== "undefined") { for (var i = 0; i < categoryBtns.length; i++) { if (categoryBtns[i].trendingTxt) { categoryBtns[i].trendingTxt.setText("Trending"); // Move trending label to the new trending category if (i === trendingCategoryIdx) { categoryBtns[i].trendingTxt.visible = true; } else { categoryBtns[i].trendingTxt.visible = false; } } // Update button highlight for trending if (i === trendingCategoryIdx) { categoryBtns[i].bg.alpha = 0.95; if (categoryBtns[i].trendingTxt) { categoryBtns[i].trendingTxt.visible = true; } } else { if (categoryBtns[i].trendingTxt) { categoryBtns[i].trendingTxt.visible = false; } if (i !== selectedCategoryIdx) { categoryBtns[i].bg.alpha = 0.7; } } } } // Video button // Edit button // Promote button // Upgrade button // Energy bar background // Energy bar fill // Subscriber icon // Money icon // Sound for making a video var subscribers = 0; var viewCount = 0; var money = 0; var videoQuality = 1; // upgrades increase this var editSkill = 1; // upgrades increase this var promoteSkill = 1; // upgrades increase this var videoCount = 0; var upgradeCost = 20; var upgradeLevel = 1; // --- Time Mechanics --- var gameHour = 8; // Start at 8:00 var gameMinute = 0; // Start at 00 minutes var gameDay = 1; var isTimePaused = true; // Start with time paused var timeTimer = null; var timeProcess = null; // {type: 'record'|'edit'|'promote', hoursLeft: int, onFinish: fn} // --- UI Elements --- var studioBg = LK.getAsset('studioBg', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(studioBg); var phoneBg = LK.getAsset('phonebackground', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(phoneBg); var computerScreen = LK.getAsset('computerscreen', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 - 5, y: 2732 / 2 - 60 }); game.addChild(computerScreen); // --- App List inside computerscreen --- // Each app is now inside its own invisible overlay container var appListContainer = new Container(); var appOverlays = {}; // key: appNameLower, value: overlay Container // Calculate app icon and background sizes for 4 per row, filling computerscreen width var appsPerRow = 4; var appListMarginX = 60; // margin from left/right inside computerscreen var appListMarginY = 120; // margin from top inside computerscreen var appListWidth = computerScreen.width - 2 * appListMarginX; var appSpacing = 48; var appRowSpacing = 120; // Further increased vertical spacing between rows var appBgW = Math.floor((appListWidth - (appsPerRow - 1) * appSpacing) / appsPerRow); var appBgH = appBgW; // make square var appIconW = Math.floor(appBgW * 0.54); var appIconH = appIconW; // Align the app list to the left edge inside computerscreen var appListStartX = computerScreen.x - computerScreen.width / 2 + appListMarginX + appBgW / 2; var appListY = computerScreen.y - computerScreen.height / 2 + appListMarginY + appBgH / 2; // Move the appListContainer visually inside the computerscreen and align to top-left appListContainer.x = computerScreen.width / -2 + appListMarginX + appBgW / 2; appListContainer.y = computerScreen.height / -2 + appListMarginY + appBgH / 2; // Helper to create an overlay for a given app function createAppOverlay(appNameLower, idx) { var overlay = new Container(); overlay.appNameLower = appNameLower; // Calculate row/col for 4 per row var row = Math.floor(idx / appsPerRow); var col = idx % appsPerRow; var bgX = col * (appBgW + appSpacing); var bgY = row * (appBgH + appRowSpacing); // Background var bg = LK.getAsset('whitebackgroundrounded', { anchorX: 0.5, anchorY: 0.5, x: bgX, y: bgY }); bg.width = appBgW; bg.height = appBgH; overlay.addChild(bg); // Icon var iconAssetId = "youtube"; if (appNameLower === "play store") iconAssetId = "playstore"; if (appNameLower === "editing") iconAssetId = "edit"; if (appNameLower === "statistics") iconAssetId = "statistics"; if (appNameLower === "promote") iconAssetId = "promotebutton"; if (appNameLower === "record") iconAssetId = "recordbutton"; if (appNameLower === "finance") iconAssetId = "financalbutton"; if (appNameLower === "youtube studio") iconAssetId = "youtubestudio"; var icon = LK.getAsset(iconAssetId, { anchorX: 0.5, anchorY: 0.5, x: bgX, y: bgY }); if (appNameLower === "editing") { icon.width = appIconW * 1.5; icon.height = appIconH * 1.5; } else { icon.width = appIconW; icon.height = appIconH; } overlay.addChild(icon); // Label var label = new Text2(appNameLower, { size: 54, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); label.anchor.set(0.5, 0); label.x = bgX; label.y = bgY + appBgH / 2 + 18; overlay.addChild(label); // Store for later reference overlay._appBg = bg; overlay._appIcon = icon; overlay._appLabel = label; // Make Youtube Studio app icon interactive to open only the publish panel with all requested features if (appNameLower === "youtube studio") { // Helper to check if there is an edited video ready to publish var isYoutubeStudioEnabled = function isYoutubeStudioEnabled() { if (!window.uploadedVideos || window.uploadedVideos.length === 0) return false; for (var i = 0; i < window.uploadedVideos.length; i++) { var v = window.uploadedVideos[i]; if (v.state === "readyToPublish" && v.publishReady && !v.finished) { return true; } } return false; }; var updateYoutubeStudioEnabled = function updateYoutubeStudioEnabled() { var enabled = isYoutubeStudioEnabled(); overlay.interactive = enabled; overlay.buttonMode = enabled; if (overlay._appBg) overlay._appBg.alpha = 1; if (overlay._appIcon) overlay._appIcon.alpha = 1; if (overlay._appLabel) overlay._appLabel.alpha = 1; }; // Initial state updateYoutubeStudioEnabled(); // Patch updateVideoLists and updateStats to also update the enabled state var oldUpdateVideoLists = typeof updateVideoLists === "function" ? updateVideoLists : null; updateVideoLists = function updateVideoLists() { if (oldUpdateVideoLists) oldUpdateVideoLists(); updateYoutubeStudioEnabled(); }; var oldUpdateStats = typeof updateStats === "function" ? updateStats : null; updateStats = function updateStats() { if (oldUpdateStats) oldUpdateStats(); updateYoutubeStudioEnabled(); }; overlay.down = function (x, y, obj) { // If channel not created, show channel creation panel (should only happen if user skipped at start) if (!window.youtubeChannel) { if (typeof showYoutubeStudioPanelAtStart === "function") showYoutubeStudioPanelAtStart(); return; } // Only open publish panel if there is an edited video ready to publish var foundReadyToPublish = false; var readyVideo = null; var hasUnpublished = false; if (window.uploadedVideos && window.uploadedVideos.length > 0) { for (var i = 0; i < window.uploadedVideos.length; i++) { var v = window.uploadedVideos[i]; if (v.state === "readyToPublish" && v.publishReady && !v.finished) { foundReadyToPublish = true; readyVideo = v; break; } if (v.state === "recorded" && !v.finished) { hasUnpublished = true; } } } if (!foundReadyToPublish) { // Animate the editing app icon (grow and shrink) if there is a video in 'recorded' state if (hasUnpublished && appOverlays && appOverlays["editing"] && appOverlays["editing"]._appIcon) { var editingIcon = appOverlays["editing"]._appIcon; tween.stop(editingIcon, { scaleX: true, scaleY: true }); tween(editingIcon, { scaleX: 1.3, scaleY: 1.3 }, { duration: 220, easing: tween.cubicOut, onFinish: function onFinish() { tween(editingIcon, { scaleX: 1, scaleY: 1 }, { duration: 220, easing: tween.cubicIn }); } }); return; // Do not open publish panel } // Otherwise, animate record icon (if all videos are published) if (!hasUnpublished && appOverlays && appOverlays["record"] && appOverlays["record"]._appIcon) { var recordIcon = appOverlays["record"]._appIcon; tween.stop(recordIcon, { scaleX: true, scaleY: true }); tween(recordIcon, { scaleX: 1.3, scaleY: 1.3 }, { duration: 220, easing: tween.cubicOut, onFinish: function onFinish() { tween(recordIcon, { scaleX: 1, scaleY: 1 }, { duration: 220, easing: tween.cubicIn }); } }); return; // Do not open publish panel } return; // Do not open publish panel } // Always hide other overlays/panels if (typeof videoListBg !== "undefined") videoListBg.visible = false; if (typeof videoListContainer !== "undefined") videoListContainer.visible = false; if (typeof statsOverlay !== "undefined") statsOverlay.visible = false; // Destroy any previous publish panel if (typeof window.youtubeStudioPublishPanel !== "undefined" && window.youtubeStudioPublishPanel) { try { window.youtubeStudioPublishPanel.destroy(); } catch (e) {} window.youtubeStudioPublishPanel = null; } if (typeof window.youtubeStudioPublishTitle !== "undefined" && window.youtubeStudioPublishTitle) { try { window.youtubeStudioPublishTitle.destroy(); } catch (e) {} window.youtubeStudioPublishTitle = null; } // If a video is ready to publish, show the publish panel for that video if (foundReadyToPublish && readyVideo) { showYoutubeStudioPublishPanel(readyVideo); } }; icon.interactive = true; icon.buttonMode = true; icon.down = overlay.down; bg.interactive = true; bg.buttonMode = true; bg.down = overlay.down; } // Make Play Store app icon interactive to open Play Store overlay if (appNameLower === "play store") { overlay.interactive = true; overlay.buttonMode = true; overlay.down = function (x, y, obj) { showPlayStoreOverlay(); }; // Also make icon and bg interactive for better UX icon.interactive = true; icon.buttonMode = true; icon.down = function (x, y, obj) { showPlayStoreOverlay(); }; bg.interactive = true; bg.buttonMode = true; bg.down = function (x, y, obj) { showPlayStoreOverlay(); }; } // Make Statistics app icon interactive to open statistics panel if (appNameLower === "statistics") { overlay.interactive = true; overlay.buttonMode = true; overlay.down = function (x, y, obj) { // Defensive: re-add statsOverlay if destroyed if (!game.children.includes(statsOverlay)) { game.addChild(statsOverlay); } hideVideoList(); updateStatsGraphSingle(); statsOverlay.visible = true; }; icon.interactive = true; icon.buttonMode = true; icon.down = overlay.down; bg.interactive = true; bg.buttonMode = true; bg.down = overlay.down; } // Make Finance app icon interactive to open finance panel if (appNameLower === "finance") { overlay.interactive = true; overlay.buttonMode = true; overlay.down = function (x, y, obj) { // Defensive: destroy previous if exists if (financePanel && typeof financePanel.destroy === "function") { try { financePanel.destroy(); } catch (e) {} financePanel = null; } financePanel = new FinancePanel(); // Insert financePanel above computerscreen (so it appears on top of computerscreen, but below everything else) var computerScreenIdx = game.children.indexOf(computerScreen); if (computerScreenIdx !== -1) { game.addChildAt(financePanel, computerScreenIdx + 1); } else { game.addChild(financePanel); } // Always update money display if (financePanel && typeof financePanel.updateMoney === "function") { financePanel.updateMoney(); } }; icon.interactive = true; icon.buttonMode = true; icon.down = overlay.down; bg.interactive = true; bg.buttonMode = true; bg.down = overlay.down; } // --- Promote Panel Globals (prevent ReferenceError) --- window.promotePanelBg = null; window.promoteTitle = null; window.moneySliderBg = null; window.moneySliderFill = null; window.moneySliderHandle = null; window.moneyInputTxt = null; window.daysSliderBg = null; window.daysSliderFill = null; window.daysSliderHandle = null; window.daysInputTxt = null; window.estViewsTxt = null; window.confirmPromoteBtn = null; window.closePromoteBtn = null; if (typeof window.promoteListLabels === "undefined" || !window.promoteListLabels) { window.promoteListLabels = []; } // --- Promote campaigns global state --- if (typeof window.activePromotes === "undefined") window.activePromotes = []; // Make Promote app icon interactive to open promote panel if (appNameLower === "promote") { overlay.interactive = true; overlay.buttonMode = true; overlay.down = function (x, y, obj) { // Defensive: destroy previous promote panel if open if (typeof game.promotePanelOpen !== "undefined" && game.promotePanelOpen) { var promotePanelElements = ["promotePanelBg", "promoteTitle", "moneySliderBg", "moneySliderFill", "moneySliderHandle", "moneyInputTxt", "daysSliderBg", "daysSliderFill", "daysSliderHandle", "daysInputTxt", "estViewsTxt", "confirmPromoteBtn", "closePromoteBtn"]; for (var i = 0; i < promotePanelElements.length; i++) { if (typeof window[promotePanelElements[i]] !== "undefined" && window[promotePanelElements[i]]) { try { window[promotePanelElements[i]].destroy(); } catch (e) {} window[promotePanelElements[i]] = null; } } // Destroy promote list labels if (typeof promoteListLabels === "undefined") { window.promoteListLabels = []; } if (typeof promoteListLabels !== "undefined" && promoteListLabels.length) { for (var i = 0; i < promoteListLabels.length; i++) { for (var j = 0; j < promoteListLabels[i].length; j++) { if (promoteListLabels[i][j]) { try { promoteListLabels[i][j].destroy(); } catch (e) {} } } } } game.promotePanelOpen = false; } // Defensive: destroy previous promote panel if open (again, for safety) if (typeof promotePanelBg !== "undefined" && promotePanelBg) { try { promotePanelBg.destroy(); } catch (e) {} promotePanelBg = null; } if (typeof promoteTitle !== "undefined" && promoteTitle) { try { promoteTitle.destroy(); } catch (e) {} promoteTitle = null; } // Create promote panel background, matching computerscreen promotePanelBg = LK.getAsset('studioBg', { anchorX: 0.5, anchorY: 0.5, x: computerScreen.x, y: computerScreen.y }); promotePanelBg.width = computerScreen.width; promotePanelBg.height = computerScreen.height; promotePanelBg.alpha = 0.98; var csIdx = game.children.indexOf(computerScreen); if (csIdx !== -1) { game.addChildAt(promotePanelBg, csIdx + 1); } else { game.addChild(promotePanelBg); } // Create promote panel title promoteTitle = new Text2("Promote Channel", { size: 90, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); promoteTitle.anchor.set(0.5, 0.5); promoteTitle.x = computerScreen.x; promoteTitle.y = computerScreen.y - computerScreen.height / 2 + 120; game.addChildAt(promoteTitle, csIdx + 2); // --- Promote Panel Content --- var panelMarginX = 60; var panelMarginY = 60; var panelInnerW = promotePanelBg.width - panelMarginX * 2; var panelInnerH = promotePanelBg.height - panelMarginY * 2; // --- Money slider (max = current money) --- var minMoney = 0; // Minimum budget is now 0 var maxMoney = Math.max(minMoney, Math.floor(money)); var minDays = 1; var maxDays = 30; var moneyValue = Math.min(100, maxMoney); var daysValue = 3; // Money slider window.moneySliderBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0.5, x: computerScreen.x, y: promoteTitle.y + 180 }); var moneySliderBg = window.moneySliderBg; moneySliderBg.width = panelInnerW - 200; moneySliderBg.height = 80; moneySliderBg.alpha = 0.92; game.addChild(moneySliderBg); window.moneySliderFill = LK.getAsset('loadingbarfull', { anchorX: 0, anchorY: 0.5, x: moneySliderBg.x - moneySliderBg.width / 2, y: moneySliderBg.y }); var moneySliderFill = window.moneySliderFill; moneySliderFill.width = 0; moneySliderFill.height = 60; moneySliderFill.tint = 0x44ff44; game.addChild(moneySliderFill); window.moneySliderHandle = LK.getAsset('promoteBtn', { anchorX: 0.5, anchorY: 0.5, x: moneySliderBg.x - moneySliderBg.width / 2, y: moneySliderBg.y }); var moneySliderHandle = window.moneySliderHandle; moneySliderHandle.width = 80; moneySliderHandle.height = 80; game.addChild(moneySliderHandle); // Money input text window.moneyInputTxt = new Text2("$" + moneyValue, { size: 54, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); var moneyInputTxt = window.moneyInputTxt; moneyInputTxt.anchor.set(0.5, 0.5); moneyInputTxt.x = moneySliderBg.x; moneyInputTxt.y = moneySliderBg.y - 70; game.addChild(moneyInputTxt); // --- Days slider (max 30) --- window.daysSliderBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0.5, x: computerScreen.x, y: moneySliderBg.y + 220 }); var daysSliderBg = window.daysSliderBg; daysSliderBg.width = panelInnerW - 200; daysSliderBg.height = 80; daysSliderBg.alpha = 0.92; game.addChild(daysSliderBg); window.daysSliderFill = LK.getAsset('loadingbarfull', { anchorX: 0, anchorY: 0.5, x: daysSliderBg.x - daysSliderBg.width / 2, y: daysSliderBg.y }); var daysSliderFill = window.daysSliderFill; daysSliderFill.width = 0; daysSliderFill.height = 60; daysSliderFill.tint = 0x44aaff; game.addChild(daysSliderFill); window.daysSliderHandle = LK.getAsset('editBtn', { anchorX: 0.5, anchorY: 0.5, x: daysSliderBg.x - daysSliderBg.width / 2, y: daysSliderBg.y }); var daysSliderHandle = window.daysSliderHandle; daysSliderHandle.width = 80; daysSliderHandle.height = 80; game.addChild(daysSliderHandle); // Days input text window.daysInputTxt = new Text2(daysValue + " days", { size: 54, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); var daysInputTxt = window.daysInputTxt; daysInputTxt.anchor.set(0.5, 0.5); daysInputTxt.x = daysSliderBg.x; daysInputTxt.y = daysSliderBg.y - 70; game.addChild(daysInputTxt); // --- Estimated views text (show as range) --- window.estViewsTxt = new Text2("Estimated: 0 - 0 views", { size: 48, fill: "#ff0", font: "Arial, Helvetica, sans-serif" }); var estViewsTxt = window.estViewsTxt; estViewsTxt.anchor.set(0.5, 0.5); estViewsTxt.x = computerScreen.x; estViewsTxt.y = daysSliderBg.y + 120; game.addChild(estViewsTxt); // --- Confirm promote button --- window.confirmPromoteBtn = new GameButton(); var confirmPromoteBtn = window.confirmPromoteBtn; confirmPromoteBtn.setButton('promoteBtn', 'Start Promotion', "#fff", 480, 120); if (confirmPromoteBtn.label && confirmPromoteBtn.label.style && typeof confirmPromoteBtn.label.style.size !== "undefined") { confirmPromoteBtn.label.style.size = 44; confirmPromoteBtn.label.dirty = true; } else if (confirmPromoteBtn.label && typeof confirmPromoteBtn.label.setStyle === "function") { confirmPromoteBtn.label.setStyle({ size: 44 }); } confirmPromoteBtn.x = computerScreen.x; confirmPromoteBtn.y = estViewsTxt.y + 180; // --- Promote List (active/finished campaigns) --- if (typeof window.promoteListLabels === "undefined") window.promoteListLabels = []; function updatePromoteListDisplay() { // Remove old labels if (window.promoteListLabels && window.promoteListLabels.length) { for (var i = 0; i < window.promoteListLabels.length; i++) { for (var j = 0; j < window.promoteListLabels[i].length; j++) { if (window.promoteListLabels[i][j]) { try { window.promoteListLabels[i][j].destroy(); } catch (e) {} } } } } window.promoteListLabels = []; if (!window.activePromotes || !window.activePromotes.length) return; var startY = confirmPromoteBtn.y + 160; var labelH = 54; for (var i = 0; i < window.activePromotes.length; i++) { var p = window.activePromotes[i]; var y = startY + i * (labelH + 16); var arr = []; // Status var status = p.finished ? "Finished" : "Active"; var labelTxt = new Text2("Ad: $" + p.amount + " / " + p.days + "g | " + "Views: " + p.viewsSoFar + "/" + p.estViewsMin + "-" + p.estViewsMax + " | " + "Subs: " + p.subsGained + " | " + status, { size: 44, fill: p.finished ? "#aaa" : "#fff", font: "Arial, Helvetica, sans-serif" }); labelTxt.anchor.set(0.5, 0.5); labelTxt.x = computerScreen.x; labelTxt.y = y; game.addChild(labelTxt); arr.push(labelTxt); // Show stats button var statsBtn = new GameButton(); statsBtn.setButton('editBtn', 'Stats', "#fff", 180, 60); statsBtn.x = computerScreen.x + 540; statsBtn.y = y; statsBtn.action = function (idx) { return function () { showPromoteStatsPanel(idx); }; }(i); game.addChild(statsBtn); arr.push(statsBtn); // Save for later removal window.promoteListLabels.push(arr); // Attach update method for live update p._promoteListLabel = arr; p.updatePromoteListLabel = function () { if (!this._promoteListLabel) return; var label = this._promoteListLabel[0]; if (!label) return; var status = this.finished ? "Finished" : "Active"; label.setText("Ad: $" + this.amount + " / " + this.days + "g | " + "Views: " + this.viewsSoFar + "/" + this.estViewsMin + "-" + this.estViewsMax + " | " + "Subs: " + this.subsGained + " | " + status); label.style.fill = this.finished ? "#aaa" : "#fff"; }; } } window.updatePromoteListDisplay = updatePromoteListDisplay; // --- UI update logic --- function updatePromotePanelUI() { // Clamp maxMoney to current money maxMoney = Math.max(minMoney, Math.floor(money)); if (moneyValue > maxMoney) moneyValue = maxMoney; if (moneyValue < minMoney) moneyValue = minMoney; if (daysValue > maxDays) daysValue = maxDays; if (daysValue < minDays) daysValue = minDays; // Money slider var moneyRatio = (moneyValue - minMoney) / (maxMoney - minMoney || 1); moneySliderFill.width = moneySliderBg.width * moneyRatio; moneySliderHandle.x = moneySliderBg.x - moneySliderBg.width / 2 + moneySliderBg.width * moneyRatio; moneyInputTxt.setText("$" + moneyValue); // Days slider var daysRatio = (daysValue - minDays) / (maxDays - minDays); daysSliderFill.width = daysSliderBg.width * daysRatio; daysSliderHandle.x = daysSliderBg.x - daysSliderBg.width / 2 + daysSliderBg.width * daysRatio; daysInputTxt.setText(daysValue + " days"); // Estimated views (show as range) var estMin = Math.floor(moneyValue * daysValue * 2.0); var estMax = Math.floor(moneyValue * daysValue * 3.0); estViewsTxt.setText("Estimated: " + estMin + " - " + estMax + " views"); } updatePromotePanelUI(); // Money slider drag moneySliderHandle.interactive = true; moneySliderHandle.buttonMode = true; var draggingMoney = false; moneySliderHandle.down = function (x, y, obj) { draggingMoney = true; }; game.move = function (origMove) { return function (x, y, obj) { if (draggingMoney) { var localX = x - (moneySliderBg.x - moneySliderBg.width / 2); var ratio = Math.max(0, Math.min(1, localX / moneySliderBg.width)); moneyValue = Math.round(minMoney + (maxMoney - minMoney) * ratio); updatePromotePanelUI(); } if (draggingDays) { var localX = x - (daysSliderBg.x - daysSliderBg.width / 2); var ratio = Math.max(0, Math.min(1, localX / daysSliderBg.width)); daysValue = Math.round(minDays + (maxDays - minDays) * ratio); updatePromotePanelUI(); } if (typeof origMove === "function") origMove(x, y, obj); }; }(game.move); moneySliderHandle.up = function (x, y, obj) { draggingMoney = false; }; // Days slider drag daysSliderHandle.interactive = true; daysSliderHandle.buttonMode = true; var draggingDays = false; daysSliderHandle.down = function (x, y, obj) { draggingDays = true; }; daysSliderHandle.up = function (x, y, obj) { draggingDays = false; }; // --- Confirm promote logic --- confirmPromoteBtn.action = function () { // Prevent promotion if budget is 0 if (moneyValue === 0) { var errTxt = new Text2("Promotion budget must be greater than $0!", { size: 54, fill: 0xFF4444, font: "Arial, Helvetica, sans-serif" }); errTxt.anchor.set(0.5, 0.5); errTxt.x = confirmPromoteBtn.x; errTxt.y = confirmPromoteBtn.y + 120; game.addChild(errTxt); tween(errTxt, { alpha: 0, y: errTxt.y + 40 }, { duration: 1200, onFinish: function onFinish() { errTxt.destroy(); } }); return; } // Defensive: check enough money if (money < moneyValue) { var errTxt = new Text2("Not enough money!", { size: 54, fill: 0xFF4444, font: "Arial, Helvetica, sans-serif" }); errTxt.anchor.set(0.5, 0.5); errTxt.x = confirmPromoteBtn.x; errTxt.y = confirmPromoteBtn.y + 120; game.addChild(errTxt); tween(errTxt, { alpha: 0, y: errTxt.y + 40 }, { duration: 1200, onFinish: function onFinish() { errTxt.destroy(); } }); return; } // Deduct money money -= moneyValue; updateStats(); // Calculate estimated views range var estMin = Math.floor(moneyValue * daysValue * 2.0); var estMax = Math.floor(moneyValue * daysValue * 3.0); // Create promote campaign object var promoteObj = { amount: moneyValue, days: daysValue, startDay: gameDay, finished: false, lastDay: gameDay + daysValue - 1, estViewsMin: estMin, estViewsMax: estMax, viewsSoFar: 0, subsGained: 0, spentSoFar: 0, viewsPerHour: [], shownPerHour: [], subsPerDay: [], viewsPerDay: [], subRate: 0.01 + Math.random() * 0.01, // 1-2% conversion _promoteListLabel: null, updatePromoteListLabel: null }; // Generate views per hour for each day for (var d = 0; d < daysValue; d++) { promoteObj.viewsPerHour[d] = []; promoteObj.shownPerHour[d] = []; var dayViews = Math.floor(estMin + Math.random() * (estMax - estMin + 1) / daysValue); for (var h = 0; h < 24; h++) { // Distribute views per hour, more at start var rel = h / 24; var hourViews = Math.floor(dayViews * (1.2 - rel * 0.7) / 24 + Math.random() * 2); promoteObj.viewsPerHour[d][h] = hourViews; promoteObj.shownPerHour[d][h] = 0; } } promoteObj.spentSoFar = 0; promoteObj.viewsSoFar = 0; promoteObj.subsGained = 0; window.activePromotes.push(promoteObj); // Clean up panel if (promotePanelBg) { promotePanelBg.destroy(); promotePanelBg = null; } if (promoteTitle) { promoteTitle.destroy(); promoteTitle = null; } if (moneySliderBg) { moneySliderBg.destroy(); moneySliderBg = null; } if (moneySliderFill) { moneySliderFill.destroy(); moneySliderFill = null; } if (moneySliderHandle) { moneySliderHandle.destroy(); moneySliderHandle = null; } if (moneyInputTxt) { moneyInputTxt.destroy(); moneyInputTxt = null; } if (daysSliderBg) { daysSliderBg.destroy(); daysSliderBg = null; } if (daysSliderFill) { daysSliderFill.destroy(); daysSliderFill = null; } if (daysSliderHandle) { daysSliderHandle.destroy(); daysSliderHandle = null; } if (daysInputTxt) { daysInputTxt.destroy(); daysInputTxt = null; } if (estViewsTxt) { estViewsTxt.destroy(); estViewsTxt = null; } if (confirmPromoteBtn) { confirmPromoteBtn.destroy(); confirmPromoteBtn = null; } if (typeof closePromoteBtn !== "undefined" && closePromoteBtn) { closePromoteBtn.destroy(); closePromoteBtn = null; } game.promotePanelOpen = false; // Show confirmation var doneTxt = new Text2("Promotion started!", { size: 64, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); doneTxt.anchor.set(0.5, 0.5); doneTxt.x = computerScreen.x; doneTxt.y = computerScreen.y; game.addChild(doneTxt); tween(doneTxt, { alpha: 0, y: doneTxt.y - 40 }, { duration: 1800, onFinish: function onFinish() { doneTxt.destroy(); } }); // Show promote panel again to see new campaign setTimeout(function () { overlay.down(); }, 600); }; game.addChild(confirmPromoteBtn); // Show all active/finished promotions in panel updatePromoteListDisplay(); // Mark promote panel as open game.promotePanelOpen = true; }; icon.interactive = true; icon.buttonMode = true; icon.down = overlay.down; bg.interactive = true; bg.buttonMode = true; bg.down = overlay.down; } // Make Editing app icon interactive to open the edit panel (like editBtn) if (appNameLower === "editing") { overlay.interactive = true; overlay.buttonMode = true; // Save the original overlay.down logic for later use (for patching after record) overlay.overlayDown = function (x, y, obj) { // --- Strict video flow logic for editing --- // Only allow editing if there is a video in 'recorded' state and not finished var canEdit = false; var hasReadyToPublish = false; var hasRecorded = false; if (window.uploadedVideos) { for (var i = 0; i < window.uploadedVideos.length; i++) { if (window.uploadedVideos[i].state === "recorded" && !window.uploadedVideos[i].finished) { canEdit = true; hasRecorded = true; // Set lastRecordedVideo for the edit panel window.lastRecordedVideo = { title: window.uploadedVideos[i].title, category: window.uploadedVideos[i].category }; break; } if (window.uploadedVideos[i].state === "readyToPublish" && !window.uploadedVideos[i].finished) { hasReadyToPublish = true; } } } // If not in recorded state, but there is a video in readyToPublish, do NOT allow editing if (!canEdit && hasReadyToPublish) { canEdit = false; // Do NOT allow editing if only readyToPublish exists, must publish first } if (!canEdit) { // If there is a video in 'readyToPublish', animate youtube studio icon if (hasReadyToPublish && appOverlays && appOverlays["youtube studio"] && appOverlays["youtube studio"]._appIcon) { var ytStudioIcon = appOverlays["youtube studio"]._appIcon; tween.stop(ytStudioIcon, { scaleX: true, scaleY: true }); tween(ytStudioIcon, { scaleX: 1.3, scaleY: 1.3 }, { duration: 220, easing: tween.cubicOut, onFinish: function onFinish() { tween(ytStudioIcon, { scaleX: 1, scaleY: 1 }, { duration: 220, easing: tween.cubicIn }); } }); return; } // Otherwise, animate record icon if (appOverlays && appOverlays["record"] && appOverlays["record"]._appIcon) { var recordIcon = appOverlays["record"]._appIcon; tween.stop(recordIcon, { scaleX: true, scaleY: true }); tween(recordIcon, { scaleX: 1.3, scaleY: 1.3 }, { duration: 220, easing: tween.cubicOut, onFinish: function onFinish() { tween(recordIcon, { scaleX: 1, scaleY: 1 }, { duration: 220, easing: tween.cubicIn }); } }); } return; // Do not open edit panel } // Defensive: destroy previous edit panel if open var editPanelElements = ["editPanelBg", "editPanelTitle", "editPanelBtn", "closeEditBtn", "videoTypeBtns", "editTechBtns", "editPanelDescTxt"]; for (var i = 0; i < editPanelElements.length; i++) { if (typeof window[editPanelElements[i]] !== "undefined" && window[editPanelElements[i]]) { try { window[editPanelElements[i]].destroy(); } catch (e) {} window[editPanelElements[i]] = null; } } // Defensive: destroy any previous dynamic arrays if (typeof window.editPanelVideoTypeBtns !== "undefined" && window.editPanelVideoTypeBtns) { for (var i = 0; i < window.editPanelVideoTypeBtns.length; i++) { if (window.editPanelVideoTypeBtns[i]) { try { window.editPanelVideoTypeBtns[i].destroy(); } catch (e) {} } } window.editPanelVideoTypeBtns = null; } if (typeof window.editPanelEditTechBtns !== "undefined" && window.editPanelEditTechBtns) { for (var i = 0; i < window.editPanelEditTechBtns.length; i++) { if (window.editPanelEditTechBtns[i]) { try { window.editPanelEditTechBtns[i].destroy(); } catch (e) {} } } window.editPanelEditTechBtns = null; } // --- Editing Panel Background --- if (typeof window.editPanelBg === "undefined") window.editPanelBg = null; window.editPanelBg = LK.getAsset('studioBg', { anchorX: 0.5, anchorY: 0.5, x: computerScreen.x, y: computerScreen.y }); var editPanelBg = window.editPanelBg; editPanelBg.width = computerScreen.width; editPanelBg.height = computerScreen.height; editPanelBg.alpha = 0.98; var csIdx = game.children.indexOf(computerScreen); if (csIdx !== -1) { game.addChildAt(editPanelBg, csIdx + 1); } else { game.addChild(editPanelBg); } // --- Editing Panel Title --- if (typeof window.editPanelTitle === "undefined") window.editPanelTitle = null; window.editPanelTitle = new Text2("Edit Video", { size: 90, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); var editPanelTitle = window.editPanelTitle; editPanelTitle.anchor.set(0.5, 0.5); editPanelTitle.x = computerScreen.x; editPanelTitle.y = computerScreen.y - computerScreen.height / 2 + 120; game.addChild(editPanelTitle); // --- Show last recorded video info if available --- if (window.lastRecordedVideo && window.lastRecordedVideo.title && window.lastRecordedVideo.category) { if (typeof window.editPanelVideoInfoTxt === "undefined") window.editPanelVideoInfoTxt = null; window.editPanelVideoInfoTxt = new Text2("Editing: " + window.lastRecordedVideo.title + " (" + window.lastRecordedVideo.category + ")", { size: 54, fill: "#ff0", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); window.editPanelVideoInfoTxt.anchor.set(0.5, 0.5); window.editPanelVideoInfoTxt.x = computerScreen.x; window.editPanelVideoInfoTxt.y = editPanelTitle.y + editPanelTitle.height / 2 + 30; game.addChild(window.editPanelVideoInfoTxt); } // --- Explanatory Texts for Editing Panel --- var editPanelHintTxt = new Text2("Please select the video form", { size: 44, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2, wordWrap: true, wordWrapWidth: computerScreen.width - 240 }); editPanelHintTxt.anchor.set(0.5, 0); editPanelHintTxt.x = computerScreen.x; editPanelHintTxt.y = editPanelTitle.y + 70 + 100; // moved 100px lower game.addChild(editPanelHintTxt); // --- Video Type Selection (Long/Short) --- // Center the buttons horizontally var videoTypes = ["Long Form", "Short Form"]; var selectedVideoTypeIdx = 0; window.editPanelVideoTypeBtns = []; var typeBtnW = 420, typeBtnH = 120, typeBtnSpacing = 60; var totalTypeWidth = videoTypes.length * typeBtnW + (videoTypes.length - 1) * typeBtnSpacing; var typeStartX = computerScreen.x - totalTypeWidth / 2 + typeBtnW / 2; var typeY = editPanelHintTxt.y + editPanelHintTxt.height + 60; for (var i = 0; i < videoTypes.length; i++) { (function (idx) { var btn = new GameButton(); btn.setButton('editBtn', videoTypes[idx], "#fff", typeBtnW, typeBtnH); btn.x = typeStartX + idx * (typeBtnW + typeBtnSpacing); btn.y = typeY; btn.action = function () { for (var j = 0; j < window.editPanelVideoTypeBtns.length; j++) { window.editPanelVideoTypeBtns[j].bg.alpha = 0.7; } btn.bg.alpha = 1; selectedVideoTypeIdx = idx; // Update description if (window.editPanelDescTxt) { window.editPanelDescTxt.setText(videoTypeDescArr[selectedVideoTypeIdx] + "\n" + editPanelDescArr[selectedEditTechIdx]); } // (Removed: video type explanations below buttons. Only technique explanations remain.) }; if (i === 0) btn.bg.alpha = 1;else btn.bg.alpha = 0.7; window.editPanelVideoTypeBtns.push(btn); game.addChild(btn); })(i); } // (Removed: Video Type Explanations below each button. Only technique explanations remain.) // --- Editing Techniques Selection --- // Add "please select editing technique" text above technique selection, not overlapping with technique buttons if (typeof window.editTechniqueHintTxt === "undefined") window.editTechniqueHintTxt = null; window.editTechniqueHintTxt = new Text2("please select editing technique", { size: 44, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2, wordWrap: true, wordWrapWidth: computerScreen.width - 240 }); window.editTechniqueHintTxt.anchor.set(0.5, 0); // Place the technique hint above the technique selection buttons, with extra margin // Place the technique hint above the technique selection buttons, with extra margin var maxTypeDescY = typeY + typeBtnH; window.editTechniqueHintTxt.x = computerScreen.x; window.editTechniqueHintTxt.y = maxTypeDescY + 40; window.editTechniqueHintTxt.y += 100; // moved 100px lower game.addChild(window.editTechniqueHintTxt); var editTechniques = ["Jump Cut", "Montage", "Slow Motion", "Text Overlay", "Music Sync", "Color Grading"]; var editPanelDescArr = ["Jump Cut: Fast-paced, removes pauses. Good for vlogs and short content.", "Montage: Sequence of clips, often with music. Great for highlights.", "Slow Motion: Dramatic effect, emphasizes moments.", "Text Overlay: Adds text for emphasis or clarity.", "Music Sync: Edits cut to the beat of music.", "Color Grading: Adjusts color for mood and style."]; var videoTypeDescArr = ["", ""]; var selectedEditTechIdx = 0; window.editPanelEditTechBtns = []; var techBtnW = 420, techBtnH = 100, techBtnSpacingX = 40, techBtnSpacingY = 30; var techPerRow = 2; var totalTechWidth = techPerRow * techBtnW + (techPerRow - 1) * techBtnSpacingX; var techStartX = computerScreen.x - totalTechWidth / 2 + techBtnW / 2; // Defensive: use window.editTechniqueHintTxt if available, else fallback to 0 var techStartY = typeof window.editTechniqueHintTxt !== "undefined" && window.editTechniqueHintTxt ? window.editTechniqueHintTxt.y + window.editTechniqueHintTxt.height + 24 + 50 : 50; for (var i = 0; i < editTechniques.length; i++) { (function (idx) { var btn = new GameButton(); btn.setButton('editBtn', editTechniques[idx], "#fff", techBtnW, techBtnH); var row = Math.floor(idx / techPerRow); var col = idx % techPerRow; btn.x = techStartX + col * (techBtnW + techBtnSpacingX); btn.y = techStartY + row * (techBtnH + techBtnSpacingY); btn.action = function () { for (var j = 0; j < window.editPanelEditTechBtns.length; j++) { window.editPanelEditTechBtns[j].bg.alpha = 0.7; } btn.bg.alpha = 1; selectedEditTechIdx = idx; // Update description if (window.editPanelDescTxt) { window.editPanelDescTxt.setText(videoTypeDescArr[selectedVideoTypeIdx] + "\n" + editPanelDescArr[selectedEditTechIdx]); } }; if (i === 0) btn.bg.alpha = 1;else btn.bg.alpha = 0.7; window.editPanelEditTechBtns.push(btn); game.addChild(btn); })(i); } // --- Description Text for Selected Technique and Form --- if (typeof window.editPanelDescTxt === "undefined") window.editPanelDescTxt = null; window.editPanelDescTxt = new Text2(videoTypeDescArr[selectedVideoTypeIdx] + "\n" + editPanelDescArr[selectedEditTechIdx], { size: 48, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2, wordWrap: true, wordWrapWidth: computerScreen.width - 240 }); var editPanelDescTxt = window.editPanelDescTxt; editPanelDescTxt.anchor.set(0.5, 0); editPanelDescTxt.x = computerScreen.x; editPanelDescTxt.y = techStartY + 3 * (techBtnH + techBtnSpacingY) + 30; editPanelDescTxt.y += 100; // moved 100px lower game.addChild(editPanelDescTxt); // --- Confirm Edit Button --- if (typeof window.editPanelBtn === "undefined") window.editPanelBtn = null; window.editPanelBtn = new GameButton(); var editPanelBtn = window.editPanelBtn; editPanelBtn.setButton('videoBtn', 'Start Editing', "#fff", 480, 120); editPanelBtn.x = computerScreen.x; editPanelBtn.y = editPanelDescTxt.y + editPanelDescTxt.height + 60; editPanelBtn.y += 100; // moved 100px lower editPanelBtn.action = function () { // Call closeAllBtn.action() to close all panels if (typeof closeAllBtn !== "undefined" && closeAllBtn && typeof closeAllBtn.action === "function") { closeAllBtn.action(); } // --- Mark the last recorded video as edited and move to publishing stage --- if (window.lastRecordedVideo && window.uploadedVideos && window.uploadedVideos.length > 0) { // Find the video object in uploadedVideos that matches lastRecordedVideo for (var i = 0; i < window.uploadedVideos.length; i++) { var v = window.uploadedVideos[i]; if (v.title === window.lastRecordedVideo.title && v.category === window.lastRecordedVideo.category && v.state === "recorded" && !v.finished) { v.state = "readyToPublish"; v.publishReady = true; // Optionally, store the selected edit type/technique for stats v.editType = typeof videoTypes !== "undefined" ? videoTypes[selectedVideoTypeIdx] : ""; v.editTechnique = typeof editTechniques !== "undefined" ? editTechniques[selectedEditTechIdx] : ""; break; } } } // --- Update video lists and stats so YouTube Studio becomes clickable --- if (typeof updateVideoLists === "function") updateVideoLists(); if (typeof updateStats === "function") updateStats(); // --- Enable YouTube Studio app icon after editing started --- if (appOverlays && appOverlays["youtube studio"] && typeof appOverlays["youtube studio"].interactive !== "undefined") { appOverlays["youtube studio"].interactive = true; appOverlays["youtube studio"].buttonMode = true; if (appOverlays["youtube studio"]._appBg) appOverlays["youtube studio"]._appBg.alpha = 1; if (appOverlays["youtube studio"]._appIcon) appOverlays["youtube studio"]._appIcon.alpha = 1; if (appOverlays["youtube studio"]._appLabel) appOverlays["youtube studio"]._appLabel.alpha = 1; } // Show confirmation and close the panel. var doneTxt = new Text2("Editing started: " + videoTypes[selectedVideoTypeIdx] + " / " + editTechniques[selectedEditTechIdx], { size: 54, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); doneTxt.anchor.set(0.5, 0.5); doneTxt.x = computerScreen.x; doneTxt.y = editPanelBtn.y + 120; game.addChild(doneTxt); tween(doneTxt, { alpha: 0, y: doneTxt.y + 40 }, { duration: 1200, onFinish: function onFinish() { doneTxt.destroy(); } }); // Destroy panel elements if (editPanelBg) { editPanelBg.destroy(); editPanelBg = null; } if (editPanelTitle) { editPanelTitle.destroy(); editPanelTitle = null; } if (window.editPanelVideoInfoTxt) { window.editPanelVideoInfoTxt.destroy(); window.editPanelVideoInfoTxt = null; } if (editPanelHintTxt) { editPanelHintTxt.destroy(); } // Remove 'please select editing technique' text if present if (window.editTechniqueHintTxt) { window.editTechniqueHintTxt.destroy(); window.editTechniqueHintTxt = null; } // Removed reference to undefined videoTypeExplainTxt // Removed reference to undefined editPanelCategoryExplainTxt if (editPanelBtn) { editPanelBtn.destroy(); editPanelBtn = null; } if (editPanelDescTxt) { editPanelDescTxt.destroy(); editPanelDescTxt = null; } if (window.editPanelVideoTypeBtns) { for (var i = 0; i < window.editPanelVideoTypeBtns.length; i++) { if (window.editPanelVideoTypeBtns[i]) window.editPanelVideoTypeBtns[i].destroy(); } window.editPanelVideoTypeBtns = null; } if (window.editPanelEditTechBtns) { for (var i = 0; i < window.editPanelEditTechBtns.length; i++) { if (window.editPanelEditTechBtns[i]) window.editPanelEditTechBtns[i].destroy(); } window.editPanelEditTechBtns = null; } }; game.addChild(editPanelBtn); // (No close button as requested) }; // Set overlay.down to call overlayDown (so patching after record works) overlay.down = function (x, y, obj) { overlay.overlayDown(x, y, obj); }; icon.interactive = true; icon.buttonMode = true; icon.down = overlay.down; bg.interactive = true; bg.buttonMode = true; bg.down = overlay.down; } // Make YouTube app icon interactive to open YouTube panel with channel banner, avatar, name, and category if (appNameLower === "youtube") { var showYoutubePanel = function showYoutubePanel() { // Defensive: destroy previous youtubePanel if exists if (typeof window.youtubePanel !== "undefined" && window.youtubePanel) { try { window.youtubePanel.destroy(); } catch (e) {} window.youtubePanel = null; } // Defensive: destroy previous youtubeBanner if exists if (typeof window.youtubeBanner !== "undefined" && window.youtubeBanner) { try { window.youtubeBanner.destroy(); } catch (e) {} window.youtubeBanner = null; } if (typeof window.youtubeAvatar !== "undefined" && window.youtubeAvatar) { try { window.youtubeAvatar.destroy(); } catch (e) {} window.youtubeAvatar = null; } if (typeof window.youtubeChannelNameTxt !== "undefined" && window.youtubeChannelNameTxt) { try { window.youtubeChannelNameTxt.destroy(); } catch (e) {} window.youtubeChannelNameTxt = null; } if (typeof window.youtubeChannelCatTxt !== "undefined" && window.youtubeChannelCatTxt) { try { window.youtubeChannelCatTxt.destroy(); } catch (e) {} window.youtubeChannelCatTxt = null; } // Defensive: re-add videoListBg and videoListContainer if destroyed by closeAllBtn if (!game.children.includes(videoListBg)) { game.addChild(videoListBg); } if (!game.children.includes(videoListContainer)) { game.addChild(videoListContainer); } videoListBg.visible = true; videoListContainer.visible = true; statsOverlay.visible = false; // --- YouTube Panel Banner --- // Create a banner at the top of the videoListBg, full width, 420px height var bannerH = 420; var bannerW = videoListBg.width; var bannerX = videoListBg.x; var bannerY = videoListBg.y - videoListBg.height / 2 + bannerH / 2; window.youtubeBanner = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0.5, x: bannerX, y: bannerY }); window.youtubeBanner.width = bannerW; window.youtubeBanner.height = bannerH; window.youtubeBanner.alpha = 1; window.youtubeBanner.tint = 0x22223a; // dark blue/gray for YouTube banner game.addChild(window.youtubeBanner); // --- Channel Avatar --- var avatarAssetId = "youtubechannelavatar01"; var channelName = "Channel"; var channelCategory = "Vlog"; if (window.youtubeChannel) { avatarAssetId = window.youtubeChannel.coverAssetId || avatarAssetId; channelName = window.youtubeChannel.name || channelName; channelCategory = window.youtubeChannel.category || channelCategory; } var avatarSize = 220; var avatarMarginLeft = 60; var avatarY = bannerY + bannerH / 2 - avatarSize / 2 - 30; // 30px margin from bottom window.youtubeAvatar = LK.getAsset(avatarAssetId, { anchorX: 0, anchorY: 1, x: bannerX - bannerW / 2 + avatarMarginLeft, y: bannerY + bannerH / 2 - 30 }); window.youtubeAvatar.width = avatarSize; window.youtubeAvatar.height = avatarSize; game.addChild(window.youtubeAvatar); // --- Channel Banner In Progress Text --- window.youtubeBannerInProgressTxt = new Text2("(Banners in progress)", { size: 44, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); window.youtubeBannerInProgressTxt.anchor.set(0.5, 0.5); window.youtubeBannerInProgressTxt.x = window.youtubeBanner.x; window.youtubeBannerInProgressTxt.y = window.youtubeBanner.y - window.youtubeBanner.height / 2 + 175; game.addChild(window.youtubeBannerInProgressTxt); // --- Channel Name --- window.youtubeChannelNameTxt = new Text2(channelName, { size: 72, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); window.youtubeChannelNameTxt.anchor.set(0, 0.5); window.youtubeChannelNameTxt.x = window.youtubeAvatar.x + avatarSize + 40; // Move 50px higher window.youtubeChannelNameTxt.y = window.youtubeAvatar.y - avatarSize / 2 + 10; game.addChild(window.youtubeChannelNameTxt); // --- Channel Category --- window.youtubeChannelCatTxt = new Text2(channelCategory, { size: 48, fill: 0xFFE066, font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); window.youtubeChannelCatTxt.anchor.set(0, 0.5); window.youtubeChannelCatTxt.x = window.youtubeChannelNameTxt.x; // Move 50px higher window.youtubeChannelCatTxt.y = window.youtubeChannelNameTxt.y + window.youtubeChannelNameTxt.height + 10; game.addChild(window.youtubeChannelCatTxt); // Ensure banner, avatar, name, and category are above videoListBg but below videoListContainer var bgIdx = game.children.indexOf(videoListBg); if (bgIdx !== -1) { if (window.youtubeBanner) game.addChildAt(window.youtubeBanner, bgIdx + 1); if (window.youtubeBannerInProgressTxt) game.addChildAt(window.youtubeBannerInProgressTxt, bgIdx + 2); if (window.youtubeAvatar) game.addChildAt(window.youtubeAvatar, bgIdx + 3); if (window.youtubeChannelNameTxt) game.addChildAt(window.youtubeChannelNameTxt, bgIdx + 4); if (window.youtubeChannelCatTxt) game.addChildAt(window.youtubeChannelCatTxt, bgIdx + 5); } }; overlay.interactive = true; overlay.buttonMode = true; overlay.down = function (x, y, obj) { showYoutubePanel(); }; icon.interactive = true; icon.buttonMode = true; icon.down = function (x, y, obj) { showYoutubePanel(); }; bg.interactive = true; bg.buttonMode = true; bg.down = function (x, y, obj) { showYoutubePanel(); }; } // Make Record app icon interactive to open the record panel if (appNameLower === "record") { overlay.interactive = true; overlay.buttonMode = true; overlay.down = function (x, y, obj) { // --- Strict video flow logic --- // 1. If there is any video in 'recorded' or 'readyToPublish' state and not finished, record is NOT allowed. var canRecord = true; var hasRecorded = false; var hasReadyToPublish = false; if (window.uploadedVideos) { for (var i = 0; i < window.uploadedVideos.length; i++) { if (window.uploadedVideos[i].state === "recorded" && !window.uploadedVideos[i].finished) { hasRecorded = true; canRecord = false; } if (window.uploadedVideos[i].state === "readyToPublish" && !window.uploadedVideos[i].finished) { hasReadyToPublish = true; canRecord = false; } } } // If can record, open record panel if (canRecord && typeof makeVideoBtn !== "undefined" && makeVideoBtn && typeof makeVideoBtn.action === "function") { makeVideoBtn.action(); return; } // If not allowed, animate the correct icon and do NOT open any panel // If there is a video in 'recorded' or 'readyToPublish', animate editing icon if ((hasRecorded || hasReadyToPublish) && appOverlays && appOverlays["editing"] && appOverlays["editing"]._appIcon) { var editingIcon = appOverlays["editing"]._appIcon; tween.stop(editingIcon, { scaleX: true, scaleY: true }); tween(editingIcon, { scaleX: 1.3, scaleY: 1.3 }, { duration: 220, easing: tween.cubicOut, onFinish: function onFinish() { tween(editingIcon, { scaleX: 1, scaleY: 1 }, { duration: 220, easing: tween.cubicIn }); } }); return; } // If editing is not available, animate youtube studio icon if (!hasRecorded && !hasReadyToPublish && appOverlays && appOverlays["youtube studio"] && appOverlays["youtube studio"]._appIcon) { var ytStudioIcon = appOverlays["youtube studio"]._appIcon; tween.stop(ytStudioIcon, { scaleX: true, scaleY: true }); tween(ytStudioIcon, { scaleX: 1.3, scaleY: 1.3 }, { duration: 220, easing: tween.cubicOut, onFinish: function onFinish() { tween(ytStudioIcon, { scaleX: 1, scaleY: 1 }, { duration: 220, easing: tween.cubicIn }); } }); return; } }; icon.interactive = true; icon.buttonMode = true; icon.down = overlay.down; bg.interactive = true; bg.buttonMode = true; bg.down = overlay.down; } return overlay; } // Initial overlays for installed apps // Always keep the app list in a fixed order: youtube, youtube studio, play store, editing, statistics, promote, record, finance var initialApps = [{ name: "youtube" }, { name: "youtube studio" }, { name: "play store" }, { name: "editing" }, { name: "statistics" }, { name: "promote" }, { name: "record" }, { name: "finance" }]; // --- Show YouTube Studio channel creation panel at game start --- var youtubeStudioPanel = null; function showYoutubeStudioPanelAtStart() { // Defensive: destroy previous if exists if (youtubeStudioPanel && typeof youtubeStudioPanel.destroy === "function") { try { youtubeStudioPanel.destroy(); } catch (e) {} youtubeStudioPanel = null; } // Create Youtube Studio panel (background only, matching computerscreen) youtubeStudioPanel = LK.getAsset('studioBg', { anchorX: 0.5, anchorY: 0.5, x: computerScreen.x, y: computerScreen.y }); youtubeStudioPanel.width = computerScreen.width; youtubeStudioPanel.height = computerScreen.height; youtubeStudioPanel.alpha = 0.98; // Insert above computerscreen var csIdx = game.children.indexOf(computerScreen); if (csIdx !== -1) { game.addChildAt(youtubeStudioPanel, csIdx + 1); } else { game.addChild(youtubeStudioPanel); } // --- YouTube Channel Creation UI (copied from app overlay logic) --- if (typeof youtubeChannel === "undefined") { window.youtubeChannel = null; } if (!window.youtubeChannel) { // --- ENGLISH UI STRINGS --- // Calculate safe margins for the panel var panelMarginX = 60; var panelMarginY = 60; var panelInnerW = youtubeStudioPanel.width - panelMarginX * 2; var panelInnerH = youtubeStudioPanel.height - panelMarginY * 2; // 1. Title var studioTitle = new Text2("Create YouTube Channel", { size: 64, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); studioTitle.anchor.set(0.5, 0.5); studioTitle.x = youtubeStudioPanel.x; studioTitle.y = youtubeStudioPanel.y - youtubeStudioPanel.height / 2 + panelMarginY + 60; // 2. Channel name input and random button (side by side) var channelName = ""; var channelNameBgW = Math.min(900, panelInnerW - 320); var channelNameBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0.5 }); channelNameBg.width = channelNameBgW; channelNameBg.height = 120; channelNameBg.x = youtubeStudioPanel.x - 80; channelNameBg.y = studioTitle.y + studioTitle.height / 2 + 50 + 60; // 50px below title channelNameBg.alpha = 0.92; var channelNameTxt = new Text2("Enter channel name...", { size: 64, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); channelNameTxt.anchor.set(0.5, 0.5); channelNameTxt.x = channelNameBg.x; channelNameTxt.y = channelNameBg.y; channelNameBg.interactive = true; channelNameBg.buttonMode = true; channelNameBg.down = function (x, y, obj) { var prompt = LK.prompt ? LK.prompt : window.prompt; var val = prompt ? prompt("Enter channel name:", channelName) : ""; if (typeof val === "string" && val.length > 0) { channelName = val; channelNameTxt.setText(channelName); } }; channelNameTxt.interactive = true; channelNameTxt.buttonMode = true; channelNameTxt.down = channelNameBg.down; var randomChannelNames = ["EpicVlogs", "DailyDose", "FunZone", "NextGen", "ChillTime", "LifeHacks", "GameOn", "MusicWave", "LaughHub", "Reactify", "UnboxKing", "HowToPro", "QnAWorld", "ComedyLab", "TrendSpot", "StudioX", "VibeTube", "SkillShare", "TheShow", "PrimeClips"]; var randomNameBtn = new GameButton(); randomNameBtn.setButton('promoteBtn', '', "#fff", 120, 120); if (randomNameBtn.label) randomNameBtn.label.visible = false; var randomLogo = LK.getAsset('randomlogo', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); randomLogo.width = 100; randomLogo.height = 82; randomNameBtn.addChild(randomLogo); randomNameBtn._customIcon = randomLogo; randomNameBtn.x = channelNameBg.x + channelNameBg.width / 2 + 80; randomNameBtn.y = channelNameBg.y; randomNameBtn.action = function () { var idx = Math.floor(Math.random() * randomChannelNames.length); channelName = randomChannelNames[idx]; if (channelNameTxt.text === "Enter channel name...") { channelNameTxt.setText(""); } if (channelName && channelName.length > 0) { channelNameTxt.setText(channelName); } else { channelNameTxt.setText(""); } }; // 3. "Please select channel category" text var selectCatTxt = new Text2("Please select channel category", { size: 48, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); selectCatTxt.anchor.set(0.5, 0.5); selectCatTxt.x = youtubeStudioPanel.x; selectCatTxt.y = channelNameBg.y + channelNameBg.height / 2 + 50; // 4. Category buttons var ytCategories = ["Vlog", "Challenge", "Reaction", "Tutorial", "Unboxing", "Gaming", "Music", "Comedy", "Q&A"]; var ytCategoryDescriptions = ["Vlog: Share your daily life and connect with your audience. Bonus: Faster subscriber growth.", "Challenge: Take on fun and trending challenges. Bonus: Higher chance to go viral.", "Reaction: React to videos, memes, and more. Bonus: More views from trending topics.", "Tutorial: Teach skills and help others learn. Bonus: Earn more money per view.", "Unboxing: Unbox products and share first impressions. Bonus: Attract sponsorships.", "Gaming: Play and review games for your fans. Bonus: Steady viewership growth.", "Music: Share your music and covers. Bonus: Loyal fanbase and higher engagement.", "Comedy: Make people laugh with skits and jokes. Bonus: Occasional viral spikes.", "Q&A: Answer questions from your audience. Bonus: Strong community connection."]; var ytCategoryBonuses = ["Faster subscriber growth.", "Higher chance to go viral.", "More views from trending topics.", "Earn more money per view.", "Attract sponsorships.", "Steady viewership growth.", "Loyal fanbase and higher engagement.", "Occasional viral spikes.", "Strong community connection."]; var selectedYtCategoryIdx = -1; // No category selected by default var categoryBtnsYt = []; var catBtnW = 320, catBtnH = 100, catBtnSpacingX = 32, catBtnSpacingY = 32; var maxRowWidth = youtubeStudioPanel.width - 120; var maxPerRow = Math.floor((maxRowWidth + catBtnSpacingX) / (catBtnW + catBtnSpacingX)); if (maxPerRow < 1) maxPerRow = 1; if (maxPerRow > ytCategories.length) maxPerRow = ytCategories.length; var startX = youtubeStudioPanel.x - (Math.min(maxPerRow, ytCategories.length) * (catBtnW + catBtnSpacingX) - catBtnSpacingX) / 2 + catBtnW / 2; var catBtnsStartY = selectCatTxt.y + 50 + catBtnH / 2; for (var i = 0; i < ytCategories.length; i++) { (function (idx) { var btn = new GameButton(); btn.setButton('editBtn', ytCategories[idx], "#fff", catBtnW, catBtnH); if (btn.label && btn.label.style && typeof btn.label.style.size !== "undefined") { btn.label.style.size = 38; btn.label.dirty = true; } else if (btn.label && typeof btn.label.setStyle === "function") { btn.label.setStyle({ size: 38 }); } var row = Math.floor(idx / maxPerRow); var col = idx % maxPerRow; btn.x = Math.max(youtubeStudioPanel.x - panelInnerW / 2 + catBtnW / 2 + 10, Math.min(startX + col * (catBtnW + catBtnSpacingX), youtubeStudioPanel.x + panelInnerW / 2 - catBtnW / 2 - 10)); btn.y = catBtnsStartY + row * (catBtnH + catBtnSpacingY); btn.action = function () { for (var j = 0; j < categoryBtnsYt.length; j++) categoryBtnsYt[j].bg.alpha = 0.7; btn.bg.alpha = 1; selectedYtCategoryIdx = idx; if (categoryDescTxt && typeof categoryDescTxt.setText === "function") { categoryDescTxt.setText(ytCategoryDescriptions[idx]); } }; if (i === selectedYtCategoryIdx && selectedYtCategoryIdx !== -1) btn.bg.alpha = 1;else btn.bg.alpha = 0.7; categoryBtnsYt.push(btn); })(i); } // 5. Selected category description var lastCatBtn = categoryBtnsYt[categoryBtnsYt.length - 1]; var catBtnsBottomY = lastCatBtn ? lastCatBtn.y + catBtnH / 2 : catBtnsStartY + catBtnH / 2; var categoryDescTxt = new Text2("", { size: 48, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2, wordWrap: true, wordWrapWidth: panelInnerW - 80 }); categoryDescTxt.anchor.set(0.5, 0); categoryDescTxt.x = youtubeStudioPanel.x; categoryDescTxt.y = catBtnsBottomY + 50; // 6. "please select avatar for your channel" text var selectAvatarTxt = new Text2("please select avatar for your channel", { size: 44, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); selectAvatarTxt.anchor.set(0.5, 0.5); selectAvatarTxt.x = youtubeStudioPanel.x; selectAvatarTxt.y = categoryDescTxt.y + categoryDescTxt.height + 50 + 50; // 7. Avatar images (thumbnails) var channelCoverAssetIds = ["youtubechannelavatar01", "youtubechannelavatar02", "youtubechannelavatar03", "youtubechannelavatar04"]; var selectedChannelCoverIdx = 0; var coverThumbW = 180, coverThumbH = 180, coverThumbSpacing = 48; var coverThumbs = []; var coverThumbY = selectAvatarTxt.y + 50 + coverThumbH / 2; var coverThumbStartX = youtubeStudioPanel.x - (channelCoverAssetIds.length * coverThumbW + (channelCoverAssetIds.length - 1) * coverThumbSpacing) / 2 + coverThumbW / 2; for (var i = 0; i < channelCoverAssetIds.length; i++) { (function (idx) { var assetId = channelCoverAssetIds[idx]; var thumb = LK.getAsset(assetId, { anchorX: 0.5, anchorY: 0.5, x: coverThumbStartX + idx * (coverThumbW + coverThumbSpacing), y: coverThumbY }); thumb.width = coverThumbW; thumb.height = coverThumbH; thumb.interactive = true; thumb.buttonMode = true; thumb.alpha = idx === selectedChannelCoverIdx ? 1 : 0.6; thumb.down = function (x, y, obj) { for (var j = 0; j < coverThumbs.length; j++) coverThumbs[j].alpha = 0.6; thumb.alpha = 1; selectedChannelCoverIdx = idx; }; coverThumbs.push(thumb); })(i); } // 8. Create channel button var confirmYtBtn = new GameButton(); confirmYtBtn.setButton('videoBtn', 'Create Channel', "#fff", 480, 120); if (confirmYtBtn.label && confirmYtBtn.label.style && typeof confirmYtBtn.label.style.size !== "undefined") { confirmYtBtn.label.style.size = 44; confirmYtBtn.label.dirty = true; } else if (confirmYtBtn.label && typeof confirmYtBtn.label.setStyle === "function") { confirmYtBtn.label.setStyle({ size: 44 }); } confirmYtBtn.x = youtubeStudioPanel.x; var maxConfirmBtnY = youtubeStudioPanel.y + panelInnerH / 2 - 80; confirmYtBtn.y = Math.min(coverThumbY + coverThumbH / 2 + 50 + 60 + 50, maxConfirmBtnY); confirmYtBtn.action = function () { if (!channelName || channelName.length < 2) { var errTxt = new Text2("Please enter a channel name!", { size: 54, fill: 0xFF4444, font: "Arial, Helvetica, sans-serif" }); errTxt.anchor.set(0.5, 0.5); errTxt.x = confirmYtBtn.x; errTxt.y = confirmYtBtn.y + 120; game.addChild(errTxt); tween(errTxt, { alpha: 0, y: errTxt.y + 40 }, { duration: 1200, onFinish: function onFinish() { errTxt.destroy(); } }); return; } window.youtubeChannel = { name: channelName, category: ytCategories[selectedYtCategoryIdx], bonus: ytCategoryBonuses[selectedYtCategoryIdx], coverAssetId: channelCoverAssetIds[selectedChannelCoverIdx] }; // Remove creation UI studioTitle.destroy(); channelNameBg.destroy(); channelNameTxt.destroy(); randomNameBtn.destroy(); selectCatTxt.destroy(); categoryDescTxt.destroy(); selectAvatarTxt.destroy(); confirmYtBtn.destroy(); for (var i = 0; i < categoryBtnsYt.length; i++) categoryBtnsYt[i].destroy(); for (var i = 0; i < coverThumbs.length; i++) if (coverThumbs[i]) coverThumbs[i].destroy(); // Show success with selected cover photo var doneTxt = new Text2("Channel created: " + channelName, { size: 64, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); doneTxt.anchor.set(0.5, 0.5); doneTxt.x = youtubeStudioPanel.x; doneTxt.y = youtubeStudioPanel.y - 80; game.addChild(doneTxt); var doneCover = LK.getAsset(channelCoverAssetIds[selectedChannelCoverIdx], { anchorX: 0.5, anchorY: 0.5, x: youtubeStudioPanel.x, y: youtubeStudioPanel.y + 80 }); doneCover.width = 220; doneCover.height = 220; game.addChild(doneCover); tween(doneTxt, { alpha: 0, y: doneTxt.y - 40 }, { duration: 1800, onFinish: function onFinish() { doneTxt.destroy(); doneCover.destroy(); // Remove the panel after animation if (youtubeStudioPanel && typeof youtubeStudioPanel.destroy === "function") { try { youtubeStudioPanel.destroy(); } catch (e) {} youtubeStudioPanel = null; } } }); }; // Add all to game in correct order game.addChild(studioTitle); game.addChild(channelNameBg); game.addChild(channelNameTxt); game.addChild(randomNameBtn); game.addChild(selectCatTxt); for (var i = 0; i < categoryBtnsYt.length; i++) game.addChild(categoryBtnsYt[i]); game.addChild(categoryDescTxt); game.addChild(selectAvatarTxt); for (var i = 0; i < coverThumbs.length; i++) game.addChild(coverThumbs[i]); game.addChild(confirmYtBtn); } } // Show the panel at game start if no channel exists LK.setTimeout(function () { if (!window.youtubeChannel) { showYoutubeStudioPanelAtStart(); } }, 100); // Helper to re-render app overlays in correct order and position function updateAppListOrder() { // Remove all overlays from container while (appListContainer.children.length > 0) { appListContainer.children[0].destroy(); } // Re-add overlays in fixed order, skipping nulls var visibleIdx = 0; for (var i = 0; i < initialApps.length; i++) { var appNameLower = initialApps[i].name; var overlay = appOverlays[appNameLower]; if (overlay) { // Update position for this index (4 per row) var row = Math.floor(visibleIdx / appsPerRow); var col = visibleIdx % appsPerRow; var bgX = col * (appBgW + appSpacing); var bgY = row * (appBgH + appRowSpacing); // Defensive: update all children positions (bg, icon, label) if (overlay._appBg) { overlay._appBg.x = bgX; overlay._appBg.y = bgY; } if (overlay._appIcon) { overlay._appIcon.x = bgX; overlay._appIcon.y = bgY; } if (overlay._appLabel) { overlay._appLabel.x = bgX; overlay._appLabel.y = bgY + appBgH / 2 + 18; } appListContainer.addChild(overlay); visibleIdx++; } } } // Create overlays for all initial apps for (var i = 0; i < initialApps.length; i++) { var appNameLower = initialApps[i].name; var overlay = createAppOverlay(appNameLower, i); appOverlays[appNameLower] = overlay; } // Initial render updateAppListOrder(); // --- Universal Close Button (Return to ComputerScreen) --- var closeAllBtn = new GameButton(); closeAllBtn.setButton('editBtn', 'Return', "#fff", 420, 120); // Place the button below the computerscreen, centered horizontally closeAllBtn.x = computerScreen.x; closeAllBtn.y = computerScreen.y + computerScreen.height / 2 + 210; // 210px below the bottom edge of computerscreen (80+130) closeAllBtn.bg.height += 40; // Increase height by 20px on top and 20px on bottom if (closeAllBtn.label) { closeAllBtn.label.y = 0; // recenter label after height change } // Make the button invisible but always clickable closeAllBtn.bg.alpha = 0; if (closeAllBtn.label) closeAllBtn.label.visible = false; closeAllBtn.interactive = true; closeAllBtn.buttonMode = true; closeAllBtn.action = function () { // Remove all children except: // - computerscreen // - appListContainer (inside computerscreen) // - closeAllBtn // - subIcon, subTxt, viewIcon, viewTxt, moneyIcon, moneyTxt // - timeTxt, pauseBtn, resumeBtn, doubleSpeedBtn // - phoneBg // Prevent closing the channel creation panel if channel is not created if (typeof youtubeStudioPanel !== "undefined" && youtubeStudioPanel && !window.youtubeChannel) { // Do nothing, force user to create a channel return; } for (var i = game.children.length - 1; i >= 0; i--) { var child = game.children[i]; if (child === computerScreen || child === appListContainer || child === closeAllBtn || child === subIcon || child === subTxt || child === viewIcon || child === viewTxt || child === moneyIcon || child === moneyTxt || child === timeTxt || child === pauseBtn || child === resumeBtn || child === doubleSpeedBtn || child === phoneBg || child === studioBg) continue; try { child.destroy(); } catch (e) {} } // Destroy finance panel if open if (typeof financePanel !== "undefined" && financePanel) { try { financePanel.destroy(); } catch (e) {} financePanel = null; } // Hide overlays if they are not destroyed if (typeof videoListBg !== "undefined") videoListBg.visible = false; if (typeof videoListContainer !== "undefined") videoListContainer.visible = false; if (typeof statsOverlay !== "undefined") statsOverlay.visible = false; // Remove playstore overlay and all its children if open if (typeof playStoreOverlay !== "undefined" && playStoreOverlay) { if (playStoreOverlay.children && playStoreOverlay.children.length) { for (var i = playStoreOverlay.children.length - 1; i >= 0; i--) { try { playStoreOverlay.children[i].destroy(); } catch (e) {} } } if (typeof psListContainer !== "undefined" && psListContainer) { if (psListContainer.children && psListContainer.children.length) { for (var i = psListContainer.children.length - 1; i >= 0; i--) { try { psListContainer.children[i].destroy(); } catch (e) {} } } try { psListContainer.destroy(); } catch (e) {} psListContainer = null; } if (playStoreOverlay.children && playStoreOverlay.children.length) { for (var i = playStoreOverlay.children.length - 1; i >= 0; i--) { try { playStoreOverlay.children[i].destroy(); } catch (e) {} } } try { playStoreOverlay.destroy(); } catch (e) {} playStoreOverlay = null; } // Remove edit panel if open var editPanelElements = ["editPanelBg", "editPanelTitle", "loadingBarBg", "loadingBarFill", "editPanelBtn", "closeEditBtn"]; for (var i = 0; i < editPanelElements.length; i++) { if (typeof window[editPanelElements[i]] !== "undefined" && window[editPanelElements[i]]) { try { window[editPanelElements[i]].destroy(); } catch (e) {} window[editPanelElements[i]] = null; } } // Remove edit panel hint and technique hint texts if present if (typeof window.editPanelHintTxt !== "undefined" && window.editPanelHintTxt) { try { window.editPanelHintTxt.destroy(); } catch (e) {} window.editPanelHintTxt = null; } if (typeof window.editTechniqueHintTxt !== "undefined" && window.editTechniqueHintTxt) { try { window.editTechniqueHintTxt.destroy(); } catch (e) {} window.editTechniqueHintTxt = null; } // Remove record panel if open (deduplicated block) if (typeof isRecordPanelOpen !== "undefined" && isRecordPanelOpen) { var recordPanelElements = ["panelBg", "panelText", "confirmBtn", "closeBtn", "titleInputBg", "titleInputTxt", "randomBtn"]; for (var i = 0; i < recordPanelElements.length; i++) { if (typeof window[recordPanelElements[i]] !== "undefined" && window[recordPanelElements[i]]) { try { window[recordPanelElements[i]].destroy(); } catch (e) {} window[recordPanelElements[i]] = null; } } // Destroy all category buttons and trending labels if (typeof categoryBtns !== "undefined" && categoryBtns.length) { for (var i = 0; i < categoryBtns.length; i++) { if (categoryBtns[i]) { if (categoryBtns[i].trendingTxt) { try { categoryBtns[i].trendingTxt.destroy(); } catch (e) {} categoryBtns[i].trendingTxt = null; } try { categoryBtns[i].destroy(); } catch (e) {} } } } isRecordPanelOpen = false; } // Remove promote panel if open if (typeof game.promotePanelOpen !== "undefined" && game.promotePanelOpen) { var promotePanelElements = ["promotePanelBg", "promoteTitle", "moneySliderBg", "moneySliderFill", "moneySliderHandle", "moneyInputTxt", "daysSliderBg", "daysSliderFill", "daysSliderHandle", "daysInputTxt", "estViewsTxt", "confirmPromoteBtn", "closePromoteBtn"]; for (var i = 0; i < promotePanelElements.length; i++) { if (typeof window[promotePanelElements[i]] !== "undefined" && window[promotePanelElements[i]]) { try { window[promotePanelElements[i]].destroy(); } catch (e) {} window[promotePanelElements[i]] = null; } else { window[promotePanelElements[i]] = null; } } // Destroy promote list labels if (typeof promoteListLabels === "undefined") { window.promoteListLabels = []; } if (typeof promoteListLabels !== "undefined" && promoteListLabels.length) { for (var i = 0; i < promoteListLabels.length; i++) { for (var j = 0; j < promoteListLabels[i].length; j++) { if (promoteListLabels[i][j]) { try { promoteListLabels[i][j].destroy(); } catch (e) {} } } } } game.promotePanelOpen = false; } // Remove promote stats panel if open if (typeof game.children !== "undefined") { for (var i = game.children.length - 1; i >= 0; i--) { var child = game.children[i]; if (child && child._isPromoteStatsPanel) { try { child.destroy(); } catch (e) {} } } } }; // Add the button to the game game.addChild(closeAllBtn); // (Removed: duplicate app list alignment code, now handled by appListContainer.x/y and createAppOverlay) // --- Play Store Fullscreen Overlay Logic --- var playStoreOverlay = null; function showPlayStoreOverlay() { if (playStoreOverlay) return; // Overlay background playStoreOverlay = LK.getAsset('playstoreWhiteBg', { anchorX: 0.5, anchorY: 0.5, x: computerScreen.x, y: computerScreen.y }); // Restrict overlay size to exactly match computerscreen playStoreOverlay.width = computerScreen.width; playStoreOverlay.height = computerScreen.height; playStoreOverlay.alpha = 1; // Remove playStoreOverlay if already present (defensive, should not happen) if (game.children.indexOf(playStoreOverlay) !== -1) { playStoreOverlay.destroy(); } // Insert playStoreOverlay so it is always below phoneBg but above computerscreen var phoneBgIdx = game.children.indexOf(phoneBg); var computerScreenIdx = game.children.indexOf(computerScreen); if (phoneBgIdx !== -1 && computerScreenIdx !== -1) { // Insert just before phoneBg, but after computerscreen // phoneBgIdx is the index of phoneBg, so insert at phoneBgIdx (which will be before phoneBg) // But if computerscreen is after phoneBg, adjust to insert after computerscreen var insertIdx = phoneBgIdx; if (computerScreenIdx >= phoneBgIdx) { // If computerscreen is after phoneBg, insert after computerscreen insertIdx = computerScreenIdx + 1; } else if (computerScreenIdx < phoneBgIdx - 1) { // If computerscreen is before phoneBg, but not immediately before, insert just before phoneBg insertIdx = phoneBgIdx; } else { // If computerscreen is immediately before phoneBg, insert at phoneBgIdx (between them) insertIdx = phoneBgIdx; } game.addChildAt(playStoreOverlay, insertIdx); } else if (phoneBgIdx !== -1) { // Fallback: insert just below phoneBg game.addChildAt(playStoreOverlay, phoneBgIdx); } else if (computerScreenIdx !== -1) { // Fallback: insert just above computerscreen game.addChildAt(playStoreOverlay, computerScreenIdx + 1); } else { // Fallback: add to top game.addChild(playStoreOverlay); } // --- Play Store App List Data --- // Each app: { name, description, sizeMB, publisher, installed } var playStoreApps = [{ name: "YouTube", description: "Watch, upload, and share videos with the world.", sizeMB: 120, publisher: "RiftGames", installed: true }, { name: "Editing", description: "Edit your videos with powerful tools.", sizeMB: 95, publisher: "RiftGames", installed: true }, { name: "Statistics", description: "Track your channel's growth and performance.", sizeMB: 40, publisher: "RiftGames", installed: false }, { name: "Promote", description: "Promote your channel to reach more viewers.", sizeMB: 60, publisher: "RiftGames", installed: false }, { name: "Record", description: "Record new videos for your channel.", sizeMB: 80, publisher: "RiftGames", installed: false }, { name: "Finance", description: "Manage your channel's finances and earnings.", sizeMB: 55, publisher: "RiftGames", installed: false }]; // --- Play Store Title Removed as requested --- // --- App List Container --- // The app list container is positioned at (0,0) inside playStoreOverlay, but all its children are positioned as if inside computerscreen var psListContainer = new Container(); // Align app list to top-left of playStoreOverlay, shifted 650px to the left and 1000px upward psListContainer.x = -650; psListContainer.y = -1000; playStoreOverlay.addChild(psListContainer); // --- Make Play Store app list scrollable vertically --- // Variables for scroll state var psListScrollY = psListContainer.y; var psListDragStartY = 0; var psListPointerStartY = 0; var psListDragging = false; var psListMinY = -1000; var psListMaxY = -1000; var psListHeight = 0; // Calculate total height of app list after rendering // (We will update psListHeight after rendering the app cards below) // Touch/drag logic for vertical scrolling playStoreOverlay.interactive = true; playStoreOverlay.buttonMode = false; playStoreOverlay.down = function (x, y, obj) { // Only start drag if inside the app list area var localY = y - playStoreOverlay.y + playStoreOverlay.height / 2; // Accept drag anywhere on overlay for now psListDragging = true; psListPointerStartY = y; psListDragStartY = psListContainer.y; }; playStoreOverlay.move = function (x, y, obj) { if (psListDragging) { var dy = y - psListPointerStartY; var newY = psListDragStartY + dy; // Clamp scroll to min/max if (newY > psListMaxY) newY = psListMaxY; if (newY < psListMinY) newY = psListMinY; psListContainer.y = newY; psListScrollY = newY; } }; playStoreOverlay.up = function (x, y, obj) { psListDragging = false; }; // Also allow scrolling by dragging on the app list container itself psListContainer.interactive = true; psListContainer.buttonMode = false; psListContainer.down = function (x, y, obj) { psListDragging = true; psListPointerStartY = y; psListDragStartY = psListContainer.y; }; psListContainer.move = function (x, y, obj) { if (psListDragging) { var dy = y - psListPointerStartY; var newY = psListDragStartY + dy; if (newY > psListMaxY) newY = psListMaxY; if (newY < psListMinY) newY = psListMinY; psListContainer.y = newY; psListScrollY = newY; } }; psListContainer.up = function (x, y, obj) { psListDragging = false; }; // Helper for global-to-overlay-local positioning function getComputerScreenLocal(x, y) { // Convert a global (game) x/y to local coordinates inside playStoreOverlay, as if overlay is at computerscreen return { x: x - (computerScreen.x - computerScreen.width / 2), y: y - (computerScreen.y - computerScreen.height / 2) }; } var appCardW = computerScreen.width - 160; var appCardH = 320; var appCardSpacing = 40; var iconSize = 160; // --- Determine installed apps from computerscreen --- var installedAppNames = []; for (var key in appOverlays) { if (appOverlays[key]) installedAppNames.push(key); } // --- App List Rendering --- // Only show apps that are not installed as Download, and installed as Delete var filteredPlayStoreApps = []; for (var i = 0; i < playStoreApps.length; i++) { var appNameLower = (playStoreApps[i].name || "").toLowerCase(); var isInstalled = false; for (var j = 0; j < installedAppNames.length; j++) { if (installedAppNames[j] === appNameLower) { isInstalled = true; break; } } // Always show all apps, but set .installed property accordingly playStoreApps[i].installed = isInstalled; filteredPlayStoreApps.push(playStoreApps[i]); } var numApps = filteredPlayStoreApps.length; var totalListHeight = numApps * appCardH + (numApps - 1) * appCardSpacing; for (var i = 0; i < filteredPlayStoreApps.length; i++) { (function (idx) { var app = filteredPlayStoreApps[idx]; // Card background, stack from top-left var cardBg = LK.getAsset('playstoreWhiteBg', { anchorX: 0, anchorY: 0, x: 0, y: idx * (appCardH + appCardSpacing) }); cardBg.width = appCardW; cardBg.height = appCardH; cardBg.alpha = 1; cardBg.tint = 0xffffff; // Always white background for app card psListContainer.addChild(cardBg); // App icon (logo only, no background) var iconAssetId = "youtube"; if (app.name === "Play Store") iconAssetId = "playstore"; if (app.name === "Editing") iconAssetId = "edit"; if (app.name === "Statistics") iconAssetId = "statistics"; if (app.name === "Promote") iconAssetId = "promotebutton"; if (app.name === "Record") iconAssetId = "recordbutton"; if (app.name === "Finance") iconAssetId = "financalbutton"; var appIcon = LK.getAsset(iconAssetId, { anchorX: 0.5, anchorY: 0.5, x: cardBg.x + iconSize / 2 + 36, y: cardBg.y + appCardH / 2 }); appIcon.width = iconSize; appIcon.height = iconSize; psListContainer.addChild(appIcon); // App name var nameTxt = new Text2(app.name, { size: 64, fill: "#222", font: "Arial, Helvetica, sans-serif" }); nameTxt.anchor.set(0, 0); nameTxt.x = cardBg.x + iconSize + 80; nameTxt.y = cardBg.y + 36; psListContainer.addChild(nameTxt); // Publisher var publisherTxt = new Text2("by " + app.publisher, { size: 38, fill: "#888", font: "Arial, Helvetica, sans-serif" }); publisherTxt.anchor.set(0, 0); publisherTxt.x = nameTxt.x; publisherTxt.y = nameTxt.y + nameTxt.height + 2; psListContainer.addChild(publisherTxt); // Description var descTxt = new Text2(app.description, { size: 44, fill: "#444", font: "Arial, Helvetica, sans-serif" }); descTxt.anchor.set(0, 0); descTxt.x = nameTxt.x; descTxt.y = publisherTxt.y + publisherTxt.height + 8; psListContainer.addChild(descTxt); // Size var sizeTxt = new Text2(app.sizeMB + " MB", { size: 38, fill: "#0aa", font: "Arial, Helvetica, sans-serif" }); sizeTxt.anchor.set(0, 0); sizeTxt.x = nameTxt.x; sizeTxt.y = descTxt.y + descTxt.height + 8; psListContainer.addChild(sizeTxt); // Install/Delete/Download button var appBtn = new GameButton(); var isInstalled = !!app.installed; // Helper to update button appearance and action function updateAppBtn() { // Move button lower in the card (move 120px lower than center, was 60px) appBtn.x = cardBg.x + appCardW - 180; appBtn.y = cardBg.y + appCardH / 2 + 120; // Remove previous custom children if any if (appBtn._customBg) { appBtn._customBg.destroy(); appBtn._customBg = null; } if (appBtn._customIcon) { appBtn._customIcon.destroy(); appBtn._customIcon = null; } if (appBtn.label) appBtn.label.visible = false; if (isInstalled) { // DELETE BUTTON: redbackground + deletebutton icon var bg = LK.getAsset('redbackground', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); bg.width = 260; bg.height = 90; appBtn.addChild(bg); appBtn._customBg = bg; var icon = LK.getAsset('deletebutton', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); // Fit icon inside button, keep aspect ratio var scale = Math.min((bg.width - 32) / icon.width, (bg.height - 32) / icon.height, 1); icon.width = icon.width * scale; icon.height = icon.height * scale; appBtn.addChild(icon); appBtn._customIcon = icon; appBtn.setEnabled(true); appBtn.action = function () { isInstalled = false; app.installed = false; updateAppBtn(); // Remove overlay from computerscreen UI var appNameLower = (app.name || "").toLowerCase(); if (appOverlays[appNameLower]) { appListContainer.removeChild(appOverlays[appNameLower]); if (typeof appOverlays[appNameLower].destroy === "function") { appOverlays[appNameLower].destroy(); } appOverlays[appNameLower] = null; // After uninstall, update app list order if (typeof updateAppListOrder === "function") updateAppListOrder(); } }; } else { // DOWNLOAD BUTTON: bluebackground + downloadbutton icon var bg = LK.getAsset('bluebackground', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); bg.width = 260; bg.height = 90; appBtn.addChild(bg); appBtn._customBg = bg; var icon = LK.getAsset('downloadbutton', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); // Fit icon inside button, keep aspect ratio var scale = Math.min((bg.width - 32) / icon.width, (bg.height - 32) / icon.height, 1); icon.width = icon.width * scale; icon.height = icon.height * scale; appBtn.addChild(icon); appBtn._customIcon = icon; appBtn.setEnabled(true); appBtn.action = function () { // Prevent double install if (isInstalled) return; // Show loading bar overlay on the app card var loadingBarBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0.5, x: cardBg.x + appCardW / 2, y: cardBg.y + appCardH - 80 }); loadingBarBg.width = 420; loadingBarBg.height = 48; loadingBarBg.alpha = 0.92; psListContainer.addChild(loadingBarBg); var loadingBarFill = LK.getAsset('loadingbarfull', { anchorX: 0, anchorY: 0.5, x: loadingBarBg.x - loadingBarBg.width / 2 + 4, y: loadingBarBg.y }); loadingBarFill.width = 0; loadingBarFill.height = 36; loadingBarFill.tint = 0x2196f3; // blue psListContainer.addChild(loadingBarFill); // Disable the button during loading appBtn.setEnabled(false); // Animate loading bar fill over 1.2 seconds var loadingDuration = 1200; tween(loadingBarFill, { width: loadingBarBg.width - 8 }, { duration: loadingDuration, easing: tween.cubicOut, onFinish: function onFinish() { // Remove loading bar loadingBarBg.destroy(); loadingBarFill.destroy(); // Actually install the app isInstalled = true; app.installed = true; updateAppBtn(); // Add overlay to computerscreen UI (appListContainer) if not already present var appNameLower = (app.name || "").toLowerCase(); if (!appOverlays[appNameLower]) { var overlay = createAppOverlay(appNameLower, idx); appOverlays[appNameLower] = overlay; } // After install, update app list order if (typeof updateAppListOrder === "function") updateAppListOrder(); } }); }; } // Hide label if button is not enabled (should not show Download/Delete text if not visible) if (!appBtn.enabled && appBtn.label) appBtn.label.visible = false; } // Initial setup updateAppBtn(); psListContainer.addChild(appBtn); })(i); } // --- Set scroll bounds for Play Store app list after rendering --- // The visible area for the app list is the height of playStoreOverlay (== computerscreen.height) psListHeight = totalListHeight; var visibleHeight = playStoreOverlay.height - 120; // 60px margin top/bottom // The minimum y is so the last card is just visible at the bottom psListMinY = Math.min(-1000, -1000 - (psListHeight - visibleHeight)); psListMaxY = -1000; // Topmost position (default) psListContainer.y = psListMaxY; psListScrollY = psListMaxY; } // Add the app list container as a child of computerscreen (so it's visually inside) computerScreen.addChild(appListContainer); // Place the videos, record, edit, promote, and statistics buttons equally at the bottom of the computerscreen, no space between them. // Videos Button removed as requested // Helper to hide video list function hideVideoList() { videoListBg.visible = false; videoListContainer.visible = false; } // (Removed: record, edit, promote, and statistics buttons at the bottom of computerscreen) // --- Time Display --- // Place time text to the right of the money text var timeTxt = new Text2('Day 1, 08:00', { size: 44, fill: 0xFFFFFF }); timeTxt.anchor.set(0, 0.5); // Will be positioned after moneyTxt is created and positioned // --- Video List UI --- // --- Video List UI --- var videoListBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0.5 }); videoListBg.alpha = 0.96; videoListBg.visible = false; // Only visible when video list is shown // Make video panel exactly match computerscreen size and position videoListBg.x = computerScreen.x; videoListBg.y = computerScreen.y; videoListBg.width = computerScreen.width; videoListBg.height = computerScreen.height; game.addChild(videoListBg); var videoListContainer = new Container(); // Place container at top-left inside videoListBg (which matches computerscreen) videoListContainer.x = videoListBg.x - videoListBg.width / 2; videoListContainer.y = videoListBg.y - videoListBg.height / 2; videoListContainer.visible = false; // Only visible when video list is shown game.addChild(videoListContainer); // --- YouTube Studio Publish Panel --- // Helper to show the publish panel for a video function showYoutubeStudioPublishPanel(videoObj) { // Defensive: destroy previous panel if exists if (typeof window.youtubeStudioPublishPanel !== "undefined" && window.youtubeStudioPublishPanel) { try { window.youtubeStudioPublishPanel.destroy(); } catch (e) {} window.youtubeStudioPublishPanel = null; } if (typeof window.youtubeStudioPublishTitle !== "undefined" && window.youtubeStudioPublishTitle) { try { window.youtubeStudioPublishTitle.destroy(); } catch (e) {} window.youtubeStudioPublishTitle = null; } if (typeof window.youtubeStudioPublishInfoTxt !== "undefined" && window.youtubeStudioPublishInfoTxt) { try { window.youtubeStudioPublishInfoTxt.destroy(); } catch (e) {} window.youtubeStudioPublishInfoTxt = null; } if (typeof window.youtubeStudioPublishCatTxt !== "undefined" && window.youtubeStudioPublishCatTxt) { try { window.youtubeStudioPublishCatTxt.destroy(); } catch (e) {} window.youtubeStudioPublishCatTxt = null; } if (typeof window.youtubeStudioPublishDescTitle !== "undefined" && window.youtubeStudioPublishDescTitle) { try { window.youtubeStudioPublishDescTitle.destroy(); } catch (e) {} window.youtubeStudioPublishDescTitle = null; } if (typeof window.youtubeStudioPublishDescSeoBtn !== "undefined" && window.youtubeStudioPublishDescSeoBtn) { try { window.youtubeStudioPublishDescSeoBtn.destroy(); } catch (e) {} window.youtubeStudioPublishDescSeoBtn = null; } if (typeof window.youtubeStudioPublishDescEmojiBtn !== "undefined" && window.youtubeStudioPublishDescEmojiBtn) { try { window.youtubeStudioPublishDescEmojiBtn.destroy(); } catch (e) {} window.youtubeStudioPublishDescEmojiBtn = null; } if (typeof window.youtubeStudioPublishDescHashtagBtn !== "undefined" && window.youtubeStudioPublishDescHashtagBtn) { try { window.youtubeStudioPublishDescHashtagBtn.destroy(); } catch (e) {} window.youtubeStudioPublishDescHashtagBtn = null; } if (typeof window.youtubeStudioPublishCommentsTitle !== "undefined" && window.youtubeStudioPublishCommentsTitle) { try { window.youtubeStudioPublishCommentsTitle.destroy(); } catch (e) {} window.youtubeStudioPublishCommentsTitle = null; } if (typeof window.youtubeStudioPublishCommentsOpenBtn !== "undefined" && window.youtubeStudioPublishCommentsOpenBtn) { try { window.youtubeStudioPublishCommentsOpenBtn.destroy(); } catch (e) {} window.youtubeStudioPublishCommentsOpenBtn = null; } if (typeof window.youtubeStudioPublishCommentsClosedBtn !== "undefined" && window.youtubeStudioPublishCommentsClosedBtn) { try { window.youtubeStudioPublishCommentsClosedBtn.destroy(); } catch (e) {} window.youtubeStudioPublishCommentsClosedBtn = null; } if (typeof window.youtubeStudioPublishPublishTitle !== "undefined" && window.youtubeStudioPublishPublishTitle) { try { window.youtubeStudioPublishPublishTitle.destroy(); } catch (e) {} window.youtubeStudioPublishPublishTitle = null; } if (typeof window.youtubeStudioPublishPremiereBtn !== "undefined" && window.youtubeStudioPublishPremiereBtn) { try { window.youtubeStudioPublishPremiereBtn.destroy(); } catch (e) {} window.youtubeStudioPublishPremiereBtn = null; } if (typeof window.youtubeStudioPublishScheduleBtn !== "undefined" && window.youtubeStudioPublishScheduleBtn) { try { window.youtubeStudioPublishScheduleBtn.destroy(); } catch (e) {} window.youtubeStudioPublishScheduleBtn = null; } if (typeof window.youtubeStudioPublishInstantBtn !== "undefined" && window.youtubeStudioPublishInstantBtn) { try { window.youtubeStudioPublishInstantBtn.destroy(); } catch (e) {} window.youtubeStudioPublishInstantBtn = null; } if (typeof window.youtubeStudioPublishCloseBtn !== "undefined" && window.youtubeStudioPublishCloseBtn) { try { window.youtubeStudioPublishCloseBtn.destroy(); } catch (e) {} window.youtubeStudioPublishCloseBtn = null; } // Panel background window.youtubeStudioPublishPanel = LK.getAsset('studioBg', { anchorX: 0.5, anchorY: 0.5, x: computerScreen.x, y: computerScreen.y }); var panel = window.youtubeStudioPublishPanel; panel.width = computerScreen.width; panel.height = computerScreen.height; panel.alpha = 0.98; var csIdx = game.children.indexOf(computerScreen); if (csIdx !== -1) { game.addChildAt(panel, csIdx + 1); } else { game.addChild(panel); } // Title window.youtubeStudioPublishTitle = new Text2("Publish Video", { size: 90, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); var title = window.youtubeStudioPublishTitle; title.anchor.set(0.5, 0.5); title.x = computerScreen.x; title.y = computerScreen.y - computerScreen.height / 2 + 120; game.addChild(title); // Video Info window.youtubeStudioPublishInfoTxt = new Text2("Video: " + (videoObj.title || "Untitled"), { size: 54, fill: "#ff0", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); var infoTxt = window.youtubeStudioPublishInfoTxt; infoTxt.anchor.set(0.5, 0.5); infoTxt.x = computerScreen.x; infoTxt.y = title.y + title.height / 2 + 30; game.addChild(infoTxt); // Video Category window.youtubeStudioPublishCatTxt = new Text2("Category: " + (videoObj.category || "-"), { size: 44, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); var catTxt = window.youtubeStudioPublishCatTxt; catTxt.anchor.set(0.5, 0.5); catTxt.x = computerScreen.x; catTxt.y = infoTxt.y + infoTxt.height + 10; game.addChild(catTxt); // --- Description Options --- window.youtubeStudioPublishDescTitle = new Text2("Description Options", { size: 48, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); var descTitle = window.youtubeStudioPublishDescTitle; descTitle.anchor.set(0.5, 0.5); descTitle.x = computerScreen.x; descTitle.y = catTxt.y + catTxt.height + 40; game.addChild(descTitle); // SEO Optimization Button window.youtubeStudioPublishDescSeoBtn = new GameButton(); var seoBtn = window.youtubeStudioPublishDescSeoBtn; // Ensure buttons do not overlap and text fits inside buttons var descBtnWidth = 420; var descBtnHeight = 90; var descBtnSpacing = 40; var descBtnFontSize = 38; // SEO Optimization Button seoBtn.setButton('editBtn', 'SEO Optimization', "#fff", descBtnWidth, descBtnHeight); if (seoBtn.label && seoBtn.label.style && typeof seoBtn.label.style.size !== "undefined") { seoBtn.label.style.size = descBtnFontSize; seoBtn.label.dirty = true; } else if (seoBtn.label && typeof seoBtn.label.setStyle === "function") { seoBtn.label.setStyle({ size: descBtnFontSize }); } seoBtn.x = computerScreen.x - (descBtnWidth + descBtnSpacing); seoBtn.y = descTitle.y + 100; seoBtn.action = function () { var txt = new Text2("SEO keywords added!", { size: 44, fill: 0x00FF44, font: "Arial, Helvetica, sans-serif" }); txt.anchor.set(0.5, 0.5); txt.x = seoBtn.x; txt.y = seoBtn.y + 80; game.addChild(txt); tween(txt, { alpha: 0, y: txt.y + 30 }, { duration: 900, onFinish: function onFinish() { txt.destroy(); } }); }; game.addChild(seoBtn); // Emoji Button window.youtubeStudioPublishDescEmojiBtn = new GameButton(); var emojiBtn = window.youtubeStudioPublishDescEmojiBtn; emojiBtn.setButton('editBtn', 'Add Emoji', "#fff", descBtnWidth, descBtnHeight); if (emojiBtn.label && emojiBtn.label.style && typeof emojiBtn.label.style.size !== "undefined") { emojiBtn.label.style.size = descBtnFontSize; emojiBtn.label.dirty = true; } else if (emojiBtn.label && typeof emojiBtn.label.setStyle === "function") { emojiBtn.label.setStyle({ size: descBtnFontSize }); } emojiBtn.x = computerScreen.x; emojiBtn.y = descTitle.y + 100; emojiBtn.action = function () { var txt = new Text2("Emojis added!", { size: 44, fill: 0x00FF44, font: "Arial, Helvetica, sans-serif" }); txt.anchor.set(0.5, 0.5); txt.x = emojiBtn.x; txt.y = emojiBtn.y + 80; game.addChild(txt); tween(txt, { alpha: 0, y: txt.y + 30 }, { duration: 900, onFinish: function onFinish() { txt.destroy(); } }); }; game.addChild(emojiBtn); // Hashtag Button window.youtubeStudioPublishDescHashtagBtn = new GameButton(); var hashtagBtn = window.youtubeStudioPublishDescHashtagBtn; hashtagBtn.setButton('editBtn', 'Add Hashtag', "#fff", descBtnWidth, descBtnHeight); if (hashtagBtn.label && hashtagBtn.label.style && typeof hashtagBtn.label.style.size !== "undefined") { hashtagBtn.label.style.size = descBtnFontSize; hashtagBtn.label.dirty = true; } else if (hashtagBtn.label && typeof hashtagBtn.label.setStyle === "function") { hashtagBtn.label.setStyle({ size: descBtnFontSize }); } hashtagBtn.x = computerScreen.x + (descBtnWidth + descBtnSpacing); hashtagBtn.y = descTitle.y + 100; hashtagBtn.action = function () { var txt = new Text2("Hashtags added!", { size: 44, fill: 0x00FF44, font: "Arial, Helvetica, sans-serif" }); txt.anchor.set(0.5, 0.5); txt.x = hashtagBtn.x; txt.y = hashtagBtn.y + 80; game.addChild(txt); tween(txt, { alpha: 0, y: txt.y + 30 }, { duration: 900, onFinish: function onFinish() { txt.destroy(); } }); }; game.addChild(hashtagBtn); // --- Comments Options --- window.youtubeStudioPublishCommentsTitle = new Text2("Comments", { size: 48, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); var commentsTitle = window.youtubeStudioPublishCommentsTitle; commentsTitle.anchor.set(0.5, 0.5); commentsTitle.x = computerScreen.x; commentsTitle.y = descTitle.y + 200; game.addChild(commentsTitle); // Comments Open Button window.youtubeStudioPublishCommentsOpenBtn = new GameButton(); var commentsOpenBtn = window.youtubeStudioPublishCommentsOpenBtn; // Ensure comment buttons do not overlap and text fits inside buttons var commentBtnWidth = 320; var commentBtnHeight = 90; var commentBtnSpacing = 40; var commentBtnFontSize = 34; commentsOpenBtn.setButton('editBtn', 'Enable Comments', "#fff", commentBtnWidth, commentBtnHeight); if (commentsOpenBtn.label && commentsOpenBtn.label.style && typeof commentsOpenBtn.label.style.size !== "undefined") { commentsOpenBtn.label.style.size = commentBtnFontSize; commentsOpenBtn.label.dirty = true; } else if (commentsOpenBtn.label && typeof commentsOpenBtn.label.setStyle === "function") { commentsOpenBtn.label.setStyle({ size: commentBtnFontSize }); } commentsOpenBtn.x = computerScreen.x - (commentBtnWidth / 2 + commentBtnSpacing / 2); commentsOpenBtn.y = commentsTitle.y + 90; commentsOpenBtn.action = function () { var txt = new Text2("Comments enabled!", { size: 44, fill: 0x00FF44, font: "Arial, Helvetica, sans-serif" }); txt.anchor.set(0.5, 0.5); txt.x = commentsOpenBtn.x; txt.y = commentsOpenBtn.y + 80; game.addChild(txt); tween(txt, { alpha: 0, y: txt.y + 30 }, { duration: 900, onFinish: function onFinish() { txt.destroy(); } }); }; game.addChild(commentsOpenBtn); // Comments Closed Button window.youtubeStudioPublishCommentsClosedBtn = new GameButton(); var commentsClosedBtn = window.youtubeStudioPublishCommentsClosedBtn; commentsClosedBtn.setButton('editBtn', 'Disable Comments', "#fff", commentBtnWidth, commentBtnHeight); if (commentsClosedBtn.label && commentsClosedBtn.label.style && typeof commentsClosedBtn.label.style.size !== "undefined") { commentsClosedBtn.label.style.size = commentBtnFontSize; commentsClosedBtn.label.dirty = true; } else if (commentsClosedBtn.label && typeof commentsClosedBtn.label.setStyle === "function") { commentsClosedBtn.label.setStyle({ size: commentBtnFontSize }); } commentsClosedBtn.x = computerScreen.x + (commentBtnWidth / 2 + commentBtnSpacing / 2); commentsClosedBtn.y = commentsTitle.y + 90; commentsClosedBtn.action = function () { var txt = new Text2("Comments disabled!", { size: 44, fill: 0xFF4444, font: "Arial, Helvetica, sans-serif" }); txt.anchor.set(0.5, 0.5); txt.x = commentsClosedBtn.x; txt.y = commentsClosedBtn.y + 80; game.addChild(txt); tween(txt, { alpha: 0, y: txt.y + 30 }, { duration: 900, onFinish: function onFinish() { txt.destroy(); } }); }; game.addChild(commentsClosedBtn); // --- Publish Options --- window.youtubeStudioPublishPublishTitle = new Text2("Publish Options", { size: 48, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); var publishTitle = window.youtubeStudioPublishPublishTitle; publishTitle.anchor.set(0.5, 0.5); publishTitle.x = computerScreen.x; publishTitle.y = commentsTitle.y + 200; game.addChild(publishTitle); // Premiere Button window.youtubeStudioPublishPremiereBtn = new GameButton(); var premiereBtn = window.youtubeStudioPublishPremiereBtn; // Ensure publish buttons do not overlap and text fits inside buttons var publishBtnWidth = 320; var publishBtnHeight = 110; var publishBtnSpacing = 40; var publishBtnFontSize = 38; // Premiere Button premiereBtn.setButton('videoBtn', 'Premiere', "#fff", publishBtnWidth, publishBtnHeight); if (premiereBtn.label && premiereBtn.label.style && typeof premiereBtn.label.style.size !== "undefined") { premiereBtn.label.style.size = publishBtnFontSize; premiereBtn.label.dirty = true; } else if (premiereBtn.label && typeof premiereBtn.label.setStyle === "function") { premiereBtn.label.setStyle({ size: publishBtnFontSize }); } premiereBtn.x = computerScreen.x - (publishBtnWidth + publishBtnSpacing); premiereBtn.y = publishTitle.y + 100; premiereBtn.action = function () { var txt = new Text2("Video set as Premiere!", { size: 44, fill: 0x00FF44, font: "Arial, Helvetica, sans-serif" }); txt.anchor.set(0.5, 0.5); txt.x = premiereBtn.x; txt.y = premiereBtn.y + 80; game.addChild(txt); tween(txt, { alpha: 0, y: txt.y + 30 }, { duration: 900, onFinish: function onFinish() { txt.destroy(); } }); }; game.addChild(premiereBtn); // Schedule Button window.youtubeStudioPublishScheduleBtn = new GameButton(); var scheduleBtn = window.youtubeStudioPublishScheduleBtn; scheduleBtn.setButton('videoBtn', 'Schedule', "#fff", publishBtnWidth, publishBtnHeight); if (scheduleBtn.label && scheduleBtn.label.style && typeof scheduleBtn.label.style.size !== "undefined") { scheduleBtn.label.style.size = publishBtnFontSize; scheduleBtn.label.dirty = true; } else if (scheduleBtn.label && typeof scheduleBtn.label.setStyle === "function") { scheduleBtn.label.setStyle({ size: publishBtnFontSize }); } scheduleBtn.x = computerScreen.x; scheduleBtn.y = publishTitle.y + 100; scheduleBtn.action = function () { var txt = new Text2("Video scheduled!", { size: 44, fill: 0x00FF44, font: "Arial, Helvetica, sans-serif" }); txt.anchor.set(0.5, 0.5); txt.x = scheduleBtn.x; txt.y = scheduleBtn.y + 80; game.addChild(txt); tween(txt, { alpha: 0, y: txt.y + 30 }, { duration: 900, onFinish: function onFinish() { txt.destroy(); } }); }; game.addChild(scheduleBtn); // Instant Publish Button window.youtubeStudioPublishInstantBtn = new GameButton(); var instantBtn = window.youtubeStudioPublishInstantBtn; instantBtn.setButton('videoBtn', 'Publish Now', "#fff", publishBtnWidth, publishBtnHeight); if (instantBtn.label && instantBtn.label.style && typeof instantBtn.label.style.size !== "undefined") { instantBtn.label.style.size = publishBtnFontSize; instantBtn.label.dirty = true; } else if (instantBtn.label && typeof instantBtn.label.setStyle === "function") { instantBtn.label.setStyle({ size: publishBtnFontSize }); } instantBtn.x = computerScreen.x + (publishBtnWidth + publishBtnSpacing); instantBtn.y = publishTitle.y + 100; instantBtn.action = function () { // Only allow publishing if video is in readyToPublish state if (videoObj.state !== "readyToPublish" || videoObj.publishReady !== true) { var txt = new Text2("You must edit the video before publishing!", { size: 54, fill: 0xFF4444, font: "Arial, Helvetica, sans-serif" }); txt.anchor.set(0.5, 0.5); txt.x = computerScreen.x; txt.y = computerScreen.y; game.addChild(txt); tween(txt, { alpha: 0, y: txt.y - 40 }, { duration: 1200, onFinish: function onFinish() { txt.destroy(); } }); return; } // Actually publish the video videoObj.state = "published"; videoObj.hour = 0; videoObj.publishReady = false; videoObj.finished = false; // Remove panel if (panel) panel.destroy(); if (title) title.destroy(); if (infoTxt) infoTxt.destroy(); if (catTxt) catTxt.destroy(); if (descTitle) descTitle.destroy(); if (seoBtn) seoBtn.destroy(); if (emojiBtn) emojiBtn.destroy(); if (hashtagBtn) hashtagBtn.destroy(); if (commentsTitle) commentsTitle.destroy(); if (commentsOpenBtn) commentsOpenBtn.destroy(); if (commentsClosedBtn) commentsClosedBtn.destroy(); if (publishTitle) publishTitle.destroy(); if (premiereBtn) premiereBtn.destroy(); if (scheduleBtn) scheduleBtn.destroy(); if (instantBtn) instantBtn.destroy(); if (window.youtubeStudioPublishCloseBtn) window.youtubeStudioPublishCloseBtn.destroy(); window.youtubeStudioPublishPanel = null; window.youtubeStudioPublishTitle = null; window.youtubeStudioPublishInfoTxt = null; window.youtubeStudioPublishCatTxt = null; window.youtubeStudioPublishDescTitle = null; window.youtubeStudioPublishDescSeoBtn = null; window.youtubeStudioPublishDescEmojiBtn = null; window.youtubeStudioPublishDescHashtagBtn = null; window.youtubeStudioPublishCommentsTitle = null; window.youtubeStudioPublishCommentsOpenBtn = null; window.youtubeStudioPublishCommentsClosedBtn = null; window.youtubeStudioPublishPublishTitle = null; window.youtubeStudioPublishPremiereBtn = null; window.youtubeStudioPublishScheduleBtn = null; window.youtubeStudioPublishInstantBtn = null; window.youtubeStudioPublishCloseBtn = null; updateVideoLists(); // --- After publishing, only record app is clickable, others animate if tapped --- if (appOverlays) { // Enable only record app, disable editing and youtube studio if (appOverlays["record"]) { appOverlays["record"].interactive = true; appOverlays["record"].buttonMode = true; if (appOverlays["record"]._appBg) appOverlays["record"]._appBg.alpha = 1; if (appOverlays["record"]._appIcon) appOverlays["record"]._appIcon.alpha = 1; if (appOverlays["record"]._appLabel) appOverlays["record"]._appLabel.alpha = 1; } if (appOverlays["editing"]) { appOverlays["editing"].interactive = false; appOverlays["editing"].buttonMode = false; if (appOverlays["editing"]._appBg) appOverlays["editing"]._appBg.alpha = 0.4; if (appOverlays["editing"]._appIcon) appOverlays["editing"]._appIcon.alpha = 0.4; if (appOverlays["editing"]._appLabel) appOverlays["editing"]._appLabel.alpha = 0.4; // Animate youtube studio icon if editing is tapped appOverlays["editing"].down = function (x, y, obj) { if (appOverlays["youtube studio"] && appOverlays["youtube studio"]._appIcon) { var ytStudioIcon = appOverlays["youtube studio"]._appIcon; tween.stop(ytStudioIcon, { scaleX: true, scaleY: true }); tween(ytStudioIcon, { scaleX: 1.3, scaleY: 1.3 }, { duration: 220, easing: tween.cubicOut, onFinish: function onFinish() { tween(ytStudioIcon, { scaleX: 1, scaleY: 1 }, { duration: 220, easing: tween.cubicIn }); } }); } }; if (appOverlays["editing"]._appIcon) appOverlays["editing"]._appIcon.down = appOverlays["editing"].down; if (appOverlays["editing"]._appBg) appOverlays["editing"]._appBg.down = appOverlays["editing"].down; } if (appOverlays["youtube studio"]) { appOverlays["youtube studio"].interactive = false; appOverlays["youtube studio"].buttonMode = false; if (appOverlays["youtube studio"]._appBg) appOverlays["youtube studio"]._appBg.alpha = 0.4; if (appOverlays["youtube studio"]._appIcon) appOverlays["youtube studio"]._appIcon.alpha = 0.4; if (appOverlays["youtube studio"]._appLabel) appOverlays["youtube studio"]._appLabel.alpha = 0.4; // Animate editing icon if youtube studio is tapped appOverlays["youtube studio"].down = function (x, y, obj) { if (appOverlays["editing"] && appOverlays["editing"]._appIcon) { var editingIcon = appOverlays["editing"]._appIcon; tween.stop(editingIcon, { scaleX: true, scaleY: true }); tween(editingIcon, { scaleX: 1.3, scaleY: 1.3 }, { duration: 220, easing: tween.cubicOut, onFinish: function onFinish() { tween(editingIcon, { scaleX: 1, scaleY: 1 }, { duration: 220, easing: tween.cubicIn }); } }); } }; if (appOverlays["youtube studio"]._appIcon) appOverlays["youtube studio"]._appIcon.down = appOverlays["youtube studio"].down; if (appOverlays["youtube studio"]._appBg) appOverlays["youtube studio"]._appBg.down = appOverlays["youtube studio"].down; } } var txt = new Text2("Video published!", { size: 54, fill: 0x00FF44, font: "Arial, Helvetica, sans-serif" }); txt.anchor.set(0.5, 0.5); txt.x = computerScreen.x; txt.y = computerScreen.y; game.addChild(txt); tween(txt, { alpha: 0, y: txt.y - 40 }, { duration: 1200, onFinish: function onFinish() { txt.destroy(); } }); }; game.addChild(instantBtn); } // Helper to update the video list display function updateVideoLists() { // Remove all previous children while (videoListContainer.children.length > 0) { videoListContainer.children[0].destroy(); } if (!window.uploadedVideos || window.uploadedVideos.length === 0) { return; } var squareSize = 340; var spacing = 48; for (var i = 0; i < window.uploadedVideos.length; i++) { var video = window.uploadedVideos[i]; // Calculate row and column for 5 per row var videosPerRow = 5; var row = Math.floor(i / videosPerRow); var col = i % videosPerRow; // Square background var bg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0.5 }); bg.width = squareSize; bg.height = squareSize; bg.x = col * (squareSize + spacing) + squareSize / 2; bg.y = row * (squareSize + spacing) + squareSize / 2; bg.alpha = 0.93; videoListContainer.addChild(bg); // Video name (title) - top of square var nameTxt = new Text2(video.title || "Untitled", { size: 44, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); nameTxt.anchor.set(0.5, 0); nameTxt.x = bg.x; nameTxt.y = bg.y - squareSize / 2 + 18; videoListContainer.addChild(nameTxt); // Views - below name var viewsTxt = new Text2(formatNumber(video.totalViews) + " views", { size: 36, fill: "#0ff", font: "Arial, Helvetica, sans-serif" }); viewsTxt.anchor.set(0.5, 0); viewsTxt.x = bg.x; viewsTxt.y = nameTxt.y + nameTxt.height + 6; videoListContainer.addChild(viewsTxt); // Money earned - below views var moneyDisplay = Math.floor(video.totalMoney * 100) / 100; var moneyTxt = new Text2("$" + formatNumber(moneyDisplay) + " earned", { size: 36, fill: 0xFA4B00, font: "Arial, Helvetica, sans-serif" }); moneyTxt.anchor.set(0.5, 0); moneyTxt.x = bg.x; moneyTxt.y = viewsTxt.y + viewsTxt.height + 2; videoListContainer.addChild(moneyTxt); // Subscribers - below money var subsTxt = new Text2(formatNumber(video.totalSubs) + " subs", { size: 36, fill: 0xFFE066, font: "Arial, Helvetica, sans-serif" }); subsTxt.anchor.set(0.5, 0); subsTxt.x = bg.x; subsTxt.y = moneyTxt.y + moneyTxt.height + 2; videoListContainer.addChild(subsTxt); // Status - below subs // (Removed: status text such as Just Published, Gaining Views, Finished) // --- Loading Bar (progress for edit/record/publish) --- var showBar = false; var barProgress = 0; var barLabel = ""; if (video.state === "recorded" && !video.finished && typeof video.editHoursLeft === "number" && video.editHoursLeft > 0) { // Editing in progress or ready to edit showBar = true; // If currently editing, show progress if (timeProcess && timeProcess.type === "edit" && timeProcess.video === video) { barProgress = 1 - timeProcess.hoursLeft / (timeProcess.total || 1); barLabel = "Editing..."; } else { barProgress = 0; barLabel = "Ready to Edit"; } } else if (video.state === "readyToPublish" && !video.finished) { // Ready to publish, no progress bar needed showBar = true; barProgress = 1; barLabel = "Ready to Publish"; } else if (video.state === "published" && !video.finished && typeof video.totalHours === "number" && video.totalHours > 0) { // Gaining views (publishing progress) // Fill the bar over 7 days (168 hours) showBar = true; var publishTotal = 7 * 24; barProgress = Math.min(1, video.hour / publishTotal); barLabel = "Publishing..."; } else if (video.state === "recording" && !video.finished && typeof video.recordHoursLeft === "number" && video.recordHoursLeft > 0) { // Recording in progress showBar = true; if (timeProcess && timeProcess.type === "record" && timeProcess.video === video) { barProgress = 1 - timeProcess.hoursLeft / (timeProcess.total || 1); barLabel = "Recording..."; } else { barProgress = 1 - video.recordHoursLeft / (video.totalRecordHours || 1); barLabel = "Recording..."; } } if (showBar) { // Bar background var barBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0 }); barBg.width = squareSize - 40; barBg.height = 36; barBg.x = bg.x; barBg.y = nameTxt.y + nameTxt.height + viewsTxt.height + moneyTxt.height + subsTxt.height + 18; barBg.alpha = 0.85; videoListContainer.addChild(barBg); // Bar fill var barFill = LK.getAsset('loadingbarfull', { anchorX: 0, anchorY: 0 }); // Animate barFill width smoothly using tween, starting from current width var targetBarWidth = (squareSize - 44) * Math.max(0, Math.min(1, barProgress)); if (typeof video.barLastWidth === "undefined") { video.barLastWidth = 0; } barFill.width = video.barLastWidth; barFill.height = 28; barFill.x = barBg.x - barBg.width / 2 + 2; barFill.y = barBg.y + 4; barFill.alpha = 0.95; videoListContainer.addChild(barFill); // Only animate if the target width is different from the last width if (Math.abs(targetBarWidth - video.barLastWidth) > 1) { tween(barFill, { width: targetBarWidth }, { duration: 400, easing: tween.cubicOut, onUpdate: function onUpdate() { video.barLastWidth = barFill.width; }, onFinish: function onFinish() { video.barLastWidth = targetBarWidth; } }); } else { barFill.width = targetBarWidth; video.barLastWidth = targetBarWidth; } // Bar label var barTxt = new Text2(barLabel, { size: 28, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); barTxt.anchor.set(0.5, 0.5); barTxt.x = barBg.x; barTxt.y = barBg.y + barBg.height / 2; videoListContainer.addChild(barTxt); } // Optionally, trending badge (top of square, above name) if (video.trending) { var trendingTxt = new Text2("Trending", { size: 32, fill: "#ff0", font: "Arial, Helvetica, sans-serif" }); trendingTxt.anchor.set(0.5, 1); trendingTxt.x = bg.x; trendingTxt.y = bg.y - squareSize / 2 + 8; videoListContainer.addChild(trendingTxt); } // --- Edit and Publish Buttons --- // Only show publish button if video is ready to publish and not finished if (video.state === "readyToPublish" && video.publishReady && !video.finished) { var publishBtn = new GameButton(); publishBtn.setButton('videoBtn', '', "#fff", 180, 80); // Make the publish text smaller var publishLabel = new Text2('Publish', { size: 44, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); publishLabel.anchor.set(0.5, 0.5); publishLabel.x = 0; publishLabel.y = 0; publishBtn.addChild(publishLabel); // Place the publish button at the bottom center of the video's background publishBtn.x = bg.x; publishBtn.y = bg.y + bg.height / 2 - publishBtn.bg.height / 2 - 10; publishBtn.action = function (vidIdx) { return function () { // Open YouTube Studio publish panel for this video showYoutubeStudioPublishPanel(window.uploadedVideos[vidIdx]); }; }(i); videoListContainer.addChild(publishBtn); // --- Show YouTube Studio publish panel features immediately for this video --- showYoutubeStudioPublishPanel(video); } // Only show publish button if video is ready to publish and not finished // (Removed duplicate publish button block) } } // --- Pause/Resume/Double Speed Buttons --- // Track time speed: 0 = paused, 1 = normal, 2 = double // Start with time paused and pause button active by default var timeSpeed = 0; isTimePaused = true; // Pause button var pauseBtn = new GameButton(); pauseBtn.setButton('pauseicon', '', "#fff", 54, 54); pauseBtn.action = function () { if (timeSpeed !== 0) { timeSpeed = 0; isTimePaused = true; updateTimeControlButtons(); } }; // Resume button (1x) var resumeBtn = new GameButton(); resumeBtn.setButton('resumeicon', '', "#fff", 54, 54); resumeBtn.action = function () { if (timeSpeed !== 1) { timeSpeed = 1; isTimePaused = false; updateTimeControlButtons(); } }; // Double speed button (2x) var doubleSpeedBtn = new GameButton(); doubleSpeedBtn.setButton('doublespeedicon', '', "#fff", 108, 108); doubleSpeedBtn.action = function () { if (timeSpeed !== 2) { timeSpeed = 2; isTimePaused = false; updateTimeControlButtons(); } }; // Helper to update button enabled/disabled state and highlight function updateTimeControlButtons() { // Highlight the selected speed, dim others pauseBtn.setEnabled(timeSpeed !== 0 ? true : false); resumeBtn.setEnabled(timeSpeed !== 1 ? true : false); doubleSpeedBtn.setEnabled(timeSpeed !== 2 ? true : false); // Optionally, visually highlight the active button pauseBtn.bg.alpha = timeSpeed === 0 ? 1 : 0.6; resumeBtn.bg.alpha = timeSpeed === 1 ? 1 : 0.6; doubleSpeedBtn.bg.alpha = timeSpeed === 2 ? 1 : 0.6; } // Initial highlight updateTimeControlButtons(); // --- Position time text and pause/resume/double speed buttons to the right of the money text --- // This must be done after moneyTxt is created and positioned, so move this block after moneyTxt and icons are created and layoutCountersRow() is called. // --- Counter Row Display (subscribers, viewers, money) --- // Helper to position counters/icons in a row, matching the viewer counter/icon position function layoutCountersRow() { var counterY = 160; var centerX = 2048 / 2; var iconSpacing = 420; // Subscribers (left, further left) subIcon.x = centerX - iconSpacing * 1.7; subIcon.y = counterY; subTxt.x = subIcon.x + 70; subTxt.y = subIcon.y; // Viewers (shifted further left from center) viewIcon.x = centerX - iconSpacing * 0.9; viewIcon.y = counterY; viewTxt.x = viewIcon.x + 70; viewTxt.y = viewIcon.y; // Money (move further left) moneyIcon.x = centerX + iconSpacing * 0.1; moneyIcon.y = counterY; moneyTxt.x = moneyIcon.x + 70; moneyTxt.y = moneyIcon.y; } // Create icons and text objects var subIcon = LK.getAsset('subIcon', { anchorX: 0.5, anchorY: 0.5 }); var subTxt = new Text2('0', { size: 64, fill: 0xFFFFFF }); subTxt.anchor.set(0, 0.5); var viewIcon = LK.getAsset('viewersicon', { anchorX: 0.5, anchorY: 0.5 }); var viewTxt = new Text2('0', { size: 64, fill: 0x00e0ff }); viewTxt.anchor.set(0, 0.5); var moneyIcon = LK.getAsset('moneyIcon', { anchorX: 0.5, anchorY: 0.5 }); var moneyTxt = new Text2('0', { size: 64, fill: 0xFFE066 }); moneyTxt.anchor.set(0, 0.5); // Add all counters and icons to the game (ensure visible) game.addChild(subIcon); game.addChild(subTxt); game.addChild(viewIcon); game.addChild(viewTxt); game.addChild(moneyIcon); game.addChild(moneyTxt); // Initial layout layoutCountersRow(); // --- Position day-time and time control buttons to top center inside computerscreen --- // Calculate top center inside computerscreen, then shift 100px left var topCenterY = computerScreen.y - computerScreen.height / 2 + 70; // 70px margin from top edge var topCenterX = computerScreen.x - 100; // shift 100px left // Place timeTxt at shifted top center timeTxt.anchor.set(0.5, 0.5); timeTxt.x = topCenterX; timeTxt.y = topCenterY; // Place pause, resume, and double speed buttons to the right of timeTxt, horizontally aligned var btnSpacing = 32; pauseBtn.x = timeTxt.x + timeTxt.width / 2 + btnSpacing + pauseBtn.bg.width / 2; pauseBtn.y = timeTxt.y; resumeBtn.x = pauseBtn.x + pauseBtn.bg.width / 2 + btnSpacing + resumeBtn.bg.width / 2; resumeBtn.y = timeTxt.y; doubleSpeedBtn.x = resumeBtn.x + resumeBtn.bg.width / 2 + btnSpacing + doubleSpeedBtn.bg.width / 2; doubleSpeedBtn.y = timeTxt.y; // Add to game after positioning (ensure visible) game.addChild(timeTxt); game.addChild(pauseBtn); game.addChild(resumeBtn); game.addChild(doubleSpeedBtn); // --- Action Buttons --- // Button layout: stack vertically, bigger, with spacing var btnW = 540; var btnH = 220; var btnSpacingY = 60; var btnStartY = 900; // Make Video Button var makeVideoBtn = new GameButton(); makeVideoBtn.setButton('videoBtn', 'Record Video', "#fff", btnW, btnH); makeVideoBtn.x = 2048 / 2; // Move the record video button further down to fill the space of removed buttons // Move the record video button 250 pixels higher makeVideoBtn.y = btnStartY + 3 * (btnH + btnSpacingY) - 250; // --- Loading Bar for Process --- // (Removed: processBarBg and processBarFill, and their show/hide functions.) // No independent loading bar on the main screen. // --- Action Button Logic (time-based) --- // Track if record video panel is open var isRecordPanelOpen = false; makeVideoBtn.action = function () { if (timeProcess) { return; } // Only one process at a time // Block recording if a video is in 'recorded' state and not finished (must edit first) if (window.uploadedVideos) { for (var i = 0; i < window.uploadedVideos.length; i++) { if (window.uploadedVideos[i].state === "recorded" && !window.uploadedVideos[i].finished) { // Optionally, show a message or flash the edit button // Use the Editing app icon as the editBtn for animation var editBtn = appOverlays && appOverlays["editing"] && appOverlays["editing"]._appIcon ? appOverlays["editing"]._appIcon : null; if (editBtn) { tween(editBtn, { scaleX: 1.15, scaleY: 1.15 }, { duration: 100, onFinish: function onFinish() { tween(editBtn, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); } return; } } } if (isRecordPanelOpen) { return; } // Prevent multiple panels isRecordPanelOpen = true; // Show a panel before starting the process // Place the record panel visually to exactly match computerscreen var panelBg = LK.getAsset('studioBg', { anchorX: 0.5, anchorY: 0.5 }); // Set panel size and position to exactly match computerscreen panelBg.width = computerScreen.width; panelBg.height = computerScreen.height; panelBg.x = computerScreen.x; panelBg.y = computerScreen.y; panelBg.alpha = 0.98; // Ensure panelBg is above computerscreen in the display list var csIdx = game.children.indexOf(computerScreen); if (csIdx !== -1) { // Insert panelBg just above computerscreen game.addChildAt(panelBg, csIdx + 1); } else { game.addChild(panelBg); } // --- Panel Title --- var panelText = new Text2("Select Category & Title", { size: 90, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); panelText.anchor.set(0.5, 0.5); panelText.x = panelBg.x; panelText.y = panelBg.y - panelBg.height / 2 + 120; // near top of panel // --- Video Title Input --- var titleInputBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0.5 }); titleInputBg.width = 1000; titleInputBg.height = 130; titleInputBg.x = panelBg.x - 180; // shift left to make space for random button titleInputBg.y = panelText.y + 200; // more space below title titleInputBg.alpha = 0.92; var videoTitle = ""; var titleInputTxt = new Text2("Enter video title...", { size: 72, fill: "#fff", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); titleInputTxt.anchor.set(0.5, 0.5); titleInputTxt.x = titleInputBg.x; titleInputTxt.y = titleInputBg.y; // Simulate input: tap to edit, prompt for text titleInputBg.down = function (x, y, obj) { var prompt = LK.prompt ? LK.prompt : window.prompt; // fallback for dev var val = prompt ? prompt("Enter video title:", videoTitle) : ""; if (typeof val === "string" && val.length > 0) { videoTitle = val; titleInputTxt.setText(videoTitle); } }; // --- Random Title Button --- var randomBtn = new GameButton(); randomBtn.setButton('promoteBtn', 'Random', "#fff", 340, 120); randomBtn.x = titleInputBg.x + titleInputBg.width / 2 + 200; // right of input with space randomBtn.y = titleInputBg.y; randomBtn.action = function () { // Titles per category var categoryTitles = { "Vlog": ["My Daily Vlog", "Life Update", "A Day in My Life", "Morning Routine", "Evening Recap"], "Challenge": ["Epic Challenge!", "24 Hour Challenge", "Impossible Task!", "Last To Leave", "Extreme Challenge"], "Reaction": ["Reacting to Comments", "Reacting to Viral Videos", "First Time Watching", "Fan Reactions", "Surprising Reactions"], "Tutorial": ["How To Edit Videos", "Beginner's Guide", "Pro Tips & Tricks", "Step by Step Tutorial", "Easy DIY"], "Unboxing": ["Unboxing Surprise", "Mystery Box Unboxing", "Tech Unboxing", "Unboxing Haul", "First Impressions"], "Gaming": ["Let's Play!", "Epic Gaming Moments", "Game Review", "Speedrun Attempt", "Funny Gaming Fails"], "Music": ["My New Song", "Music Cover", "Behind the Music", "Songwriting Session", "Live Performance"], "Comedy": ["Funny Moments", "Comedy Skit", "Prank Video", "Try Not To Laugh", "Bloopers & Outtakes"], "Q&A": ["Q&A Special", "Answering Your Questions", "Ask Me Anything", "Subscriber Q&A", "Get To Know Me"] }; var cat = videoCategories[selectedCategoryIdx]; var titles = categoryTitles[cat] || ["My Daily Vlog", "Epic Challenge!", "Reacting to Comments", "24 Hours in My Studio", "Behind the Scenes", "Q&A Special", "Trying Viral Trends", "Unboxing Surprise", "Life Update", "Funny Moments"]; var idx = Math.floor(Math.random() * titles.length); videoTitle = titles[idx]; titleInputTxt.setText(videoTitle); }; // --- Video Category Buttons --- var categoryBtnW = 340; var categoryBtnH = 120; var categoryBtnSpacingX = 40; var categoryBtnSpacingY = 40; var categoryBtns = []; // Layout: fit as many as possible per row, then wrap var maxRowWidth = panelBg.width - 120; // leave some margin var maxPerRow = Math.floor((maxRowWidth + categoryBtnSpacingX) / (categoryBtnW + categoryBtnSpacingX)); if (maxPerRow < 1) { maxPerRow = 1; } var startX = panelBg.x - (Math.min(maxPerRow, videoCategories.length) * (categoryBtnW + categoryBtnSpacingX) - categoryBtnSpacingX) / 2 + categoryBtnW / 2; var startY = titleInputBg.y + 220; // more space below input+random for (var i = 0; i < videoCategories.length; i++) { (function (idx) { var btn = new GameButton(); btn.setButton('editBtn', videoCategories[idx], "#fff", categoryBtnW, categoryBtnH); var row = Math.floor(idx / maxPerRow); var col = idx % maxPerRow; btn.x = startX + col * (categoryBtnW + categoryBtnSpacingX); btn.y = startY + row * (categoryBtnH + categoryBtnSpacingY); btn.action = function () { // Deselect all for (var j = 0; j < categoryBtns.length; j++) { // If trending, keep its highlight if (j === trendingCategoryIdx) { categoryBtns[j].bg.alpha = 0.95; } else { categoryBtns[j].bg.alpha = 0.7; } } btn.bg.alpha = 1; selectedCategoryIdx = idx; }; // Highlight the first by default if (i === 0) { btn.bg.alpha = 1; } else { btn.bg.alpha = 0.7; } // Mark trending category visually if (i === trendingCategoryIdx) { btn.bg.alpha = 0.95; // Add a "Trending" label above the button var trendingTxt = new Text2("🔥 Trending", { size: 48, fill: "#ff0", font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); trendingTxt.anchor.set(0.5, 1); trendingTxt.x = btn.x; trendingTxt.y = btn.y - categoryBtnH / 2 - 10; btn.trendingTxt = trendingTxt; } categoryBtns.push(btn); })(i); } // --- Confirm/Record Button --- var confirmBtn = new GameButton(); // Make the button smaller and move it 50px up confirmBtn.setButton('videoBtn', 'Record', "#fff", 480, 130); confirmBtn.x = panelBg.x; // Find the bottom Y of the last category button for spacing var lastCategoryBtn = categoryBtns[categoryBtns.length - 1]; var categoryBtnsBottomY = lastCategoryBtn ? lastCategoryBtn.y + categoryBtnH / 2 : startY + categoryBtnH / 2; confirmBtn.y = categoryBtnsBottomY + 150; // 50px higher than before confirmBtn.action = function () { // Remove panel panelBg.destroy(); panelText.destroy(); confirmBtn.destroy(); titleInputBg.destroy(); titleInputTxt.destroy(); randomBtn.destroy(); // Hide all category buttons and trending labels immediately for (var i = 0; i < categoryBtns.length; i++) { if (categoryBtns[i].trendingTxt) { categoryBtns[i].trendingTxt.visible = false; } categoryBtns[i].visible = false; } // Destroy all category buttons for (var i = 0; i < categoryBtns.length; i++) { // Destroy trending label if exists if (categoryBtns[i].trendingTxt) { categoryBtns[i].trendingTxt.destroy(); } categoryBtns[i].destroy(); } isRecordPanelOpen = false; // --- Add video to list immediately, in 'recording' state, before recording starts --- if (!window.uploadedVideos) { window.uploadedVideos = []; } // Store last recorded video info for edit panel window.lastRecordedVideo = { title: videoTitle, category: videoCategories[selectedCategoryIdx] }; var videoObj = { title: videoTitle, category: videoCategories[selectedCategoryIdx], hour: 0, totalHours: 7 * 24, totalViews: 0, totalMoney: 0, totalSubs: 0, trending: videoCategories[selectedCategoryIdx] === videoCategories[trendingCategoryIdx], baseSubscribers: subscribers, finished: false, state: "recording", // <--- show as recording recordHoursLeft: 3, totalRecordHours: 3, // new: states are "recording", "recorded", "editing", "readyToPublish", "published" editHoursLeft: 5, publishReady: false }; // --- Animate editing app icon and disable record button --- if (appOverlays && appOverlays["editing"] && appOverlays["editing"]._appIcon) { var editingIcon = appOverlays["editing"]._appIcon; // Defensive: stop any previous tweens on scale tween.stop(editingIcon, { scaleX: true, scaleY: true }); // Disable record button if (typeof makeVideoBtn !== "undefined" && makeVideoBtn && typeof makeVideoBtn.setEnabled === "function") { makeVideoBtn.setEnabled(false); } // Animate: scale up, then down, then re-enable record button tween(editingIcon, { scaleX: 1.3, scaleY: 1.3 }, { duration: 220, easing: tween.cubicOut, onFinish: function onFinish() { tween(editingIcon, { scaleX: 1, scaleY: 1 }, { duration: 220, easing: tween.cubicIn, onFinish: function onFinish() { // Re-enable record button after animation if (typeof makeVideoBtn !== "undefined" && makeVideoBtn && typeof makeVideoBtn.setEnabled === "function") { makeVideoBtn.setEnabled(true); } } }); } }); } // --- Enable Editing app icon after a video is recorded --- if (appOverlays && appOverlays["editing"]) { appOverlays["editing"].interactive = true; appOverlays["editing"].buttonMode = true; if (appOverlays["editing"]._appBg) appOverlays["editing"]._appBg.alpha = 1; if (appOverlays["editing"]._appIcon) appOverlays["editing"]._appIcon.alpha = 1; if (appOverlays["editing"]._appLabel) appOverlays["editing"]._appLabel.alpha = 1; // Also enable the icon and bg for direct interaction if (appOverlays["editing"]._appIcon) { appOverlays["editing"]._appIcon.interactive = true; appOverlays["editing"]._appIcon.buttonMode = true; } if (appOverlays["editing"]._appBg) { appOverlays["editing"]._appBg.interactive = true; appOverlays["editing"]._appBg.buttonMode = true; } // Patch: after recording, clicking the editing app icon opens the edit panel (no animation) appOverlays["editing"].down = function (x, y, obj) { // Always call overlayDown to open the edit panel if a video is in 'recorded' state if (typeof appOverlays["editing"].overlayDown === "function") { appOverlays["editing"].overlayDown(x, y, obj); } }; if (appOverlays["editing"]._appIcon) appOverlays["editing"]._appIcon.down = appOverlays["editing"].down; if (appOverlays["editing"]._appBg) appOverlays["editing"]._appBg.down = appOverlays["editing"].down; } // Precompute total views to distribute realistically over 7 days var minViewPercent = 0.01; var maxViewPercent = 0.05; var percent = minViewPercent + Math.random() * (maxViewPercent - minViewPercent); var baseViews = Math.floor(videoObj.baseSubscribers * percent); if (videoObj.baseSubscribers < 100) { baseViews = 100 + Math.floor(Math.random() * 400); } if (videoObj.trending) { baseViews = Math.floor(baseViews * 1.5); } videoObj.targetViews = baseViews; videoObj.targetMoney = Math.floor(baseViews / 1000 * (3 + Math.random() * 2)); videoObj.targetSubs = Math.floor(baseViews / (200 + Math.floor(Math.random() * 101))); videoObj.hourlyViews = []; // Distribute views per hour: more at start, less at end (decay curve) var decay = 0.012; // controls how fast views drop off var total = 0; for (var h = 0; h < videoObj.totalHours; h++) { var rel = h / videoObj.totalHours; var hourViews = Math.max(1, Math.round(baseViews * Math.exp(-decay * h))); videoObj.hourlyViews.push(hourViews); total += hourViews; } // Normalize to match targetViews var scale = baseViews / total; for (var h = 0; h < videoObj.hourlyViews.length; h++) { videoObj.hourlyViews[h] = Math.floor(videoObj.hourlyViews[h] * scale); } window.uploadedVideos.push(videoObj); videoCount += 1; updateStats(); updateVideoLists(); // Start the process timeProcess = { type: 'record', hoursLeft: 3, total: 3, category: videoCategories[selectedCategoryIdx], title: videoTitle, video: videoObj, onFinish: function onFinish() { LK.getSound('makeVideo').play(); // Mark video as recorded, ready for editing videoObj.state = "recorded"; videoObj.recordHoursLeft = 0; updateVideoLists(); // Animate button tween(makeVideoBtn, { scaleX: 1.1, scaleY: 1.1 }, { duration: 80, onFinish: function onFinish() { tween(makeVideoBtn, { scaleX: 1, scaleY: 1 }, { duration: 80 }); } }); // Removed winning condition at 1000 subscribers; game continues forever } }; // Removed call to undefined showProcessBar(0) }; // --- Close (X) Button --- // Add all panel elements to game game.addChild(panelBg); game.addChild(panelText); game.addChild(titleInputBg); game.addChild(titleInputTxt); game.addChild(randomBtn); // (closeBtn removed) // Add all category buttons for (var i = 0; i < categoryBtns.length; i++) { game.addChild(categoryBtns[i]); // If trending label exists, add it to game if (categoryBtns[i].trendingTxt) { game.addChild(categoryBtns[i].trendingTxt); } } game.addChild(confirmBtn); }; // (Removed: makeVideoBtn from main screen, now triggered by recordVideoBtn next to videos button) // (Removed: manual y-positioning of subIcon/subTxt and moneyIcon/moneyTxt; handled by layoutCountersRow) // Removed undefined energyBar and energyTxt // --- GUI: Timer/Score (use subscribers as score) --- // Removed giant numbers next to the subscriber counter // --- Helper Functions --- function formatNumber(num) { if (num < 1000) { return "" + num; } if (num < 1000000) { var k = num / 1000; if (k % 1 === 0) { return k + "k"; } return k.toFixed(1).replace(/\.0$/, "") + "k"; } var m = num / 1000000; if (m % 1 === 0) { return m + "m"; } return m.toFixed(1).replace(/\.0$/, "") + "m"; } function updateStats() { // --- Helper for green increase text --- function showGreenIncrease(textObj, increase, prefix) { if (!increase || increase <= 0) { return; } var plusText = new Text2("+" + formatNumber(increase), { size: 48, fill: 0x00FF44, font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 8, dropShadowDistance: 2 }); plusText.anchor.set(0, 0.5); // Place to the right of the number plusText.x = textObj.x + textObj.width + 16; plusText.y = textObj.y; game.addChild(plusText); tween(plusText, { y: plusText.y - 40, alpha: 0 }, { duration: 1200, easing: tween.cubicOut, onFinish: function onFinish() { plusText.destroy(); } }); } // Subscribers if (typeof updateStats.lastSubValue !== "number") { updateStats.lastSubValue = subscribers; } var subIncrease = subscribers - updateStats.lastSubValue; subTxt.setText(formatNumber(subscribers)); if (subIncrease > 0) { showGreenIncrease(subTxt, subIncrease, ""); } updateStats.lastSubValue = subscribers; // Views if (typeof updateStats.lastViewValue !== "number") { updateStats.lastViewValue = viewCount; } var viewIncrease = viewCount - updateStats.lastViewValue; viewTxt.setText(formatNumber(viewCount)); if (viewIncrease > 0) { showGreenIncrease(viewTxt, viewIncrease, ""); } updateStats.lastViewValue = viewCount; // Money if (typeof updateStats.lastMoneyValue !== "number") { updateStats.lastMoneyValue = money; } var moneyIncrease = money - updateStats.lastMoneyValue; // Truncate money to 2 decimal digits for display var moneyDisplay = Math.floor(money * 100) / 100; moneyTxt.setText(formatNumber(moneyDisplay)); if (moneyIncrease > 0) { // Truncate moneyIncrease to 2 decimal digits for display var moneyIncreaseDisplay = Math.floor(moneyIncrease * 100) / 100; showGreenIncrease(moneyTxt, moneyIncreaseDisplay, ""); } updateStats.lastMoneyValue = money; // If financePanel is open, update its money display if (typeof financePanel !== "undefined" && financePanel && typeof financePanel.updateMoney === "function") { financePanel.updateMoney(); } // Enable/disable buttons based on process and resources makeVideoBtn.setEnabled(!timeProcess); // --- Achievements --- if (!updateStats.milestones) { updateStats.milestones = {}; } // Subscriber milestones var milestones = [10, 25, 50, 100, 250, 500, 750, 1000, 2500, 5000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000]; for (var i = 0; i < milestones.length; i++) { var m = milestones[i]; if (subscribers >= m && !updateStats.milestones["subs" + m]) { updateStats.milestones["subs" + m] = true; var ach = new Text2("Milestone: " + m + " Subs!", { size: 110, fill: "#ff0", stroke: "#000", strokeThickness: 12, font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 12, dropShadowDistance: 4 }); ach.anchor.set(0.5, 0.5); ach.x = 2048 / 2; ach.y = 400 + i * 80; game.addChild(ach); tween(ach, { alpha: 0, y: ach.y - 100 }, { duration: 1800, onFinish: function onFinish() { ach.destroy(); } }); } } // View milestones var viewMilestones = [1000, 5000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000, 5000000, 10000000]; for (var i = 0; i < viewMilestones.length; i++) { var m = viewMilestones[i]; if (viewCount >= m && !updateStats.milestones["views" + m]) { updateStats.milestones["views" + m] = true; var ach = new Text2("Milestone: " + formatNumber(m) + " Views!", { size: 110, fill: 0x00E0FF, stroke: "#000", strokeThickness: 12, font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 12, dropShadowDistance: 4 }); ach.anchor.set(0.5, 0.5); ach.x = 2048 / 2; ach.y = 400 + (i + milestones.length) * 80; game.addChild(ach); tween(ach, { alpha: 0, y: ach.y - 100 }, { duration: 1800, onFinish: function onFinish() { ach.destroy(); } }); } } // Money milestones var moneyMilestones = [100, 500, 1000, 5000, 10000, 25000, 50000, 100000, 250000, 500000, 1000000]; for (var i = 0; i < moneyMilestones.length; i++) { var m = moneyMilestones[i]; if (money >= m && !updateStats.milestones["money" + m]) { updateStats.milestones["money" + m] = true; var ach = new Text2("Milestone: $" + formatNumber(m) + " Earned!", { size: 110, fill: 0xFA4B00, stroke: "#000", strokeThickness: 12, font: "Arial, Helvetica, sans-serif", dropShadow: true, dropShadowColor: "#222", dropShadowBlur: 12, dropShadowDistance: 4 }); ach.anchor.set(0.5, 0.5); ach.x = 2048 / 2; ach.y = 400 + (i + milestones.length + viewMilestones.length) * 80; game.addChild(ach); tween(ach, { alpha: 0, y: ach.y - 100 }, { duration: 1800, onFinish: function onFinish() { ach.destroy(); } }); } } } // --- Video List UI Update --- // --- Time Update --- function updateTimeDisplay() { var h = gameHour; var m = gameMinute; var hStr = (h < 10 ? "0" : "") + h; var mStr = (m < 10 ? "0" : "") + m; timeTxt.setText("Day " + gameDay + ", " + hStr + ":" + mStr); } // --- Process Update --- function updateProcessBar() { // No independent loading bar on the main screen. } // --- Time Timer --- if (timeTimer) { LK.clearInterval(timeTimer); } // Helper function to process one minute of time advancement function processOneMinute() { gameMinute += 1; if (gameMinute >= 60) { gameMinute = 0; gameHour += 1; if (gameHour >= 24) { gameHour = 0; gameDay += 1; // Record daily stats exactly once per day recordDailyStats(); // Check if it's time to change trending category // Trending category changes a random number of times every 7 to 30 days if (typeof trendingCategoryNextChangeDay === "undefined") { trendingCategoryNextChangeDay = trendingCategoryDay + 7 + Math.floor(Math.random() * 24); // 7-30 days } if (gameDay >= trendingCategoryNextChangeDay) { updateTrendingCategory(); trendingCategoryNextChangeDay = gameDay + 7 + Math.floor(Math.random() * 24); // 7-30 days } } // All per-hour logic is processed when hour advances updateTimeDisplay(); // Process logic if (timeProcess) { timeProcess.hoursLeft -= 1; updateProcessBar(); if (timeProcess.hoursLeft <= 0) { var finish = timeProcess.onFinish; // If editing, update video state if (timeProcess.type === "edit" && timeProcess.video) { timeProcess.video.state = "readyToPublish"; timeProcess.video.publishReady = true; } timeProcess = null; updateProcessBar(); updateStats(); updateVideoLists(); if (typeof finish === "function") { finish(); } } } // Per-hour video view/money/subscriber accrual if (window.uploadedVideos) { for (var v = 0; v < window.uploadedVideos.length; v++) { var vid = window.uploadedVideos[v]; // Only accrue views, money, and subs if published and not finished if (vid.state === "published" && vid.hour < vid.totalHours) { var viewsThisHour = vid.hourlyViews[vid.hour] || 0; // --- Add promote campaign views to this video if any active promote campaigns exist --- // Find all active promote campaigns for this hour and add their views to this video if the campaign is running if (window.activePromotes && window.activePromotes.length > 0) { for (var pi = 0; pi < window.activePromotes.length; pi++) { var p = window.activePromotes[pi]; if (p.finished) continue; var promoteDay = gameDay - p.startDay; var promoteHour = gameHour; if (promoteDay >= 0 && promoteDay < p.days) { var promoteViewsThisHour = p.viewsPerHour[promoteDay][promoteHour] || 0; viewsThisHour += promoteViewsThisHour; } } } // --- NEW: Instantly update subscribers and money per view --- // 1) For every 1 view, 1% chance to gain a subscriber (instantly) // 2) For every 100 views, earn 0.1 money (instantly) var subsThisHour = 0; var moneyThisHour = 0; for (var i = 0; i < viewsThisHour; i++) { if (Math.random() < 0.01) { // 1% chance per view subsThisHour += 1; } } // Each viewer gives a random amount between 0.001 and 0.01 moneyThisHour = 0; for (var vi = 0; vi < viewsThisHour; vi++) { moneyThisHour += 0.001 + Math.random() * 0.009; } vid.totalViews += viewsThisHour; vid.totalMoney += moneyThisHour; vid.totalSubs += subsThisHour; viewCount += viewsThisHour; money += moneyThisHour; subscribers += subsThisHour; vid.hour++; // Clamp to target on last hour if (vid.hour === vid.totalHours) { // Remove the video from the video list when publishing is complete window.uploadedVideos.splice(v, 1); v--; // Adjust index since we removed an item continue; // Skip further processing for this video } } } } // --- Promote Campaigns: process per hour --- if (window.activePromotes && window.activePromotes.length > 0) { for (var pi = window.activePromotes.length - 1; pi >= 0; pi--) { var p = window.activePromotes[pi]; // Determine which day/hour of campaign we are in var promoteDay = gameDay - p.startDay; var promoteHour = gameHour; if (promoteDay >= 0 && promoteDay < p.days && !p.finished) { // Show to this hour's people var viewsThisHour = p.viewsPerHour[promoteDay][promoteHour] || 0; p.shownPerHour[promoteDay][promoteHour] = viewsThisHour; // Conversion rate: use p.subRate var subsThisHour = 0; for (var vi = 0; vi < viewsThisHour; vi++) { if (Math.random() < p.subRate) subsThisHour++; } p.subsGained += subsThisHour; subscribers += subsThisHour; viewCount += viewsThisHour; // Track for stats if (!p.subsPerDay[promoteDay]) p.subsPerDay[promoteDay] = 0; p.subsPerDay[promoteDay] += subsThisHour; if (!p.viewsPerDay[promoteDay]) p.viewsPerDay[promoteDay] = 0; p.viewsPerDay[promoteDay] += viewsThisHour; // --- Update promote in-panel label values --- var totalHours = p.days * 24; var spentPerHour = p.amount / totalHours; // Defensive: never overspend if (p.spentSoFar + spentPerHour > p.amount) { spentPerHour = p.amount - p.spentSoFar; if (spentPerHour < 0) spentPerHour = 0; } p.spentSoFar += spentPerHour; // Clamp spentSoFar to not exceed amount if (p.spentSoFar > p.amount) p.spentSoFar = p.amount; p.viewsSoFar += viewsThisHour; if (typeof p.updatePromoteListLabel === "function") { p.updatePromoteListLabel(); } // If spentSoFar reached amount, mark as finished if (p.spentSoFar >= p.amount && !p.finished) { p.finished = true; // Also set lastDay to current day if not already set if (typeof p.lastDay === "undefined" || p.lastDay < gameDay) { p.lastDay = gameDay; } } } // Mark as finished if campaign is over by time if (gameDay > p.startDay + p.days - 1) { p.finished = true; } // Remove finished promotes after last day if (p.finished && gameDay > p.lastDay + 1) { // Remove label from panel if (p._promoteListLabel) { for (var li = 0; li < p._promoteListLabel.length; li++) { if (p._promoteListLabel[li] && typeof p._promoteListLabel[li].destroy === "function") { p._promoteListLabel[li].destroy(); } } p._promoteListLabel = null; } window.activePromotes.splice(pi, 1); updatePromoteListDisplay(); } } } updateStats(); updateVideoLists(); } else { updateTimeDisplay(); } } // Timer logic for normal and double speed, and paused at start var doubleSpeedTimer = null; function setTimeTimer() { if (timeTimer) { LK.clearInterval(timeTimer); timeTimer = null; } if (doubleSpeedTimer) { LK.clearInterval(doubleSpeedTimer); doubleSpeedTimer = null; } // Paused: do nothing if (timeSpeed === 0 || isTimePaused) { return; } // 1x speed: 1 minute every 100ms if (timeSpeed === 1) { timeTimer = LK.setInterval(function () { if (timeSpeed !== 1 || isTimePaused) return; processOneMinute(); }, 100); } // 2x speed: 1 minute every 50ms else if (timeSpeed === 2) { doubleSpeedTimer = LK.setInterval(function () { if (timeSpeed !== 2 || isTimePaused) return; processOneMinute(); }, 50); } } setTimeTimer(); // Patch time control buttons to call setTimeTimer when speed changes var oldUpdateTimeControlButtons = updateTimeControlButtons; updateTimeControlButtons = function updateTimeControlButtons() { oldUpdateTimeControlButtons(); setTimeTimer(); }; // --- Game Update Loop --- game.update = function () { // Nothing needed for now, all logic is event/click based }; // --- Touch/Drag Handling (no drag needed, but block top left 100x100) --- game.down = function (x, y, obj) { // Prevent accidental clicks in top left if (x < 100 && y < 100) { return; } }; game.move = function (x, y, obj) {}; game.up = function (x, y, obj) {}; // --- Initialize UI --- updateStats(); // Hide video list and background by default at game start videoListBg.visible = false; videoListContainer.visible = false; // --- Tutorial Items removed as requested --- // --- Promote Stats Panel (hourly breakdown) --- function showPromoteStatsPanel(promoteIdx) { if (!window.activePromotes || !window.activePromotes[promoteIdx]) return; var p = window.activePromotes[promoteIdx]; // Panel background var promoteStatsBg = LK.getAsset('studioBg', { anchorX: 0.5, anchorY: 0.5 }); promoteStatsBg.width = 1200; promoteStatsBg.height = 1200; promoteStatsBg.x = 2048 / 2; promoteStatsBg.y = 2732 / 2; promoteStatsBg.alpha = 0.98; // Title var promoteStatsTitle = new Text2("Promote Campaign Details", { size: 70, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); promoteStatsTitle.anchor.set(0.5, 0.5); promoteStatsTitle.x = promoteStatsBg.x; promoteStatsTitle.y = promoteStatsBg.y - promoteStatsBg.height / 2 + 80; // Table header var headerTxt = new Text2("Day | Hour | Views | Subs", { size: 44, fill: "#0ff", font: "Arial, Helvetica, sans-serif" }); headerTxt.anchor.set(0.5, 0.5); headerTxt.x = promoteStatsBg.x; headerTxt.y = promoteStatsTitle.y + 80; // Table rows (show up to 24 hours for each day) var tableLabels = []; var startY = headerTxt.y + 60; var rowH = 38; var maxRows = 20; var shownRows = 0; for (var d = 0; d < p.days && shownRows < maxRows; d++) { for (var h = 0; h < 24 && shownRows < maxRows; h++) { var views = p.shownPerHour[d] ? p.shownPerHour[d][h] : 0; var subs = 0; // Estimate subs for this hour (approximate, since we don't store per hour) if (views > 0) { subs = Math.floor(views * p.subRate); } var rowTxt = new Text2(d + 1 + " | " + (h < 10 ? "0" : "") + h + ":00 | " + views + " | " + subs, { size: 36, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); rowTxt.anchor.set(0.5, 0.5); rowTxt.x = promoteStatsBg.x; rowTxt.y = startY + shownRows * rowH; tableLabels.push(rowTxt); shownRows++; } } // Close button var closeStatsBtn = new GameButton(); closeStatsBtn.setButton('editBtn', 'Close', "#fff", 320, 90); closeStatsBtn.x = promoteStatsBg.x; closeStatsBtn.y = promoteStatsBg.y + promoteStatsBg.height / 2 - 80; closeStatsBtn.action = function () { promoteStatsBg.destroy(); promoteStatsTitle.destroy(); headerTxt.destroy(); closeStatsBtn.destroy(); for (var i = 0; i < tableLabels.length; i++) tableLabels[i].destroy(); }; // Add to game game.addChild(promoteStatsBg); game.addChild(promoteStatsTitle); game.addChild(headerTxt); for (var i = 0; i < tableLabels.length; i++) game.addChild(tableLabels[i]); game.addChild(closeStatsBtn); } // --- Statistics Section UI --- // Data arrays for stats (one entry per day) var statsViewsPerDay = []; var statsSubsPerDay = []; var statsMoneyPerDay = []; var statsLastDay = 0; // Statistics overlay container (hidden by default) var statsOverlay = new Container(); statsOverlay.visible = false; statsOverlay.x = 0; statsOverlay.y = 0; game.addChild(statsOverlay); // Overlay background // Make the statistics overlay exactly match computerscreen size and position var statsBg = LK.getAsset('studioBg', { anchorX: 0.5, anchorY: 0.5, x: computerScreen.x, y: computerScreen.y }); statsBg.width = computerScreen.width; statsBg.height = computerScreen.height; statsBg.alpha = 0.98; statsOverlay.addChild(statsBg); // Title removed as requested // --- Graph Toggle Buttons --- var statTypes = [{ key: "views", label: "Views", color: 0x00e0ff, icon: "viewersicon" }, { key: "subs", label: "Subscribers", color: 0xffe066, icon: "subIcon" }, { key: "money", label: "Money", color: 0xfa4b00, icon: "moneyIcon" }]; var statDataMap = { views: statsViewsPerDay, subs: statsSubsPerDay, money: statsMoneyPerDay }; var statLabelMap = { views: "Views per Day", subs: "Subscribers per Day", money: "Money Earned per Day" }; var statIconMap = { views: "viewersicon", subs: "subIcon", money: "moneyIcon" }; var statColorMap = { views: 0x00e0ff, subs: 0xffe066, money: 0xfa4b00 }; var selectedStatType = "views"; var statToggleBtns = []; var toggleBtnW = 260; var toggleBtnH = 80; var toggleBtnSpacing = 36; // Center toggle buttons at the top of statsBg, with spacing var toggleBtnStartX = statsBg.x - (toggleBtnW * 1.5 + toggleBtnSpacing); var toggleBtnY = statsBg.y - statsBg.height / 2 + 120; for (var i = 0; i < statTypes.length; i++) { (function (idx) { var btn = new GameButton(); btn.setButton('editBtn', statTypes[idx].label, "#fff", toggleBtnW, toggleBtnH); // Reduce label font size for statistics top buttons if (btn.label) { if (btn.label.style && typeof btn.label.style.size !== "undefined") { btn.label.style.size = 44; btn.label.dirty = true; } else if (typeof btn.label.setStyle === "function") { btn.label.setStyle({ size: 44 }); } } btn.x = toggleBtnStartX + idx * (toggleBtnW + toggleBtnSpacing); btn.y = toggleBtnY; btn.action = function () { // Deselect all for (var j = 0; j < statToggleBtns.length; j++) { statToggleBtns[j].bg.alpha = 0.7; } btn.bg.alpha = 1; selectedStatType = statTypes[idx].key; updateStatsGraphSingle(); }; // Highlight first by default btn.bg.alpha = i === 0 ? 1 : 0.7; statToggleBtns.push(btn); statsOverlay.addChild(btn); })(i); } // --- Single Graph Area --- // Center graph inside statsBg var graphW = statsBg.width - 200; var graphH = 500; var graphStartX = statsBg.x - graphW / 2; var graphStartY = statsBg.y - statsBg.height / 2 + 220; // Helper to draw a single stat graph function drawStatSingleGraph(container, data, color, iconAssetId, label) { if (!container.graphNodes) container.graphNodes = []; // Remove previous graph for (var i = 0; i < container.graphNodes.length; i++) { container.graphNodes[i].destroy(); } container.graphNodes = []; // Card background var cardBg = LK.getAsset('loadingbarempty', { anchorX: 0.5, anchorY: 0, x: statsBg.x, y: graphStartY }); cardBg.width = graphW + 120; cardBg.height = graphH + 100; cardBg.alpha = 0.93; container.addChild(cardBg); container.graphNodes.push(cardBg); // (Removed: icon from statistics panel as requested) // Draw label var labelTxt = new Text2(label, { size: 60, fill: "#fff", font: "Arial, Helvetica, sans-serif" }); labelTxt.anchor.set(0, 0.5); labelTxt.x = graphStartX; labelTxt.y = graphStartY + 40; container.addChild(labelTxt); container.graphNodes.push(labelTxt); // Find max value for scaling var maxVal = 1; for (var i = 0; i < data.length; i++) { if (data[i] > maxVal) maxVal = data[i]; } // Draw line graph: connect points with rectangles (simulate lines) var prevX = null, prevY = null; for (var i = 0; i < data.length; i++) { var x0 = graphStartX + i / Math.max(1, data.length - 1) * graphW; var y0 = graphStartY + 100 + graphH - data[i] / maxVal * (graphH - 20); // Draw a small circle at each data point var point = LK.getAsset('loadingbarfull', { anchorX: 0.5, anchorY: 0.5, x: x0, y: y0 }); point.width = 18; point.height = 18; point.tint = color; container.addChild(point); container.graphNodes.push(point); // Draw value label every 5 days or last if ((i % 5 === 0 || i === data.length - 1) && data[i] > 0) { var displayValue = data[i]; // If this is the money graph, format to 2 decimal places if (selectedStatType === "money") { displayValue = Math.floor(data[i] * 100) / 100; // Always show 2 decimals for money displayValue = displayValue.toFixed(2); } var valTxt = new Text2("" + displayValue, { size: 36, fill: "#fff" }); valTxt.anchor.set(0.5, 1); valTxt.x = x0; valTxt.y = y0 - 8; container.addChild(valTxt); container.graphNodes.push(valTxt); } // Draw a "line" between previous and current point using a thin rectangle if (prevX !== null && prevY !== null) { var dx = x0 - prevX; var dy = y0 - prevY; var dist = Math.sqrt(dx * dx + dy * dy); var angle = Math.atan2(dy, dx); var line = LK.getAsset('loadingbarfull', { anchorX: 0, anchorY: 0.5, x: prevX, y: prevY }); line.width = dist; line.height = 8; line.tint = color; line.rotation = angle; container.addChild(line); container.graphNodes.push(line); } prevX = x0; prevY = y0; } } // Draw the selected graph function updateStatsGraphSingle() { var key = selectedStatType; var data = statDataMap[key]; var color = statColorMap[key]; var icon = statIconMap[key]; var label = statLabelMap[key]; drawStatSingleGraph(statsOverlay, data, color, icon, label); } // Close button for stats overlay var statsCloseBtn = new GameButton(); statsCloseBtn.setButton('editBtn', 'Close', "#fff", 320, 90); statsCloseBtn.x = 2048 / 2; statsCloseBtn.y = statsBg.y + statsBg.height / 2 - 80; statsCloseBtn.action = function () { statsOverlay.visible = false; }; statsOverlay.addChild(statsCloseBtn); // Statistics Section Button removed with navigation bar // --- Track stats per day --- // Call this at the end of each day function recordDailyStats() { // Only record once per day if (statsLastDay === gameDay) { return; } statsLastDay = gameDay; statsViewsPerDay.push(viewCount); statsSubsPerDay.push(subscribers); statsMoneyPerDay.push(money); } // Record stats for day 1 at game start recordDailyStats(); // Define updatePromoteListDisplay in global scope to avoid not defined error function updatePromoteListDisplay() { // This is a stub to avoid not defined error if called outside promote panel // The real implementation is inside the promote panel logic }
===================================================================
--- original.js
+++ change.js
@@ -312,11 +312,11 @@
/****
* Game Code
****/
-// Global variable to track finance panel instance
-// --- Trending Category State ---
// (Removed: Video Type Explanations below each button. Only technique explanations remain.)
+// --- Trending Category State ---
+// Global variable to track finance panel instance
var financePanel = null;
var videoCategories = ["Vlog", "Challenge", "Reaction", "Tutorial", "Unboxing", "Gaming", "Music", "Comedy", "Q&A"];
var selectedCategoryIdx = 0;
// Studio background (simple box for now)
@@ -4220,16 +4220,11 @@
appOverlays["editing"]._appBg.buttonMode = true;
}
// Patch: after recording, clicking the editing app icon opens the edit panel (no animation)
appOverlays["editing"].down = function (x, y, obj) {
- // Directly call the overlay.down logic for editing, which opens the edit panel
- // This is the same as the original overlay.down for editing
- // (We call the overlay.down defined in createAppOverlay for "editing")
+ // Always call overlayDown to open the edit panel if a video is in 'recorded' state
if (typeof appOverlays["editing"].overlayDown === "function") {
appOverlays["editing"].overlayDown(x, y, obj);
- } else if (typeof appOverlays["editing"].down === "function") {
- // fallback to default if not already set
- // (should not recurse infinitely, as overlayDown is not set by default)
}
};
if (appOverlays["editing"]._appIcon) appOverlays["editing"]._appIcon.down = appOverlays["editing"].down;
if (appOverlays["editing"]._appBg) appOverlays["editing"]._appBg.down = appOverlays["editing"].down;
subscriber icon 2d. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
money icon 2d. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
solid grey colour background for panel. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
viewers icon for a mobile game. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
make bigger this monitor
please to this white color
white play button solid white color. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
double speed icon for mobile games. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat. no text. only white color.
2d phone for mobile games. modern phone. looks good but phone is one color, phone's screen one color. Let it be completely 2-dimensional and not look like 3-dimensional. There should be a mute button and small volume up and down and hang up buttons on the sides of the phone.. In-Game asset. 2d. High contrast. No shadows - Fill the entire screen with a light gray color. - The outer cover color of the phone should be dark gray.
youtube button logo. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
white background rounded corners. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat white color. all white color no border.
playstore logo. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
editing application logo. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
çöp kutusu logosu fakat kırmızı arka planlı (çöp kutusu logosu beyaz renkte olacak). In-Game asset. 2d. High contrast. No shadows
kırmızıya boya
beyaza boya
maviye boya
istatistik logosu. In-Game asset. 2d. High contrast. No shadows
reklam logosu herhangi bir yazı olmasın. In-Game asset. 2d. High contrast. No shadows
record video logo with not text. In-Game asset. 2d. High contrast. No shadows
finans logosu. In-Game asset. 2d. High contrast. No shadows
youtube studio logo with no text only logo. In-Game asset. 2d. High contrast. No shadows
create youtube channel avatar cartoon 2d. In-Game asset. 2d. High contrast. No shadows
youtube channel logo. In-Game asset. 2d. High contrast. No shadows
"rastgele" ikonu, beyaz renginde olacak.. In-Game asset. 2d. High contrast. No shadows
youtube thumbnail for vlog. 2d. High contrast. No shadows
kilit ikonu beyaz. In-Game asset. 2d. High contrast. No shadows