fix app layouts: remove style tags from content fragments, use component classes
This commit is contained in:
@@ -1,11 +1,138 @@
|
||||
<!-- Browser App Content Fragment -->
|
||||
<!-- Styles are in shell.rml -->
|
||||
<!-- Uses classes from components.rcss -->
|
||||
|
||||
<div class="app-content">
|
||||
<div class="app-header">
|
||||
<span class="app-header-title">Browser</span>
|
||||
<!-- URL bar -->
|
||||
<div class="app-bar" style="padding: 8px 12px;">
|
||||
<div class="btn-icon" onclick="browserBack()" style="width: 40px; height: 40px;">
|
||||
<img src="../../icons/back.tga" style="width: 24px; height: 24px;"/>
|
||||
</div>
|
||||
<div class="search-bar" style="flex: 1; margin: 0 8px; padding: 8px 16px;">
|
||||
<span style="color: #4CAF50; margin-right: 8px;">S</span>
|
||||
<input type="text" id="url-input" style="flex: 1; background-color: transparent; color: #FFFFFF; font-size: 14px;" value="mosis.app"/>
|
||||
</div>
|
||||
<div class="btn-icon" onclick="browserRefresh()" style="width: 40px; height: 40px;">
|
||||
<img src="../../icons/refresh.tga" style="width: 24px; height: 24px;"/>
|
||||
</div>
|
||||
<div class="btn-icon" onclick="showTabs()" style="width: 40px; height: 40px;">
|
||||
<span style="font-size: 14px; color: #FFFFFF; font-weight: bold;">1</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-body">
|
||||
<span class="placeholder-text">Browser App</span>
|
||||
|
||||
<!-- Page content -->
|
||||
<div style="flex: 1; overflow: auto; background-color: #FFFFFF; padding: 24px;">
|
||||
<div style="text-align: center;">
|
||||
<div style="font-size: 48px; font-weight: bold; color: #BB86FC; margin-bottom: 24px;">Mosis</div>
|
||||
<div class="search-bar" style="margin-bottom: 32px; background-color: #f1f3f4;">
|
||||
<input type="text" style="flex: 1; background-color: transparent; color: #333333; font-size: 16px; text-align: center;" placeholder="Search or enter URL"/>
|
||||
</div>
|
||||
<div style="display: flex; flex-wrap: wrap; justify-content: center; gap: 16px;">
|
||||
<div onclick="navigateTo('google.com')" style="cursor: pointer; width: 80px; display: flex; flex-direction: column; align-items: center;">
|
||||
<div style="width: 48px; height: 48px; border-radius: 8px; background-color: #4285F4; display: flex; align-items: center; justify-content: center; color: #FFFFFF; font-size: 20px; margin-bottom: 8px;">G</div>
|
||||
<span style="font-size: 12px; color: #666666;">Google</span>
|
||||
</div>
|
||||
<div onclick="navigateTo('youtube.com')" style="cursor: pointer; width: 80px; display: flex; flex-direction: column; align-items: center;">
|
||||
<div style="width: 48px; height: 48px; border-radius: 8px; background-color: #FF0000; display: flex; align-items: center; justify-content: center; color: #FFFFFF; font-size: 20px; margin-bottom: 8px;">Y</div>
|
||||
<span style="font-size: 12px; color: #666666;">YouTube</span>
|
||||
</div>
|
||||
<div onclick="navigateTo('github.com')" style="cursor: pointer; width: 80px; display: flex; flex-direction: column; align-items: center;">
|
||||
<div style="width: 48px; height: 48px; border-radius: 8px; background-color: #333333; display: flex; align-items: center; justify-content: center; color: #FFFFFF; font-size: 20px; margin-bottom: 8px;">G</div>
|
||||
<span style="font-size: 12px; color: #666666;">GitHub</span>
|
||||
</div>
|
||||
<div onclick="navigateTo('reddit.com')" style="cursor: pointer; width: 80px; display: flex; flex-direction: column; align-items: center;">
|
||||
<div style="width: 48px; height: 48px; border-radius: 8px; background-color: #FF4500; display: flex; align-items: center; justify-content: center; color: #FFFFFF; font-size: 20px; margin-bottom: 8px;">R</div>
|
||||
<span style="font-size: 12px; color: #666666;">Reddit</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom bar -->
|
||||
<div class="bottom-nav">
|
||||
<div class="bottom-nav-item" onclick="browserBack()">
|
||||
<img src="../../icons/back.tga" style="width: 24px; height: 24px;"/>
|
||||
</div>
|
||||
<div class="bottom-nav-item" onclick="browserForward()">
|
||||
<img src="../../icons/forward.tga" style="width: 24px; height: 24px;"/>
|
||||
</div>
|
||||
<div class="bottom-nav-item" onclick="browserHome()">
|
||||
<img src="../../icons/home.tga" style="width: 24px; height: 24px;"/>
|
||||
</div>
|
||||
<div class="bottom-nav-item" onclick="addBookmark()">
|
||||
<img src="../../icons/star.tga" style="width: 24px; height: 24px;"/>
|
||||
</div>
|
||||
<div class="bottom-nav-item" onclick="showBrowserMenu()">
|
||||
<img src="../../icons/menu.tga" style="width: 24px; height: 24px;"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
local current_url = "mosis.app"
|
||||
|
||||
function navigateTo(url)
|
||||
print("[Browser] Navigating to: " .. url)
|
||||
current_url = url
|
||||
|
||||
local doc = shell_document
|
||||
if doc then
|
||||
local url_input = doc:GetElementById("url-input")
|
||||
if url_input then
|
||||
url_input.value = url
|
||||
end
|
||||
end
|
||||
|
||||
if showToast then
|
||||
showToast("Loading " .. url)
|
||||
end
|
||||
end
|
||||
|
||||
function browserBack()
|
||||
print("[Browser] Back")
|
||||
if showToast then
|
||||
showToast("Back")
|
||||
end
|
||||
end
|
||||
|
||||
function browserForward()
|
||||
print("[Browser] Forward")
|
||||
if showToast then
|
||||
showToast("No forward history")
|
||||
end
|
||||
end
|
||||
|
||||
function browserRefresh()
|
||||
print("[Browser] Refresh")
|
||||
if showToast then
|
||||
showToast("Page refreshed")
|
||||
end
|
||||
end
|
||||
|
||||
function browserHome()
|
||||
print("[Browser] Home")
|
||||
navigateTo("mosis.app")
|
||||
end
|
||||
|
||||
function showTabs()
|
||||
print("[Browser] Show tabs")
|
||||
if showToast then
|
||||
showToast("1 tab open")
|
||||
end
|
||||
end
|
||||
|
||||
function addBookmark()
|
||||
print("[Browser] Add bookmark")
|
||||
if showToast then
|
||||
showToast("Bookmark added")
|
||||
end
|
||||
end
|
||||
|
||||
function showBrowserMenu()
|
||||
print("[Browser] Menu")
|
||||
if showToast then
|
||||
showToast("Browser menu")
|
||||
end
|
||||
end
|
||||
|
||||
print("[Browser] Content loaded")
|
||||
</script>
|
||||
|
||||
@@ -1,44 +1,281 @@
|
||||
<!-- Camera App Content Fragment -->
|
||||
<!-- Loaded into shell's #app-container -->
|
||||
<!-- Styles are in shell.rml -->
|
||||
<!-- Uses classes from shell.rml -->
|
||||
|
||||
<div class="camera-content">
|
||||
<!-- Top Bar -->
|
||||
<div class="camera-top-bar">
|
||||
<div class="camera-btn" onclick="showToast('Flash: Auto')">
|
||||
<img src="../../icons/flash.tga"/>
|
||||
<div style="display: flex; gap: 12px;">
|
||||
<div class="camera-btn" id="flash-btn" onclick="toggleFlash()">
|
||||
<img src="../../icons/flash.tga" style="width: 24px; height: 24px;"/>
|
||||
</div>
|
||||
<div class="camera-btn" onclick="toggleTimer()">
|
||||
<img src="../../icons/timer.tga" style="width: 24px; height: 24px;"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="camera-btn">
|
||||
<img src="../../icons/timer.tga"/>
|
||||
</div>
|
||||
<div class="camera-btn" onclick="showToast('Settings')">
|
||||
<img src="../../icons/settings.tga"/>
|
||||
<span id="flash-indicator" style="font-size: 12px; color: #FFFFFF; background-color: rgba(0, 0, 0, 0.4); padding: 6px 12px; border-radius: 16px;">Flash: Auto</span>
|
||||
<div class="camera-btn" onclick="openCameraSettings()">
|
||||
<img src="../../icons/settings.tga" style="width: 24px; height: 24px;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recording Indicator -->
|
||||
<div id="recording-indicator" style="position: absolute; top: 80px; left: 50%; display: none; align-items: center; gap: 8px; background-color: rgba(0, 0, 0, 0.6); padding: 8px 16px; border-radius: 20px;">
|
||||
<div style="width: 12px; height: 12px; border-radius: 6px; background-color: #F44336;"></div>
|
||||
<span id="recording-time" style="font-size: 14px; color: #FFFFFF; font-weight: bold;">00:00</span>
|
||||
</div>
|
||||
|
||||
<!-- Viewfinder -->
|
||||
<div class="viewfinder-container">
|
||||
<div class="viewfinder">
|
||||
<span class="viewfinder-text">Camera Preview</span>
|
||||
<div class="viewfinder-container" onclick="tapToFocus()">
|
||||
<div class="viewfinder" id="viewfinder">
|
||||
<span style="font-size: 64px; color: #444444; margin-bottom: 16px;">C</span>
|
||||
<span style="color: #666666; font-size: 18px;">Camera Preview</span>
|
||||
<span style="font-size: 14px; color: #555555; margin-top: 8px;">Tap to focus</span>
|
||||
</div>
|
||||
<div class="focus-indicator"></div>
|
||||
<div id="focus-indicator" style="position: absolute; width: 80px; height: 80px; border-radius: 8px; opacity: 0;"></div>
|
||||
</div>
|
||||
|
||||
<!-- Zoom Controls -->
|
||||
<div style="position: absolute; bottom: 180px; left: 50%; display: flex; gap: 16px;">
|
||||
<div onclick="setZoom(0.5)" style="width: 40px; height: 40px; border-radius: 20px; background-color: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; color: #FFFFFF; font-size: 12px; font-weight: bold; cursor: pointer;">0.5x</div>
|
||||
<div id="zoom-1x" onclick="setZoom(1)" style="width: 40px; height: 40px; border-radius: 20px; background-color: #FFFFFF; display: flex; align-items: center; justify-content: center; color: #000000; font-size: 12px; font-weight: bold; cursor: pointer;">1x</div>
|
||||
<div onclick="setZoom(2)" style="width: 40px; height: 40px; border-radius: 20px; background-color: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; color: #FFFFFF; font-size: 12px; font-weight: bold; cursor: pointer;">2x</div>
|
||||
</div>
|
||||
|
||||
<!-- Mode Selector -->
|
||||
<div class="mode-selector">
|
||||
<span class="mode-item">Video</span>
|
||||
<span class="mode-item active">Photo</span>
|
||||
<span class="mode-item">Portrait</span>
|
||||
<div class="camera-mode-selector">
|
||||
<span class="camera-mode" id="mode-night" onclick="switchMode('night')">Night</span>
|
||||
<span class="camera-mode" id="mode-portrait" onclick="switchMode('portrait')">Portrait</span>
|
||||
<span class="camera-mode active" id="mode-photo" onclick="switchMode('photo')">Photo</span>
|
||||
<span class="camera-mode" id="mode-video" onclick="switchMode('video')">Video</span>
|
||||
</div>
|
||||
|
||||
<!-- Bottom Controls -->
|
||||
<div class="camera-bottom-bar">
|
||||
<div class="gallery-preview"></div>
|
||||
<div class="shutter-btn" onclick="showToast('Photo captured!', 'success')">
|
||||
<div class="shutter-btn-inner"></div>
|
||||
<div class="camera-gallery-preview" onclick="openGallery()"></div>
|
||||
<div class="camera-shutter-btn" id="shutter-btn" onclick="capture()">
|
||||
<div id="shutter-inner" class="camera-shutter-inner"></div>
|
||||
</div>
|
||||
<div class="switch-camera-btn" onclick="showToast('Switched camera')">
|
||||
<img src="../../icons/switch-camera.tga"/>
|
||||
<div class="camera-switch-btn" onclick="switchCamera()">
|
||||
<img src="../../icons/switch-camera.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
local current_mode = "photo"
|
||||
local flash_mode = "auto"
|
||||
local timer_mode = "off"
|
||||
local is_front = false
|
||||
local is_recording = false
|
||||
local record_time = 0
|
||||
local record_timer = nil
|
||||
local zoom_level = 1
|
||||
|
||||
local function getDoc()
|
||||
return shell_document
|
||||
end
|
||||
|
||||
function switchMode(mode)
|
||||
current_mode = mode
|
||||
local doc = getDoc()
|
||||
if not doc then return end
|
||||
|
||||
local modes = {"night", "portrait", "photo", "video"}
|
||||
for _, m in ipairs(modes) do
|
||||
local el = doc:GetElementById("mode-" .. m)
|
||||
if el then
|
||||
el:SetClass("active", m == mode)
|
||||
end
|
||||
end
|
||||
|
||||
local inner = doc:GetElementById("shutter-inner")
|
||||
if inner then
|
||||
if mode == "video" then
|
||||
inner:SetClass("camera-shutter-inner", false)
|
||||
inner:SetClass("camera-shutter-video", true)
|
||||
else
|
||||
inner:SetClass("camera-shutter-video", false)
|
||||
inner:SetClass("camera-shutter-inner", true)
|
||||
end
|
||||
end
|
||||
|
||||
print("[Camera] Mode: " .. mode)
|
||||
if showToast then
|
||||
showToast(mode:sub(1,1):upper() .. mode:sub(2) .. " mode")
|
||||
end
|
||||
end
|
||||
|
||||
function toggleFlash()
|
||||
if flash_mode == "auto" then
|
||||
flash_mode = "on"
|
||||
elseif flash_mode == "on" then
|
||||
flash_mode = "off"
|
||||
else
|
||||
flash_mode = "auto"
|
||||
end
|
||||
|
||||
local doc = getDoc()
|
||||
if doc then
|
||||
local indicator = doc:GetElementById("flash-indicator")
|
||||
if indicator then
|
||||
indicator.inner_rml = "Flash: " .. flash_mode:sub(1,1):upper() .. flash_mode:sub(2)
|
||||
end
|
||||
end
|
||||
|
||||
print("[Camera] Flash: " .. flash_mode)
|
||||
end
|
||||
|
||||
function toggleTimer()
|
||||
if timer_mode == "off" then
|
||||
timer_mode = "3s"
|
||||
elseif timer_mode == "3s" then
|
||||
timer_mode = "10s"
|
||||
else
|
||||
timer_mode = "off"
|
||||
end
|
||||
|
||||
print("[Camera] Timer: " .. timer_mode)
|
||||
if showToast then
|
||||
showToast("Timer: " .. timer_mode)
|
||||
end
|
||||
end
|
||||
|
||||
function setZoom(level)
|
||||
zoom_level = level
|
||||
print("[Camera] Zoom: " .. level .. "x")
|
||||
if showToast then
|
||||
showToast(level .. "x zoom")
|
||||
end
|
||||
end
|
||||
|
||||
function switchCamera()
|
||||
is_front = not is_front
|
||||
local doc = getDoc()
|
||||
if doc then
|
||||
local vf = doc:GetElementById("viewfinder")
|
||||
if vf then
|
||||
if is_front then
|
||||
vf.inner_rml = [[
|
||||
<span style="font-size: 64px; color: #444444; margin-bottom: 16px;">F</span>
|
||||
<span style="color: #666666; font-size: 18px;">Front Camera</span>
|
||||
<span style="font-size: 14px; color: #555555; margin-top: 8px;">Tap to focus</span>
|
||||
]]
|
||||
else
|
||||
vf.inner_rml = [[
|
||||
<span style="font-size: 64px; color: #444444; margin-bottom: 16px;">C</span>
|
||||
<span style="color: #666666; font-size: 18px;">Camera Preview</span>
|
||||
<span style="font-size: 14px; color: #555555; margin-top: 8px;">Tap to focus</span>
|
||||
]]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
print("[Camera] Switched to " .. (is_front and "front" or "back") .. " camera")
|
||||
if showToast then
|
||||
showToast(is_front and "Front camera" or "Back camera")
|
||||
end
|
||||
end
|
||||
|
||||
function capture()
|
||||
if current_mode == "video" then
|
||||
if is_recording then
|
||||
stopRecording()
|
||||
else
|
||||
startRecording()
|
||||
end
|
||||
else
|
||||
takePhoto()
|
||||
end
|
||||
end
|
||||
|
||||
function takePhoto()
|
||||
print("[Camera] Photo captured!")
|
||||
if showToast then
|
||||
showToast("Photo saved")
|
||||
end
|
||||
end
|
||||
|
||||
function startRecording()
|
||||
is_recording = true
|
||||
record_time = 0
|
||||
|
||||
local doc = getDoc()
|
||||
if doc then
|
||||
local indicator = doc:GetElementById("recording-indicator")
|
||||
if indicator then
|
||||
indicator.style.display = "flex"
|
||||
end
|
||||
local inner = doc:GetElementById("shutter-inner")
|
||||
if inner then
|
||||
inner:SetClass("camera-shutter-video", false)
|
||||
inner:SetClass("camera-shutter-stop", true)
|
||||
end
|
||||
end
|
||||
|
||||
if setInterval then
|
||||
record_timer = setInterval(function()
|
||||
record_time = record_time + 1
|
||||
local mins = math.floor(record_time / 60)
|
||||
local secs = record_time % 60
|
||||
local doc = getDoc()
|
||||
if doc then
|
||||
local time_el = doc:GetElementById("recording-time")
|
||||
if time_el then
|
||||
time_el.inner_rml = string.format("%02d:%02d", mins, secs)
|
||||
end
|
||||
end
|
||||
end, 1000)
|
||||
end
|
||||
|
||||
print("[Camera] Recording started")
|
||||
end
|
||||
|
||||
function stopRecording()
|
||||
is_recording = false
|
||||
|
||||
if record_timer and clearInterval then
|
||||
clearInterval(record_timer)
|
||||
record_timer = nil
|
||||
end
|
||||
|
||||
local doc = getDoc()
|
||||
if doc then
|
||||
local indicator = doc:GetElementById("recording-indicator")
|
||||
if indicator then
|
||||
indicator.style.display = "none"
|
||||
end
|
||||
local inner = doc:GetElementById("shutter-inner")
|
||||
if inner then
|
||||
inner:SetClass("camera-shutter-stop", false)
|
||||
inner:SetClass("camera-shutter-video", true)
|
||||
end
|
||||
end
|
||||
|
||||
local mins = math.floor(record_time / 60)
|
||||
local secs = record_time % 60
|
||||
print("[Camera] Recording stopped: " .. string.format("%02d:%02d", mins, secs))
|
||||
if showToast then
|
||||
showToast(string.format("Video saved (%02d:%02d)", mins, secs))
|
||||
end
|
||||
end
|
||||
|
||||
function tapToFocus()
|
||||
print("[Camera] Tap to focus")
|
||||
end
|
||||
|
||||
function openGallery()
|
||||
print("[Camera] Opening gallery")
|
||||
if showToast then
|
||||
showToast("Gallery")
|
||||
end
|
||||
end
|
||||
|
||||
function openCameraSettings()
|
||||
print("[Camera] Camera settings")
|
||||
if showToast then
|
||||
showToast("Camera settings")
|
||||
end
|
||||
end
|
||||
|
||||
print("[Camera] Content loaded")
|
||||
</script>
|
||||
|
||||
@@ -1,11 +1,143 @@
|
||||
<!-- Contacts App Content Fragment -->
|
||||
<!-- Styles are in shell.rml -->
|
||||
<!-- Uses classes from components.rcss -->
|
||||
|
||||
<div class="app-content">
|
||||
<div class="app-header">
|
||||
<span class="app-header-title">Contacts</span>
|
||||
<div class="app-bar">
|
||||
<span class="app-bar-title">Contacts</span>
|
||||
</div>
|
||||
<div class="app-body">
|
||||
<span class="placeholder-text">Contacts App</span>
|
||||
|
||||
<div class="search-bar">
|
||||
<img src="../../icons/search.tga" style="width: 24px; height: 24px; margin-right: 12px; opacity: 0.6;"/>
|
||||
<span class="search-input">Search contacts</span>
|
||||
</div>
|
||||
|
||||
<div class="list" style="flex: 1; overflow: auto;">
|
||||
<div class="list-header">A</div>
|
||||
<div class="list-item" onclick="openContact('Alice Johnson')">
|
||||
<div class="list-item-avatar" style="background-color: #4CAF50;">A</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Alice Johnson</span>
|
||||
<span class="list-item-subtitle">+1 555-0101</span>
|
||||
</div>
|
||||
<div class="btn-icon" onclick="callContact('Alice Johnson'); event.stopPropagation();">
|
||||
<img src="../../icons/phone.tga" style="width: 24px; height: 24px;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-header">B</div>
|
||||
<div class="list-item" onclick="openContact('Bob Williams')">
|
||||
<div class="list-item-avatar" style="background-color: #2196F3;">B</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Bob Williams</span>
|
||||
<span class="list-item-subtitle">+1 555-0102</span>
|
||||
</div>
|
||||
<div class="btn-icon" onclick="callContact('Bob Williams'); event.stopPropagation();">
|
||||
<img src="../../icons/phone.tga" style="width: 24px; height: 24px;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-header">C</div>
|
||||
<div class="list-item" onclick="openContact('Carol Davis')">
|
||||
<div class="list-item-avatar" style="background-color: #9C27B0;">C</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Carol Davis</span>
|
||||
<span class="list-item-subtitle">+1 555-0103</span>
|
||||
</div>
|
||||
<div class="btn-icon" onclick="callContact('Carol Davis'); event.stopPropagation();">
|
||||
<img src="../../icons/phone.tga" style="width: 24px; height: 24px;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-header">D</div>
|
||||
<div class="list-item" onclick="openContact('David Miller')">
|
||||
<div class="list-item-avatar" style="background-color: #FF9800;">D</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">David Miller</span>
|
||||
<span class="list-item-subtitle">+1 555-0104</span>
|
||||
</div>
|
||||
<div class="btn-icon" onclick="callContact('David Miller'); event.stopPropagation();">
|
||||
<img src="../../icons/phone.tga" style="width: 24px; height: 24px;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-header">E</div>
|
||||
<div class="list-item" onclick="openContact('Emma Wilson')">
|
||||
<div class="list-item-avatar" style="background-color: #E91E63;">E</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Emma Wilson</span>
|
||||
<span class="list-item-subtitle">+1 555-0105</span>
|
||||
</div>
|
||||
<div class="btn-icon" onclick="callContact('Emma Wilson'); event.stopPropagation();">
|
||||
<img src="../../icons/phone.tga" style="width: 24px; height: 24px;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-header">J</div>
|
||||
<div class="list-item" onclick="openContact('John Smith')">
|
||||
<div class="list-item-avatar" style="background-color: #3F51B5;">J</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">John Smith</span>
|
||||
<span class="list-item-subtitle">+1 555-0109</span>
|
||||
</div>
|
||||
<div class="btn-icon" onclick="callContact('John Smith'); event.stopPropagation();">
|
||||
<img src="../../icons/phone.tga" style="width: 24px; height: 24px;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-header">M</div>
|
||||
<div class="list-item" onclick="openContact('Mom')">
|
||||
<div class="list-item-avatar" style="background-color: #E91E63;">M</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Mom</span>
|
||||
<span class="list-item-subtitle">+1 555-0110</span>
|
||||
</div>
|
||||
<div class="btn-icon" onclick="callContact('Mom'); event.stopPropagation();">
|
||||
<img src="../../icons/phone.tga" style="width: 24px; height: 24px;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-header">S</div>
|
||||
<div class="list-item" onclick="openContact('Sarah')">
|
||||
<div class="list-item-avatar" style="background-color: #9C27B0;">S</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Sarah</span>
|
||||
<span class="list-item-subtitle">+1 555-0111</span>
|
||||
</div>
|
||||
<div class="btn-icon" onclick="callContact('Sarah'); event.stopPropagation();">
|
||||
<img src="../../icons/phone.tga" style="width: 24px; height: 24px;"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-fab" onclick="addContact()">
|
||||
<img src="../../icons/add.tga" style="width: 32px; height: 32px;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function openContact(name)
|
||||
print("[Contacts] Opening contact: " .. name)
|
||||
if showToast then
|
||||
showToast("Contact: " .. name)
|
||||
end
|
||||
end
|
||||
|
||||
function callContact(name)
|
||||
print("[Contacts] Calling: " .. name)
|
||||
if showToast then
|
||||
showToast("Calling " .. name .. "...")
|
||||
end
|
||||
if shellNavigateTo then
|
||||
shellNavigateTo("calling")
|
||||
end
|
||||
end
|
||||
|
||||
function addContact()
|
||||
print("[Contacts] Add new contact")
|
||||
if showToast then
|
||||
showToast("Add new contact")
|
||||
end
|
||||
end
|
||||
|
||||
print("[Contacts] Content loaded")
|
||||
</script>
|
||||
|
||||
468
src/main/assets/apps/dialer/calling_content.rml
Normal file
468
src/main/assets/apps/dialer/calling_content.rml
Normal file
@@ -0,0 +1,468 @@
|
||||
<!-- Calling Screen Content Fragment -->
|
||||
<!-- In-call interface with controls -->
|
||||
|
||||
<style>
|
||||
.calling-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: linear-gradient(180deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
|
||||
}
|
||||
|
||||
.calling-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 48px 24px;
|
||||
}
|
||||
|
||||
.calling-avatar {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: 60px;
|
||||
background-color: #BB86FC;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 48px;
|
||||
color: #FFFFFF;
|
||||
font-weight: 500;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.calling-name {
|
||||
font-size: 32px;
|
||||
color: #FFFFFF;
|
||||
font-weight: 500;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.calling-status {
|
||||
font-size: 18px;
|
||||
color: #B0B0B0;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.calling-timer {
|
||||
font-size: 24px;
|
||||
color: #FFFFFF;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
/* Call controls */
|
||||
.call-controls {
|
||||
padding: 32px 24px 48px;
|
||||
}
|
||||
|
||||
.controls-row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 32px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.control-btn {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 32px;
|
||||
background-color: rgba(255, 255, 255, 0.15);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.control-btn:hover {
|
||||
background-color: rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
|
||||
.control-btn.active {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.control-btn.active img {
|
||||
filter: invert(1);
|
||||
}
|
||||
|
||||
.control-btn img {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.control-label {
|
||||
font-size: 12px;
|
||||
color: #FFFFFF;
|
||||
margin-top: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.control-btn.active .control-label {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
/* End call button */
|
||||
.end-call-row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.end-call-btn {
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
border-radius: 36px;
|
||||
background-color: #F44336;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.end-call-btn:hover {
|
||||
background-color: #E53935;
|
||||
}
|
||||
|
||||
.end-call-btn img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
|
||||
/* Dialpad overlay */
|
||||
.dialpad-overlay {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #1a1a1a;
|
||||
padding: 24px;
|
||||
border-radius: 24px 24px 0 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dialpad-overlay.visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dialpad-row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 24px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.dialpad-key {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 32px;
|
||||
background-color: #2d2d2d;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dialpad-key:hover {
|
||||
background-color: #3d3d3d;
|
||||
}
|
||||
|
||||
.dialpad-digit {
|
||||
font-size: 24px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.dialpad-letters {
|
||||
font-size: 10px;
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
.dialpad-close {
|
||||
text-align: center;
|
||||
padding: 16px;
|
||||
color: #BB86FC;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="calling-content">
|
||||
<div class="calling-info">
|
||||
<div id="calling-avatar" class="calling-avatar">J</div>
|
||||
<div id="calling-name" class="calling-name">John Smith</div>
|
||||
<div id="calling-status" class="calling-status">Calling...</div>
|
||||
<div id="calling-timer" class="calling-timer"></div>
|
||||
</div>
|
||||
|
||||
<div class="call-controls">
|
||||
<div class="controls-row">
|
||||
<div class="control-btn" id="btn-mute" onclick="toggleMute()">
|
||||
<img src="../../icons/mic.tga"/>
|
||||
<span class="control-label">Mute</span>
|
||||
</div>
|
||||
<div class="control-btn" id="btn-keypad" onclick="toggleKeypad()">
|
||||
<img src="../../icons/keypad.tga"/>
|
||||
<span class="control-label">Keypad</span>
|
||||
</div>
|
||||
<div class="control-btn" id="btn-speaker" onclick="toggleSpeaker()">
|
||||
<img src="../../icons/speaker.tga"/>
|
||||
<span class="control-label">Speaker</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="controls-row">
|
||||
<div class="control-btn" id="btn-add" onclick="addCall()">
|
||||
<img src="../../icons/add.tga"/>
|
||||
<span class="control-label">Add call</span>
|
||||
</div>
|
||||
<div class="control-btn" id="btn-hold" onclick="toggleHold()">
|
||||
<img src="../../icons/pause.tga"/>
|
||||
<span class="control-label">Hold</span>
|
||||
</div>
|
||||
<div class="control-btn" id="btn-video" onclick="toggleVideo()">
|
||||
<img src="../../icons/camera.tga"/>
|
||||
<span class="control-label">Video</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="end-call-row">
|
||||
<div class="end-call-btn" onclick="endCall()">
|
||||
<img src="../../icons/phone.tga"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dialpad overlay -->
|
||||
<div id="dialpad-overlay" class="dialpad-overlay">
|
||||
<div class="dialpad-row">
|
||||
<div class="dialpad-key" onclick="dialDTMF('1')">
|
||||
<span class="dialpad-digit">1</span>
|
||||
</div>
|
||||
<div class="dialpad-key" onclick="dialDTMF('2')">
|
||||
<span class="dialpad-digit">2</span>
|
||||
<span class="dialpad-letters">ABC</span>
|
||||
</div>
|
||||
<div class="dialpad-key" onclick="dialDTMF('3')">
|
||||
<span class="dialpad-digit">3</span>
|
||||
<span class="dialpad-letters">DEF</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialpad-row">
|
||||
<div class="dialpad-key" onclick="dialDTMF('4')">
|
||||
<span class="dialpad-digit">4</span>
|
||||
<span class="dialpad-letters">GHI</span>
|
||||
</div>
|
||||
<div class="dialpad-key" onclick="dialDTMF('5')">
|
||||
<span class="dialpad-digit">5</span>
|
||||
<span class="dialpad-letters">JKL</span>
|
||||
</div>
|
||||
<div class="dialpad-key" onclick="dialDTMF('6')">
|
||||
<span class="dialpad-digit">6</span>
|
||||
<span class="dialpad-letters">MNO</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialpad-row">
|
||||
<div class="dialpad-key" onclick="dialDTMF('7')">
|
||||
<span class="dialpad-digit">7</span>
|
||||
<span class="dialpad-letters">PQRS</span>
|
||||
</div>
|
||||
<div class="dialpad-key" onclick="dialDTMF('8')">
|
||||
<span class="dialpad-digit">8</span>
|
||||
<span class="dialpad-letters">TUV</span>
|
||||
</div>
|
||||
<div class="dialpad-key" onclick="dialDTMF('9')">
|
||||
<span class="dialpad-digit">9</span>
|
||||
<span class="dialpad-letters">WXYZ</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialpad-row">
|
||||
<div class="dialpad-key" onclick="dialDTMF('*')">
|
||||
<span class="dialpad-digit">*</span>
|
||||
</div>
|
||||
<div class="dialpad-key" onclick="dialDTMF('0')">
|
||||
<span class="dialpad-digit">0</span>
|
||||
<span class="dialpad-letters">+</span>
|
||||
</div>
|
||||
<div class="dialpad-key" onclick="dialDTMF('#')">
|
||||
<span class="dialpad-digit">#</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialpad-close" onclick="toggleKeypad()">Hide</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
-- Calling state
|
||||
local call_state = {
|
||||
is_muted = false,
|
||||
is_speaker = false,
|
||||
is_hold = false,
|
||||
is_connected = false,
|
||||
call_duration = 0,
|
||||
keypad_visible = false
|
||||
}
|
||||
|
||||
local timer_id = nil
|
||||
|
||||
local function getDoc()
|
||||
return shell_document
|
||||
end
|
||||
|
||||
-- Simulate call connection
|
||||
local function simulateConnection()
|
||||
if setTimeout then
|
||||
setTimeout(function()
|
||||
call_state.is_connected = true
|
||||
local doc = getDoc()
|
||||
if doc then
|
||||
local status = doc:GetElementById("calling-status")
|
||||
if status then
|
||||
status.inner_rml = "Connected"
|
||||
end
|
||||
end
|
||||
startCallTimer()
|
||||
end, 2000)
|
||||
end
|
||||
end
|
||||
|
||||
-- Start call timer
|
||||
function startCallTimer()
|
||||
if setInterval then
|
||||
timer_id = setInterval(function()
|
||||
call_state.call_duration = call_state.call_duration + 1
|
||||
updateTimerDisplay()
|
||||
end, 1000)
|
||||
end
|
||||
end
|
||||
|
||||
-- Update timer display
|
||||
function updateTimerDisplay()
|
||||
local doc = getDoc()
|
||||
if not doc then return end
|
||||
|
||||
local timer = doc:GetElementById("calling-timer")
|
||||
if timer then
|
||||
local mins = math.floor(call_state.call_duration / 60)
|
||||
local secs = call_state.call_duration % 60
|
||||
timer.inner_rml = string.format("%02d:%02d", mins, secs)
|
||||
end
|
||||
end
|
||||
|
||||
-- Toggle mute
|
||||
function toggleMute()
|
||||
call_state.is_muted = not call_state.is_muted
|
||||
local doc = getDoc()
|
||||
if doc then
|
||||
local btn = doc:GetElementById("btn-mute")
|
||||
if btn then
|
||||
btn:SetClass("active", call_state.is_muted)
|
||||
end
|
||||
end
|
||||
if showToast then
|
||||
showToast(call_state.is_muted and "Muted" or "Unmuted")
|
||||
end
|
||||
print("[Calling] Mute: " .. tostring(call_state.is_muted))
|
||||
end
|
||||
|
||||
-- Toggle speaker
|
||||
function toggleSpeaker()
|
||||
call_state.is_speaker = not call_state.is_speaker
|
||||
local doc = getDoc()
|
||||
if doc then
|
||||
local btn = doc:GetElementById("btn-speaker")
|
||||
if btn then
|
||||
btn:SetClass("active", call_state.is_speaker)
|
||||
end
|
||||
end
|
||||
if showToast then
|
||||
showToast(call_state.is_speaker and "Speaker on" or "Speaker off")
|
||||
end
|
||||
print("[Calling] Speaker: " .. tostring(call_state.is_speaker))
|
||||
end
|
||||
|
||||
-- Toggle hold
|
||||
function toggleHold()
|
||||
call_state.is_hold = not call_state.is_hold
|
||||
local doc = getDoc()
|
||||
if doc then
|
||||
local btn = doc:GetElementById("btn-hold")
|
||||
if btn then
|
||||
btn:SetClass("active", call_state.is_hold)
|
||||
end
|
||||
local status = doc:GetElementById("calling-status")
|
||||
if status then
|
||||
if call_state.is_hold then
|
||||
status.inner_rml = "On Hold"
|
||||
elseif call_state.is_connected then
|
||||
status.inner_rml = "Connected"
|
||||
end
|
||||
end
|
||||
end
|
||||
if showToast then
|
||||
showToast(call_state.is_hold and "Call on hold" or "Call resumed")
|
||||
end
|
||||
print("[Calling] Hold: " .. tostring(call_state.is_hold))
|
||||
end
|
||||
|
||||
-- Toggle keypad
|
||||
function toggleKeypad()
|
||||
call_state.keypad_visible = not call_state.keypad_visible
|
||||
local doc = getDoc()
|
||||
if doc then
|
||||
local overlay = doc:GetElementById("dialpad-overlay")
|
||||
if overlay then
|
||||
overlay:SetClass("visible", call_state.keypad_visible)
|
||||
end
|
||||
end
|
||||
print("[Calling] Keypad: " .. tostring(call_state.keypad_visible))
|
||||
end
|
||||
|
||||
-- Dial DTMF tone
|
||||
function dialDTMF(digit)
|
||||
print("[Calling] DTMF: " .. digit)
|
||||
if showToast then
|
||||
showToast("DTMF: " .. digit)
|
||||
end
|
||||
end
|
||||
|
||||
-- Add call
|
||||
function addCall()
|
||||
if showToast then
|
||||
showToast("Add call not available")
|
||||
end
|
||||
end
|
||||
|
||||
-- Toggle video
|
||||
function toggleVideo()
|
||||
if showToast then
|
||||
showToast("Video call not available")
|
||||
end
|
||||
end
|
||||
|
||||
-- End call
|
||||
function endCall()
|
||||
print("[Calling] Ending call")
|
||||
|
||||
-- Stop timer
|
||||
if timer_id and clearInterval then
|
||||
clearInterval(timer_id)
|
||||
timer_id = nil
|
||||
end
|
||||
|
||||
if showToast then
|
||||
local mins = math.floor(call_state.call_duration / 60)
|
||||
local secs = call_state.call_duration % 60
|
||||
showToast(string.format("Call ended (%02d:%02d)", mins, secs))
|
||||
end
|
||||
|
||||
-- Navigate back
|
||||
if shellGoBack then
|
||||
shellGoBack()
|
||||
end
|
||||
end
|
||||
|
||||
-- Initialize on load
|
||||
simulateConnection()
|
||||
print("[Calling] Content loaded")
|
||||
</script>
|
||||
@@ -1,11 +1,261 @@
|
||||
<!-- Dialer App Content Fragment -->
|
||||
<!-- Styles are in shell.rml -->
|
||||
<!-- Uses classes from components.rcss -->
|
||||
|
||||
<div class="app-content">
|
||||
<div class="app-header">
|
||||
<span class="app-header-title">Phone</span>
|
||||
<!-- Tabs -->
|
||||
<div class="bottom-nav" style="height: 56px; position: relative; top: 0;">
|
||||
<div id="tab-keypad" class="bottom-nav-item active" onclick="switchDialerTab('keypad')">
|
||||
<span style="font-size: 14px; font-weight: 600;">Keypad</span>
|
||||
</div>
|
||||
<div id="tab-recent" class="bottom-nav-item" onclick="switchDialerTab('recent')">
|
||||
<span style="font-size: 14px; font-weight: 600;">Recent</span>
|
||||
</div>
|
||||
<div id="tab-contacts" class="bottom-nav-item" onclick="switchDialerTab('contacts')">
|
||||
<span style="font-size: 14px; font-weight: 600;">Contacts</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-body">
|
||||
<span class="placeholder-text">Dialer App</span>
|
||||
|
||||
<!-- Keypad View -->
|
||||
<div id="view-keypad" style="flex: 1; display: flex; flex-direction: column;">
|
||||
<div class="dial-display" id="dialer-number"></div>
|
||||
|
||||
<div class="dial-pad">
|
||||
<div class="dial-key" onclick="dialDigit('1')">
|
||||
<span class="dial-key-number">1</span>
|
||||
<span class="dial-key-letters"></span>
|
||||
</div>
|
||||
<div class="dial-key" onclick="dialDigit('2')">
|
||||
<span class="dial-key-number">2</span>
|
||||
<span class="dial-key-letters">ABC</span>
|
||||
</div>
|
||||
<div class="dial-key" onclick="dialDigit('3')">
|
||||
<span class="dial-key-number">3</span>
|
||||
<span class="dial-key-letters">DEF</span>
|
||||
</div>
|
||||
<div class="dial-key" onclick="dialDigit('4')">
|
||||
<span class="dial-key-number">4</span>
|
||||
<span class="dial-key-letters">GHI</span>
|
||||
</div>
|
||||
<div class="dial-key" onclick="dialDigit('5')">
|
||||
<span class="dial-key-number">5</span>
|
||||
<span class="dial-key-letters">JKL</span>
|
||||
</div>
|
||||
<div class="dial-key" onclick="dialDigit('6')">
|
||||
<span class="dial-key-number">6</span>
|
||||
<span class="dial-key-letters">MNO</span>
|
||||
</div>
|
||||
<div class="dial-key" onclick="dialDigit('7')">
|
||||
<span class="dial-key-number">7</span>
|
||||
<span class="dial-key-letters">PQRS</span>
|
||||
</div>
|
||||
<div class="dial-key" onclick="dialDigit('8')">
|
||||
<span class="dial-key-number">8</span>
|
||||
<span class="dial-key-letters">TUV</span>
|
||||
</div>
|
||||
<div class="dial-key" onclick="dialDigit('9')">
|
||||
<span class="dial-key-number">9</span>
|
||||
<span class="dial-key-letters">WXYZ</span>
|
||||
</div>
|
||||
<div class="dial-key" onclick="dialDigit('*')">
|
||||
<span class="dial-key-number">*</span>
|
||||
<span class="dial-key-letters"></span>
|
||||
</div>
|
||||
<div class="dial-key" onclick="dialDigit('0')">
|
||||
<span class="dial-key-number">0</span>
|
||||
<span class="dial-key-letters">+</span>
|
||||
</div>
|
||||
<div class="dial-key" onclick="dialDigit('#')">
|
||||
<span class="dial-key-number">#</span>
|
||||
<span class="dial-key-letters"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dial-actions">
|
||||
<div class="btn-icon" onclick="openVideoCall()">
|
||||
<img src="../../icons/camera.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
<div class="dial-call-btn" onclick="makeCall()">
|
||||
<img src="../../icons/phone.tga" style="width: 36px; height: 36px;"/>
|
||||
</div>
|
||||
<div class="btn-icon" onclick="deleteDigit()">
|
||||
<img src="../../icons/back.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recent Calls View -->
|
||||
<div id="view-recent" style="flex: 1; overflow: auto; display: none;">
|
||||
<div class="list">
|
||||
<div class="list-item" onclick="callContact('Mom')">
|
||||
<div class="list-item-avatar" style="background-color: #E91E63;">M</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Mom</span>
|
||||
<span class="list-item-subtitle" style="color: #4CAF50;">Outgoing - 5 min</span>
|
||||
</div>
|
||||
<span style="font-size: 14px; color: #888888;">10:30 AM</span>
|
||||
</div>
|
||||
<div class="list-divider"></div>
|
||||
<div class="list-item" onclick="callContact('John Smith')">
|
||||
<div class="list-item-avatar" style="background-color: #2196F3;">J</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">John Smith</span>
|
||||
<span class="list-item-subtitle" style="color: #F44336;">Missed</span>
|
||||
</div>
|
||||
<span style="font-size: 14px; color: #888888;">Yesterday</span>
|
||||
</div>
|
||||
<div class="list-divider"></div>
|
||||
<div class="list-item" onclick="callContact('Work')">
|
||||
<div class="list-item-avatar" style="background-color: #FF9800;">W</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Work</span>
|
||||
<span class="list-item-subtitle">Incoming - 12 min</span>
|
||||
</div>
|
||||
<span style="font-size: 14px; color: #888888;">Yesterday</span>
|
||||
</div>
|
||||
<div class="list-divider"></div>
|
||||
<div class="list-item" onclick="callContact('Sarah')">
|
||||
<div class="list-item-avatar" style="background-color: #9C27B0;">S</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Sarah</span>
|
||||
<span class="list-item-subtitle" style="color: #4CAF50;">Outgoing - 23 min</span>
|
||||
</div>
|
||||
<span style="font-size: 14px; color: #888888;">Monday</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contacts View -->
|
||||
<div id="view-contacts" style="flex: 1; overflow: auto; display: none;">
|
||||
<div class="search-bar">
|
||||
<img src="../../icons/search.tga" style="width: 24px; height: 24px; margin-right: 12px; opacity: 0.6;"/>
|
||||
<span style="color: #B3B3B3;">Search contacts</span>
|
||||
</div>
|
||||
<div class="list">
|
||||
<div class="list-item" onclick="callContact('Alice Johnson')">
|
||||
<div class="list-item-avatar" style="background-color: #4CAF50;">A</div>
|
||||
<span class="list-item-title">Alice Johnson</span>
|
||||
</div>
|
||||
<div class="list-item" onclick="callContact('Bob Williams')">
|
||||
<div class="list-item-avatar" style="background-color: #2196F3;">B</div>
|
||||
<span class="list-item-title">Bob Williams</span>
|
||||
</div>
|
||||
<div class="list-item" onclick="callContact('Carol Davis')">
|
||||
<div class="list-item-avatar" style="background-color: #9C27B0;">C</div>
|
||||
<span class="list-item-title">Carol Davis</span>
|
||||
</div>
|
||||
<div class="list-item" onclick="callContact('David Miller')">
|
||||
<div class="list-item-avatar" style="background-color: #FF9800;">D</div>
|
||||
<span class="list-item-title">David Miller</span>
|
||||
</div>
|
||||
<div class="list-item" onclick="callContact('Emma Wilson')">
|
||||
<div class="list-item-avatar" style="background-color: #E91E63;">E</div>
|
||||
<span class="list-item-title">Emma Wilson</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
local dialed_number = ""
|
||||
local current_tab = "keypad"
|
||||
|
||||
local function getDoc()
|
||||
return shell_document
|
||||
end
|
||||
|
||||
function switchDialerTab(tab)
|
||||
current_tab = tab
|
||||
local doc = getDoc()
|
||||
if not doc then return end
|
||||
|
||||
local tabs = {"keypad", "recent", "contacts"}
|
||||
for _, t in ipairs(tabs) do
|
||||
local tab_el = doc:GetElementById("tab-" .. t)
|
||||
local view_el = doc:GetElementById("view-" .. t)
|
||||
if tab_el then
|
||||
if t == tab then
|
||||
tab_el:SetClass("active", true)
|
||||
else
|
||||
tab_el:SetClass("active", false)
|
||||
end
|
||||
end
|
||||
if view_el then
|
||||
if t == tab then
|
||||
view_el.style.display = "flex"
|
||||
else
|
||||
view_el.style.display = "none"
|
||||
end
|
||||
end
|
||||
end
|
||||
print("[Dialer] Switched to tab: " .. tab)
|
||||
end
|
||||
|
||||
function dialDigit(digit)
|
||||
dialed_number = dialed_number .. digit
|
||||
updateDisplay()
|
||||
print("[Dialer] Dialed: " .. digit .. " -> " .. dialed_number)
|
||||
end
|
||||
|
||||
function deleteDigit()
|
||||
if #dialed_number > 0 then
|
||||
dialed_number = dialed_number:sub(1, -2)
|
||||
updateDisplay()
|
||||
print("[Dialer] Deleted digit -> " .. dialed_number)
|
||||
end
|
||||
end
|
||||
|
||||
function updateDisplay()
|
||||
local doc = getDoc()
|
||||
if not doc then return end
|
||||
local display = doc:GetElementById("dialer-number")
|
||||
if display then
|
||||
local formatted = dialed_number
|
||||
if #dialed_number > 6 then
|
||||
formatted = dialed_number:sub(1, 3) .. "-" .. dialed_number:sub(4, 6) .. "-" .. dialed_number:sub(7)
|
||||
elseif #dialed_number > 3 then
|
||||
formatted = dialed_number:sub(1, 3) .. "-" .. dialed_number:sub(4)
|
||||
end
|
||||
display.inner_rml = formatted
|
||||
end
|
||||
end
|
||||
|
||||
function makeCall()
|
||||
if #dialed_number > 0 then
|
||||
print("[Dialer] Calling: " .. dialed_number)
|
||||
if showToast then
|
||||
showToast("Calling " .. dialed_number .. "...")
|
||||
end
|
||||
if shellNavigateTo then
|
||||
shellNavigateTo("calling")
|
||||
end
|
||||
else
|
||||
if showToast then
|
||||
showToast("Enter a number to call")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function callContact(name)
|
||||
print("[Dialer] Calling contact: " .. name)
|
||||
if showToast then
|
||||
showToast("Calling " .. name .. "...")
|
||||
end
|
||||
if shellNavigateTo then
|
||||
shellNavigateTo("calling")
|
||||
end
|
||||
end
|
||||
|
||||
function openVideoCall()
|
||||
if #dialed_number > 0 then
|
||||
if showToast then
|
||||
showToast("Video call to " .. dialed_number)
|
||||
end
|
||||
else
|
||||
if showToast then
|
||||
showToast("Enter a number for video call")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
print("[Dialer] Content loaded")
|
||||
</script>
|
||||
|
||||
117
src/main/assets/apps/messages/chat_content.rml
Normal file
117
src/main/assets/apps/messages/chat_content.rml
Normal file
@@ -0,0 +1,117 @@
|
||||
<!-- Chat Content Fragment -->
|
||||
<!-- Uses classes from components.rcss -->
|
||||
|
||||
<div class="app-content">
|
||||
<div class="app-bar">
|
||||
<div class="app-bar-nav" onclick="goBackToMessages()">
|
||||
<img src="../../icons/back.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
<div class="list-item-avatar" id="chat-avatar" style="background-color: #9C27B0; width: 40px; height: 40px; margin-right: 12px;">S</div>
|
||||
<div class="list-item-content" style="flex: 1;">
|
||||
<span class="list-item-title" id="chat-name">Sarah</span>
|
||||
<span class="list-item-subtitle" style="color: #4CAF50;">Online</span>
|
||||
</div>
|
||||
<div class="btn-icon" onclick="startCall()">
|
||||
<img src="../../icons/phone.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Messages Area -->
|
||||
<div class="chat-container" id="messages-area" style="flex: 1; overflow: auto;">
|
||||
<div class="chat-timestamp">Today</div>
|
||||
|
||||
<div class="chat-bubble chat-bubble-received">
|
||||
Hey! How are you doing?
|
||||
</div>
|
||||
|
||||
<div class="chat-bubble chat-bubble-sent">
|
||||
I'm good! Just finished some work.
|
||||
</div>
|
||||
|
||||
<div class="chat-bubble chat-bubble-received">
|
||||
Nice! Are you coming to the party tonight?
|
||||
</div>
|
||||
|
||||
<div class="chat-bubble chat-bubble-sent">
|
||||
Yeah, I'll be there around 8pm
|
||||
</div>
|
||||
|
||||
<div class="chat-bubble chat-bubble-received">
|
||||
Perfect! Can't wait to see you there!
|
||||
</div>
|
||||
|
||||
<div class="chat-bubble chat-bubble-sent">
|
||||
Same here! Should I bring anything?
|
||||
</div>
|
||||
|
||||
<div class="chat-bubble chat-bubble-received">
|
||||
Just yourself! Maybe some snacks if you want
|
||||
</div>
|
||||
|
||||
<div class="chat-bubble chat-bubble-received">
|
||||
Hey! Are you coming to the party tonight?
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Input Area -->
|
||||
<div class="chat-input-container">
|
||||
<div class="btn-icon" onclick="attachFile()">
|
||||
<img src="../../icons/add.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
<input type="text" class="chat-input" id="message-input" placeholder="Message"/>
|
||||
<div class="chat-send-btn" onclick="sendMessage()">
|
||||
<img src="../../icons/send.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function goBackToMessages()
|
||||
print("[Chat] Going back to messages")
|
||||
if shellGoBack then
|
||||
shellGoBack()
|
||||
end
|
||||
end
|
||||
|
||||
function startCall()
|
||||
print("[Chat] Starting call")
|
||||
if showToast then
|
||||
showToast("Calling Sarah...")
|
||||
end
|
||||
if shellNavigateTo then
|
||||
shellNavigateTo("calling")
|
||||
end
|
||||
end
|
||||
|
||||
function attachFile()
|
||||
print("[Chat] Attach file")
|
||||
if showToast then
|
||||
showToast("Attach file")
|
||||
end
|
||||
end
|
||||
|
||||
function sendMessage()
|
||||
local doc = shell_document
|
||||
if doc then
|
||||
local input = doc:GetElementById("message-input")
|
||||
if input and input.value and input.value ~= "" then
|
||||
local msg = input.value
|
||||
print("[Chat] Sending: " .. msg)
|
||||
|
||||
local area = doc:GetElementById("messages-area")
|
||||
if area then
|
||||
local new_msg = [[<div class="chat-bubble chat-bubble-sent">]] .. msg .. [[</div>]]
|
||||
area.inner_rml = area.inner_rml .. new_msg
|
||||
end
|
||||
|
||||
input.value = ""
|
||||
|
||||
if showToast then
|
||||
showToast("Message sent")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
print("[Chat] Content loaded")
|
||||
</script>
|
||||
@@ -1,11 +1,119 @@
|
||||
<!-- Messages App Content Fragment -->
|
||||
<!-- Styles are in shell.rml -->
|
||||
<!-- Uses classes from components.rcss -->
|
||||
|
||||
<div class="app-content">
|
||||
<div class="app-header">
|
||||
<span class="app-header-title">Messages</span>
|
||||
<div class="app-bar">
|
||||
<span class="app-bar-title">Messages</span>
|
||||
<div class="app-bar-actions">
|
||||
<div class="btn-icon" onclick="searchMessages()">
|
||||
<img src="../../icons/search.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-body">
|
||||
<span class="placeholder-text">Messages App</span>
|
||||
|
||||
<div class="list" style="flex: 1; overflow: auto;">
|
||||
<div class="list-item" onclick="openChat('Sarah')">
|
||||
<div class="list-item-avatar" style="background-color: #9C27B0;">S</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title" style="color: #BB86FC;">Sarah</span>
|
||||
<span class="list-item-subtitle" style="color: #FFFFFF;">Hey! Are you coming to the party tonight?</span>
|
||||
</div>
|
||||
<span style="font-size: 14px; color: #888888;">2 min</span>
|
||||
</div>
|
||||
|
||||
<div class="list-divider"></div>
|
||||
|
||||
<div class="list-item" onclick="openChat('John Smith')">
|
||||
<div class="list-item-avatar" style="background-color: #3F51B5;">J</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">John Smith</span>
|
||||
<span class="list-item-subtitle">Thanks for your help yesterday!</span>
|
||||
</div>
|
||||
<span style="font-size: 14px; color: #888888;">1 hr</span>
|
||||
</div>
|
||||
|
||||
<div class="list-divider"></div>
|
||||
|
||||
<div class="list-item" onclick="openChat('Mom')">
|
||||
<div class="list-item-avatar" style="background-color: #E91E63;">M</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title" style="color: #BB86FC;">Mom</span>
|
||||
<span class="list-item-subtitle" style="color: #FFFFFF;">Don't forget to call grandma!</span>
|
||||
</div>
|
||||
<span style="font-size: 14px; color: #888888;">3 hr</span>
|
||||
</div>
|
||||
|
||||
<div class="list-divider"></div>
|
||||
|
||||
<div class="list-item" onclick="openChat('Work Group')">
|
||||
<div class="list-item-avatar" style="background-color: #FF9800;">W</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Work Group</span>
|
||||
<span class="list-item-subtitle">Bob: Meeting moved to 3pm</span>
|
||||
</div>
|
||||
<span style="font-size: 14px; color: #888888;">Yesterday</span>
|
||||
</div>
|
||||
|
||||
<div class="list-divider"></div>
|
||||
|
||||
<div class="list-item" onclick="openChat('Alice Johnson')">
|
||||
<div class="list-item-avatar" style="background-color: #4CAF50;">A</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Alice Johnson</span>
|
||||
<span class="list-item-subtitle">See you at the coffee shop!</span>
|
||||
</div>
|
||||
<span style="font-size: 14px; color: #888888;">Yesterday</span>
|
||||
</div>
|
||||
|
||||
<div class="list-divider"></div>
|
||||
|
||||
<div class="list-item" onclick="openChat('David Miller')">
|
||||
<div class="list-item-avatar" style="background-color: #FF9800;">D</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">David Miller</span>
|
||||
<span class="list-item-subtitle">The project is almost done</span>
|
||||
</div>
|
||||
<span style="font-size: 14px; color: #888888;">Monday</span>
|
||||
</div>
|
||||
|
||||
<div class="list-divider"></div>
|
||||
|
||||
<div class="list-item" onclick="openChat('Emma Wilson')">
|
||||
<div class="list-item-avatar" style="background-color: #E91E63;">E</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Emma Wilson</span>
|
||||
<span class="list-item-subtitle">That was a great movie!</span>
|
||||
</div>
|
||||
<span style="font-size: 14px; color: #888888;">Sunday</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-fab" onclick="newMessage()">
|
||||
<img src="../../icons/edit.tga" style="width: 32px; height: 32px;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function openChat(name)
|
||||
print("[Messages] Opening chat: " .. name)
|
||||
if shellNavigateTo then
|
||||
shellNavigateTo("chat")
|
||||
end
|
||||
end
|
||||
|
||||
function searchMessages()
|
||||
print("[Messages] Search")
|
||||
if showToast then
|
||||
showToast("Search messages")
|
||||
end
|
||||
end
|
||||
|
||||
function newMessage()
|
||||
print("[Messages] New message")
|
||||
if showToast then
|
||||
showToast("New message")
|
||||
end
|
||||
end
|
||||
|
||||
print("[Messages] Content loaded")
|
||||
</script>
|
||||
|
||||
@@ -1,11 +1,175 @@
|
||||
<!-- Music App Content Fragment -->
|
||||
<!-- Styles are in shell.rml -->
|
||||
<!-- Uses classes from components.rcss -->
|
||||
|
||||
<div class="app-content">
|
||||
<div class="app-header">
|
||||
<span class="app-header-title">Music</span>
|
||||
<div class="app-content" style="position: relative;">
|
||||
<div class="app-bar">
|
||||
<span class="app-bar-title">Good afternoon</span>
|
||||
<div class="btn-icon" onclick="openMusicSettings()">
|
||||
<img src="../../icons/settings.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-body">
|
||||
<span class="placeholder-text">Music App</span>
|
||||
|
||||
<div style="flex: 1; overflow: auto; padding-bottom: 100px;">
|
||||
<!-- Quick Access Grid -->
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 8px; padding: 16px;">
|
||||
<div class="quick-card" onclick="openPlaylist('liked')" style="width: 48%;">
|
||||
<div class="quick-card-art" style="background-color: #7c3aed;">L</div>
|
||||
<span class="quick-card-title">Liked Songs</span>
|
||||
</div>
|
||||
<div class="quick-card" onclick="openPlaylist('daily1')" style="width: 48%;">
|
||||
<div class="quick-card-art" style="background-color: #667eea;">D</div>
|
||||
<span class="quick-card-title">Daily Mix 1</span>
|
||||
</div>
|
||||
<div class="quick-card" onclick="openPlaylist('release')" style="width: 48%;">
|
||||
<div class="quick-card-art" style="background-color: #16a34a;">R</div>
|
||||
<span class="quick-card-title">Release Radar</span>
|
||||
</div>
|
||||
<div class="quick-card" onclick="openPlaylist('chill')" style="width: 48%;">
|
||||
<div class="quick-card-art" style="background-color: #f093fb;">C</div>
|
||||
<span class="quick-card-title">Chill Vibes</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recently Played -->
|
||||
<div class="section-header">
|
||||
<span class="section-title">Recently Played</span>
|
||||
<span class="section-action" onclick="showAllRecent()">SEE ALL</span>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; overflow-x: auto; padding: 0 16px; gap: 16px;">
|
||||
<div class="recent-item" onclick="openPlaylist('pop')">
|
||||
<div class="recent-art" style="background-color: #43e97b;">P</div>
|
||||
<div class="recent-title">Pop Hits</div>
|
||||
<div class="recent-subtitle">Playlist</div>
|
||||
</div>
|
||||
<div class="recent-item" onclick="openPlaylist('electronic')">
|
||||
<div class="recent-art" style="background-color: #fa709a;">E</div>
|
||||
<div class="recent-title">Electronic</div>
|
||||
<div class="recent-subtitle">Playlist</div>
|
||||
</div>
|
||||
<div class="recent-item" onclick="openPlaylist('jazz')">
|
||||
<div class="recent-art" style="background-color: #667eea;">J</div>
|
||||
<div class="recent-title">Jazz Classics</div>
|
||||
<div class="recent-subtitle">Playlist</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Made For You -->
|
||||
<div class="section-header">
|
||||
<span class="section-title">Made For You</span>
|
||||
<span class="section-action" onclick="showAllMixes()">SEE ALL</span>
|
||||
</div>
|
||||
|
||||
<div class="playlist-item" onclick="openPlaylist('daily1')">
|
||||
<div class="playlist-art" style="background-color: #4facfe;">1</div>
|
||||
<div class="playlist-info">
|
||||
<div class="playlist-title">Daily Mix 1</div>
|
||||
<div class="playlist-meta">Based on your listening</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="playlist-item" onclick="openPlaylist('daily2')">
|
||||
<div class="playlist-art" style="background-color: #43e97b;">2</div>
|
||||
<div class="playlist-info">
|
||||
<div class="playlist-title">Daily Mix 2</div>
|
||||
<div class="playlist-meta">Electronic, Ambient, Chill</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="playlist-item" onclick="openPlaylist('discover')">
|
||||
<div class="playlist-art" style="background-color: #fa709a;">D</div>
|
||||
<div class="playlist-info">
|
||||
<div class="playlist-title">Discover Weekly</div>
|
||||
<div class="playlist-meta">Your weekly mixtape</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mini Player -->
|
||||
<div class="mini-player" onclick="openNowPlaying()" style="position: absolute; bottom: 0; left: 0; right: 0;">
|
||||
<div class="mini-player-art" id="mini-art" style="background-color: #667eea;">M</div>
|
||||
<div class="mini-player-info">
|
||||
<div class="mini-player-title" id="mini-title">Midnight City</div>
|
||||
<div class="mini-player-artist" id="mini-artist">M83</div>
|
||||
</div>
|
||||
<div class="mini-player-controls">
|
||||
<div class="mini-control-btn" onclick="toggleLike(); event.stopPropagation();">
|
||||
<img src="../../icons/heart.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
<div class="mini-control-btn" id="play-btn" onclick="togglePlay(); event.stopPropagation();">
|
||||
<img id="play-icon" src="../../icons/play.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
local is_playing = false
|
||||
local current_track = {
|
||||
title = "Midnight City",
|
||||
artist = "M83"
|
||||
}
|
||||
|
||||
local function getDoc()
|
||||
return shell_document
|
||||
end
|
||||
|
||||
function togglePlay()
|
||||
is_playing = not is_playing
|
||||
local doc = getDoc()
|
||||
if doc then
|
||||
local icon = doc:GetElementById("play-icon")
|
||||
if icon then
|
||||
icon:SetAttribute("src", is_playing and "../../icons/pause.tga" or "../../icons/play.tga")
|
||||
end
|
||||
end
|
||||
print("[Music] " .. (is_playing and "Playing" or "Paused"))
|
||||
if showToast then
|
||||
showToast(is_playing and "Playing" or "Paused")
|
||||
end
|
||||
end
|
||||
|
||||
function toggleLike()
|
||||
print("[Music] Liked")
|
||||
if showToast then
|
||||
showToast("Added to Liked Songs")
|
||||
end
|
||||
end
|
||||
|
||||
function openPlaylist(id)
|
||||
print("[Music] Opening playlist: " .. id)
|
||||
if showToast then
|
||||
showToast("Playlist: " .. id)
|
||||
end
|
||||
end
|
||||
|
||||
function openNowPlaying()
|
||||
print("[Music] Now playing")
|
||||
if showToast then
|
||||
showToast("Now Playing: " .. current_track.title)
|
||||
end
|
||||
end
|
||||
|
||||
function showAllRecent()
|
||||
print("[Music] Show all recent")
|
||||
if showToast then
|
||||
showToast("Recently played")
|
||||
end
|
||||
end
|
||||
|
||||
function showAllMixes()
|
||||
print("[Music] Show all mixes")
|
||||
if showToast then
|
||||
showToast("Made for you")
|
||||
end
|
||||
end
|
||||
|
||||
function openMusicSettings()
|
||||
print("[Music] Settings")
|
||||
if showToast then
|
||||
showToast("Music settings")
|
||||
end
|
||||
end
|
||||
|
||||
print("[Music] Content loaded")
|
||||
</script>
|
||||
|
||||
@@ -1,11 +1,309 @@
|
||||
<!-- Settings App Content Fragment -->
|
||||
<!-- Styles are in shell.rml -->
|
||||
<!-- Uses classes from components.rcss -->
|
||||
|
||||
<div class="app-content">
|
||||
<div class="app-header">
|
||||
<span class="app-header-title">Settings</span>
|
||||
<div class="app-bar">
|
||||
<span class="app-bar-title">Settings</span>
|
||||
</div>
|
||||
<div class="app-body">
|
||||
<span class="placeholder-text">Settings App</span>
|
||||
|
||||
<div class="search-bar">
|
||||
<img class="search-icon" src="../../icons/search.tga"/>
|
||||
<span class="search-input">Search settings</span>
|
||||
</div>
|
||||
|
||||
<div style="flex: 1; overflow: auto;">
|
||||
<!-- Profile Card -->
|
||||
<div class="list-item" onclick="openProfile()">
|
||||
<div class="list-item-avatar" style="background-color: #BB86FC;">U</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">User</span>
|
||||
<span class="list-item-subtitle">user@mosis.app</span>
|
||||
</div>
|
||||
<span class="list-item-action">></span>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<!-- Network Section -->
|
||||
<div class="list-header">Network</div>
|
||||
|
||||
<div class="list-item" onclick="toggleWifi()">
|
||||
<div class="list-item-icon" style="background-color: #2196F3; border-radius: 24px;">
|
||||
<img src="../../icons/wifi.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Wi-Fi</span>
|
||||
<span id="wifi-status" class="list-item-subtitle">Connected to MosisNetwork</span>
|
||||
</div>
|
||||
<div id="toggle-wifi" class="toggle active">
|
||||
<div class="toggle-thumb"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-item" onclick="toggleBluetooth()">
|
||||
<div class="list-item-icon" style="background-color: #3F51B5; border-radius: 24px;">
|
||||
<img src="../../icons/bluetooth.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Bluetooth</span>
|
||||
<span id="bt-status" class="list-item-subtitle">Off</span>
|
||||
</div>
|
||||
<div id="toggle-bluetooth" class="toggle">
|
||||
<div class="toggle-thumb"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-item" onclick="toggleAirplane()">
|
||||
<div class="list-item-icon" style="background-color: #FF9800; border-radius: 24px;">
|
||||
<img src="../../icons/plane.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Airplane Mode</span>
|
||||
<span class="list-item-subtitle">Off</span>
|
||||
</div>
|
||||
<div id="toggle-airplane" class="toggle">
|
||||
<div class="toggle-thumb"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<!-- Device Section -->
|
||||
<div class="list-header">Device</div>
|
||||
|
||||
<div class="list-item" onclick="openDisplay()">
|
||||
<div class="list-item-icon" style="background-color: #9C27B0; border-radius: 24px;">
|
||||
<img src="../../icons/display.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Display</span>
|
||||
<span class="list-item-subtitle">Brightness, Dark mode</span>
|
||||
</div>
|
||||
<span class="list-item-action">></span>
|
||||
</div>
|
||||
|
||||
<div class="list-item" onclick="openSound()">
|
||||
<div class="list-item-icon" style="background-color: #E91E63; border-radius: 24px;">
|
||||
<img src="../../icons/volume.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Sound</span>
|
||||
<span class="list-item-subtitle">Volume, Ringtone</span>
|
||||
</div>
|
||||
<span class="list-item-action">></span>
|
||||
</div>
|
||||
|
||||
<div class="list-item" onclick="openNotifications()">
|
||||
<div class="list-item-icon" style="background-color: #00BCD4; border-radius: 24px;">
|
||||
<img src="../../icons/notifications.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Notifications</span>
|
||||
<span class="list-item-subtitle">App notifications</span>
|
||||
</div>
|
||||
<span class="list-item-action">></span>
|
||||
</div>
|
||||
|
||||
<div class="list-item" onclick="openBattery()">
|
||||
<div class="list-item-icon" style="background-color: #4CAF50; border-radius: 24px;">
|
||||
<img src="../../icons/battery.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Battery</span>
|
||||
<span class="list-item-subtitle">85% - Not charging</span>
|
||||
</div>
|
||||
<span class="list-item-action">></span>
|
||||
</div>
|
||||
|
||||
<div class="list-item" onclick="openStorage()">
|
||||
<div class="list-item-icon" style="background-color: #795548; border-radius: 24px;">
|
||||
<img src="../../icons/storage.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Storage</span>
|
||||
<span class="list-item-subtitle">32 GB of 128 GB used</span>
|
||||
</div>
|
||||
<span class="list-item-action">></span>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<!-- Privacy Section -->
|
||||
<div class="list-header">Privacy</div>
|
||||
|
||||
<div class="list-item" onclick="toggleLocation()">
|
||||
<div class="list-item-icon" style="background-color: #F44336; border-radius: 24px;">
|
||||
<img src="../../icons/location.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Location</span>
|
||||
<span id="location-status" class="list-item-subtitle">On - High accuracy</span>
|
||||
</div>
|
||||
<div id="toggle-location" class="toggle active">
|
||||
<div class="toggle-thumb"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-item" onclick="openPrivacy()">
|
||||
<div class="list-item-icon" style="background-color: #607D8B; border-radius: 24px;">
|
||||
<img src="../../icons/lock.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">Privacy</span>
|
||||
<span class="list-item-subtitle">Permissions, Data</span>
|
||||
</div>
|
||||
<span class="list-item-action">></span>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<!-- About Section -->
|
||||
<div class="list-header">About</div>
|
||||
|
||||
<div class="list-item" onclick="openAbout()">
|
||||
<div class="list-item-icon" style="background-color: #BB86FC; border-radius: 24px;">
|
||||
<img src="../../icons/info.tga" style="width: 28px; height: 28px;"/>
|
||||
</div>
|
||||
<div class="list-item-content">
|
||||
<span class="list-item-title">About Phone</span>
|
||||
<span class="list-item-subtitle">Mosis v1.0</span>
|
||||
</div>
|
||||
<span class="list-item-action">></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
local settings = {
|
||||
wifi = true,
|
||||
bluetooth = false,
|
||||
airplane = false,
|
||||
location = true
|
||||
}
|
||||
|
||||
local function getDoc()
|
||||
return shell_document
|
||||
end
|
||||
|
||||
function toggleWifi()
|
||||
settings.wifi = not settings.wifi
|
||||
local doc = getDoc()
|
||||
if doc then
|
||||
local toggle = doc:GetElementById("toggle-wifi")
|
||||
local status = doc:GetElementById("wifi-status")
|
||||
if toggle then
|
||||
toggle:SetClass("active", settings.wifi)
|
||||
end
|
||||
if status then
|
||||
status.inner_rml = settings.wifi and "Connected to MosisNetwork" or "Off"
|
||||
end
|
||||
end
|
||||
print("[Settings] Wi-Fi: " .. tostring(settings.wifi))
|
||||
if showToast then
|
||||
showToast(settings.wifi and "Wi-Fi enabled" or "Wi-Fi disabled")
|
||||
end
|
||||
end
|
||||
|
||||
function toggleBluetooth()
|
||||
settings.bluetooth = not settings.bluetooth
|
||||
local doc = getDoc()
|
||||
if doc then
|
||||
local toggle = doc:GetElementById("toggle-bluetooth")
|
||||
local status = doc:GetElementById("bt-status")
|
||||
if toggle then
|
||||
toggle:SetClass("active", settings.bluetooth)
|
||||
end
|
||||
if status then
|
||||
status.inner_rml = settings.bluetooth and "On" or "Off"
|
||||
end
|
||||
end
|
||||
print("[Settings] Bluetooth: " .. tostring(settings.bluetooth))
|
||||
if showToast then
|
||||
showToast(settings.bluetooth and "Bluetooth enabled" or "Bluetooth disabled")
|
||||
end
|
||||
end
|
||||
|
||||
function toggleAirplane()
|
||||
settings.airplane = not settings.airplane
|
||||
local doc = getDoc()
|
||||
if doc then
|
||||
local toggle = doc:GetElementById("toggle-airplane")
|
||||
if toggle then
|
||||
toggle:SetClass("active", settings.airplane)
|
||||
end
|
||||
if settings.airplane then
|
||||
settings.wifi = false
|
||||
settings.bluetooth = false
|
||||
local wt = doc:GetElementById("toggle-wifi")
|
||||
local bt = doc:GetElementById("toggle-bluetooth")
|
||||
if wt then wt:SetClass("active", false) end
|
||||
if bt then bt:SetClass("active", false) end
|
||||
end
|
||||
end
|
||||
print("[Settings] Airplane: " .. tostring(settings.airplane))
|
||||
if showToast then
|
||||
showToast(settings.airplane and "Airplane mode on" or "Airplane mode off")
|
||||
end
|
||||
end
|
||||
|
||||
function toggleLocation()
|
||||
settings.location = not settings.location
|
||||
local doc = getDoc()
|
||||
if doc then
|
||||
local toggle = doc:GetElementById("toggle-location")
|
||||
local status = doc:GetElementById("location-status")
|
||||
if toggle then
|
||||
toggle:SetClass("active", settings.location)
|
||||
end
|
||||
if status then
|
||||
status.inner_rml = settings.location and "On - High accuracy" or "Off"
|
||||
end
|
||||
end
|
||||
print("[Settings] Location: " .. tostring(settings.location))
|
||||
if showToast then
|
||||
showToast(settings.location and "Location enabled" or "Location disabled")
|
||||
end
|
||||
end
|
||||
|
||||
function openProfile()
|
||||
print("[Settings] Profile")
|
||||
if showToast then showToast("User profile") end
|
||||
end
|
||||
|
||||
function openDisplay()
|
||||
print("[Settings] Display")
|
||||
if showToast then showToast("Display settings") end
|
||||
end
|
||||
|
||||
function openSound()
|
||||
print("[Settings] Sound")
|
||||
if showToast then showToast("Sound settings") end
|
||||
end
|
||||
|
||||
function openNotifications()
|
||||
print("[Settings] Notifications")
|
||||
if showToast then showToast("Notification settings") end
|
||||
end
|
||||
|
||||
function openBattery()
|
||||
print("[Settings] Battery")
|
||||
if showToast then showToast("Battery: 85%") end
|
||||
end
|
||||
|
||||
function openStorage()
|
||||
print("[Settings] Storage")
|
||||
if showToast then showToast("Storage: 25% used") end
|
||||
end
|
||||
|
||||
function openPrivacy()
|
||||
print("[Settings] Privacy")
|
||||
if showToast then showToast("Privacy settings") end
|
||||
end
|
||||
|
||||
function openAbout()
|
||||
print("[Settings] About")
|
||||
if showToast then showToast("Mosis Virtual Phone v1.0") end
|
||||
end
|
||||
|
||||
print("[Settings] Content loaded")
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user