add toast and app transition animations

Toast:
- Bigger size with bold text (18dp padding, 16dp font)
- Pop-up animation from bottom with bounce effect
- Fade-out animation when dismissing
- Cancels previous toast when showing new one

App transitions:
- Opening: fade in + scale from 0.8 to 1.0 with back-out easing
- Closing: fade out + scale from 1.0 to 0.8
- Skip animation on initial shell load
- Async close animation before loading previous app
This commit is contained in:
2026-01-20 12:27:44 +01:00
parent 11c59b890e
commit 469535f79a
2 changed files with 140 additions and 45 deletions

View File

@@ -30,8 +30,8 @@ function initShell(doc)
-- Update time display
updateTime()
-- Load home screen by default
loadAppContent_internal("home", "apps/home/home_content.rml")
-- Load home screen by default (skip animation on initial load)
loadAppContent_internal("home", "apps/home/home_content.rml", true)
print("[Shell] Shell initialized")
end
@@ -46,8 +46,8 @@ end
-- ===== APP LOADING =====
-- Internal function to load app content
function loadAppContent_internal(app_id, app_path)
-- Internal function to load app content with optional animation
function loadAppContent_internal(app_id, app_path, skip_animation)
if not app_container then
print("[Shell] ERROR: No app container")
return false
@@ -68,6 +68,18 @@ function loadAppContent_internal(app_id, app_path)
current_app_path = app_path
print("[Shell] App loaded: " .. app_id)
-- Play opening animation (unless skipped for initial load)
if not skip_animation then
app_container:SetClass("app-opening", true)
app_container:SetClass("app-closing", false)
-- Remove animation class after it completes
if setTimeout then
setTimeout(function()
app_container:SetClass("app-opening", false)
end, 300)
end
end
-- If home was loaded, populate apps dynamically
if app_id == "home" then
populateHomeApps()
@@ -126,6 +138,21 @@ end
-- ===== NAVIGATION =====
-- Play closing animation then execute callback
local function playCloseAnimation(callback)
if app_container and setTimeout then
app_container:SetClass("app-closing", true)
app_container:SetClass("app-opening", false)
setTimeout(function()
app_container:SetClass("app-closing", false)
if callback then callback() end
end, 200)
else
-- No animation support, execute immediately
if callback then callback() end
end
end
-- Go back to previous app
function shellGoBack()
print("[Shell] goBack called (history depth: " .. #nav_history .. ")")
@@ -139,17 +166,20 @@ function shellGoBack()
local previous = table.remove(nav_history)
print("[Shell] Going back to: " .. previous.app_id)
-- Don't push to history when going back
local temp_app = current_app
current_app = nil
current_app_path = nil
-- Play closing animation, then load previous app
playCloseAnimation(function()
-- Don't push to history when going back
local temp_app = current_app
current_app = nil
current_app_path = nil
local success = loadAppContent_internal(previous.app_id, previous.app_path)
if not success then
-- Restore state on failure
current_app = temp_app
end
return success
local success = loadAppContent_internal(previous.app_id, previous.app_path)
if not success then
-- Restore state on failure
current_app = temp_app
end
end)
return true
else
print("[Shell] No history - already at root")
if current_app ~= "home" then
@@ -171,10 +201,12 @@ function shellGoHome()
-- Clear history
nav_history = {}
-- Load home
current_app = nil
current_app_path = nil
loadAppContent_internal("home", "apps/home/home_content.rml")
-- Play closing animation, then load home
playCloseAnimation(function()
current_app = nil
current_app_path = nil
loadAppContent_internal("home", "apps/home/home_content.rml")
end)
end
-- Show recents (placeholder)
@@ -209,6 +241,8 @@ end
-- ===== TOASTS =====
local active_toast_id = nil
function showToast(message, type)
type = type or "default"
@@ -218,24 +252,39 @@ function showToast(message, type)
return
end
local class = "toast"
if type == "success" then
class = "toast toast-success"
elseif type == "error" then
class = "toast toast-error"
elseif type == "warning" then
class = "toast toast-warning"
-- Cancel any pending hide timer
if active_toast_id and clearTimeout then
clearTimeout(active_toast_id)
active_toast_id = nil
end
-- Clear existing toasts and add new one
local toast_html = '<div class="' .. class .. '"><span>' .. message .. '</span></div>'
local type_class = ""
if type == "success" then
type_class = " toast-success"
elseif type == "error" then
type_class = " toast-error"
elseif type == "warning" then
type_class = " toast-warning"
end
-- Create toast with visible animation class
local toast_html = '<div id="active-toast" class="toast toast-visible' .. type_class .. '"><span>' .. message .. '</span></div>'
container.inner_rml = toast_html
-- Auto-remove after 3 seconds
-- Auto-hide after 2.5 seconds (start hide animation, then remove)
if setTimeout then
setTimeout(function()
container.inner_rml = ""
end, 3000)
active_toast_id = setTimeout(function()
local toast = shell_document:GetElementById("active-toast")
if toast then
-- Switch to hiding animation
toast:SetAttribute("class", "toast toast-hiding" .. type_class)
-- Remove after animation completes
setTimeout(function()
container.inner_rml = ""
active_toast_id = nil
end, 300)
end
end, 2500)
end
print("[Shell] Toast: " .. message .. " (" .. type .. ")")