mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-08-29 04:01:32 +00:00
30559048fd
* FIX - preserve LB custom app lifecycle * FIX - reset LB export aliases before startup * FIX - report competing custom app providers * FIX - identify LB app frames as live NUI * FIX - complete LB custom app compatibility * FIX - provide LB PicChat runtime exports * FIX - route LB PicChat through Sky Phone * FIX - return cached LB equipped phone number * FIX - harden PicChat compatibility migration * ENH - complete modular phone provider and Creator APIs * DOC - document the Sky Phone Creator API --------- Co-authored-by: DerEchteAlec <bycraky@gmail.com> Co-authored-by: DerEchteAlec <alec.schitzkat@luwan.io>
177 lines
5.1 KiB
Lua
177 lines
5.1 KiB
Lua
SkyPhoneCalls = {}
|
|
|
|
local active_call_payload = nil
|
|
local call_channel = 0
|
|
|
|
local function copy_payload(value)
|
|
if type(value) ~= "table" then
|
|
return value
|
|
end
|
|
|
|
local copy = {}
|
|
for key, nested_value in pairs(value) do
|
|
copy[key] = copy_payload(nested_value)
|
|
end
|
|
return copy
|
|
end
|
|
|
|
local function emit_call_changed(call)
|
|
TriggerEvent("sky_phone:client:callChanged", copy_payload(call))
|
|
end
|
|
|
|
local function request_call_action(action, call)
|
|
local result = Bridge.Callbacks.Trigger("sky_phone:calls:" .. action, { id = call.id })
|
|
if not result or not result.success then
|
|
local call_error = result and result.error or "request_failed"
|
|
Bridge.Debug(
|
|
"error",
|
|
"[sky_phone] Call %s request failed: %s.",
|
|
action,
|
|
tostring(call_error)
|
|
)
|
|
return false, call_error
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
local function leave_voice()
|
|
if call_channel == 0 then
|
|
return
|
|
end
|
|
Bridge.Calls.Leave()
|
|
call_channel = 0
|
|
end
|
|
|
|
local function join_voice(channel)
|
|
local next_channel = tonumber(channel) or 0
|
|
if not Bridge.Calls.Join(next_channel) then
|
|
return false
|
|
end
|
|
call_channel = next_channel
|
|
return true
|
|
end
|
|
|
|
function SkyPhoneCalls.Dial(phone_number, company)
|
|
if (phone_number ~= nil and (type(phone_number) ~= "string" or phone_number == ""))
|
|
or (company ~= nil and (type(company) ~= "string" or company == ""))
|
|
or (phone_number == nil and company == nil)
|
|
then
|
|
Bridge.Debug("error", "[sky_phone] Rejected invalid call target.")
|
|
return false, "invalid_request"
|
|
end
|
|
|
|
local result = Bridge.Callbacks.Trigger("sky_phone:calls:dial", {
|
|
company = company,
|
|
phoneNumber = phone_number,
|
|
})
|
|
if not result or not result.success then
|
|
local call_error = result and result.error or "request_failed"
|
|
Bridge.Debug("error", "[sky_phone] Call request failed: %s.", tostring(call_error))
|
|
return false, call_error
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
function SkyPhoneCalls.IsActive()
|
|
return active_call_payload ~= nil
|
|
end
|
|
|
|
function SkyPhoneCalls.GetActive()
|
|
if not active_call_payload then
|
|
return nil
|
|
end
|
|
return copy_payload(active_call_payload)
|
|
end
|
|
|
|
function SkyPhoneCalls.Answer()
|
|
local call = active_call_payload
|
|
if not call or call.state ~= "ringing" or call.direction ~= "incoming" then
|
|
return false, "call_not_found"
|
|
end
|
|
return request_call_action("answer", call)
|
|
end
|
|
|
|
function SkyPhoneCalls.Decline()
|
|
local call = active_call_payload
|
|
if not call or call.state ~= "ringing" or call.direction ~= "incoming" then
|
|
return false, "call_not_found"
|
|
end
|
|
return request_call_action("decline", call)
|
|
end
|
|
|
|
function SkyPhoneCalls.Hangup()
|
|
local call = active_call_payload
|
|
if not call or (call.state ~= "ringing" and call.state ~= "connected") then
|
|
return false, "call_not_found"
|
|
end
|
|
return request_call_action("hangup", call)
|
|
end
|
|
|
|
function SkyPhoneCalls.Terminate()
|
|
local call = active_call_payload
|
|
if not call or (call.state ~= "ringing" and call.state ~= "connected") then
|
|
return false, "call_not_found"
|
|
end
|
|
return request_call_action("terminate", call)
|
|
end
|
|
|
|
function SkyPhoneCalls.ReleaseFocus()
|
|
SkyPhoneFocus.SetCall(false)
|
|
end
|
|
|
|
function SkyPhoneCalls.ReplayNui()
|
|
if active_call_payload then
|
|
SendNUIMessage({ type = "call:state", data = active_call_payload })
|
|
end
|
|
end
|
|
|
|
function SkyPhoneCalls.Reset()
|
|
local had_active_call = active_call_payload ~= nil
|
|
active_call_payload = nil
|
|
SkyPhoneFocus.SetCall(false)
|
|
leave_voice()
|
|
if had_active_call then
|
|
emit_call_changed(nil)
|
|
end
|
|
end
|
|
|
|
RegisterNetEvent("sky_phone:call:incoming", function(data)
|
|
if type(data) ~= "table" or type(data.id) ~= "string" or data.state ~= "ringing" then
|
|
Bridge.Debug("error", "[sky_phone] Rejected invalid incoming call data.")
|
|
return
|
|
end
|
|
active_call_payload = data
|
|
SkyPhoneFocus.SetCall(true)
|
|
emit_call_changed(data)
|
|
TriggerEvent("sky_phone:animation:call", data)
|
|
SendNUIMessage({ type = "call:incoming", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:call:state", function(data)
|
|
if type(data) ~= "table" or type(data.id) ~= "string" or type(data.state) ~= "string" then
|
|
Bridge.Debug("error", "[sky_phone] Rejected invalid call state data.")
|
|
return
|
|
end
|
|
if data.state == "ringing" or data.state == "connected" then
|
|
active_call_payload = data
|
|
end
|
|
if data.state ~= "ringing" then
|
|
SkyPhoneFocus.SetCall(false)
|
|
end
|
|
if data.state ~= "ringing" and data.state ~= "connected" then
|
|
active_call_payload = nil
|
|
end
|
|
if data.state == "connected" and data.channel then
|
|
if not join_voice(data.channel) then
|
|
TriggerEvent("sky_phone:device:error", "voice_unavailable")
|
|
end
|
|
elseif data.state ~= "ringing" then
|
|
leave_voice()
|
|
end
|
|
emit_call_changed(data)
|
|
TriggerEvent("sky_phone:animation:call", data)
|
|
SendNUIMessage({ type = "call:state", data = data })
|
|
end)
|