mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-08-28 23:01:37 +00:00
462 lines
13 KiB
Lua
462 lines
13 KiB
Lua
local is_open = false
|
|
local open_requested = false
|
|
local notification_focus = false
|
|
local device_payload = nil
|
|
local sim_picker_open = false
|
|
local call_channel = 0
|
|
|
|
Bridge.Debug("debug", "[sky_phone] Client script initialized.", { always = true })
|
|
|
|
local server_callbacks = {
|
|
"device:save",
|
|
"device:factory-reset",
|
|
"account:login",
|
|
"account:register",
|
|
"account:logout",
|
|
"account:devices",
|
|
"account:remove-device",
|
|
"notes:list",
|
|
"notes:create",
|
|
"notes:update",
|
|
"notes:delete",
|
|
"mail:register",
|
|
"mail:login",
|
|
"mail:logout",
|
|
"mail:counts",
|
|
"mail:list",
|
|
"mail:get",
|
|
"mail:get-draft",
|
|
"mail:save-draft",
|
|
"mail:delete-draft",
|
|
"mail:send",
|
|
"mail:set-read",
|
|
"mail:trash",
|
|
"mail:restore",
|
|
"mail:delete-forever",
|
|
"mail:empty-trash",
|
|
"marketplace:list",
|
|
"marketplace:get",
|
|
"marketplace:list-own",
|
|
"marketplace:create",
|
|
"marketplace:update",
|
|
"marketplace:set-status",
|
|
"marketplace:favorite",
|
|
"marketplace:counts",
|
|
"marketplace:list-inquiries",
|
|
"marketplace:get-inquiry",
|
|
"marketplace:send-message",
|
|
"marketplace:make-offer",
|
|
"marketplace:respond-offer",
|
|
"marketplace:report",
|
|
"marketplace:block",
|
|
"pages:list",
|
|
"pages:get",
|
|
"pages:list-own",
|
|
"pages:create",
|
|
"pages:share-citymarkt",
|
|
"pages:react",
|
|
"pages:delete",
|
|
"calendar:list",
|
|
"calendar:create",
|
|
"calendar:update",
|
|
"calendar:delete",
|
|
"sim:insert",
|
|
"sim:eject",
|
|
"contacts:list",
|
|
"contacts:save",
|
|
"contacts:delete",
|
|
"calls:recents",
|
|
"calls:dial",
|
|
"calls:answer",
|
|
"calls:decline",
|
|
"calls:hangup",
|
|
"banking:overview",
|
|
"banking:transfer",
|
|
"messages:conversations",
|
|
"messages:thread",
|
|
"messages:send",
|
|
"messages:media",
|
|
"messages:delete",
|
|
"messages:gifs",
|
|
"darkchat:bootstrap",
|
|
"darkchat:update-profile",
|
|
"darkchat:start",
|
|
"darkchat:thread",
|
|
"darkchat:send",
|
|
"darkchat:media",
|
|
"darkchat:react",
|
|
"darkchat:message-action",
|
|
"darkchat:update-conversation",
|
|
"darkchat:add-contact",
|
|
"darkchat:remove-contact",
|
|
"darkchat:block",
|
|
"darkchat:report",
|
|
"darkchat:clear",
|
|
"gallery:list",
|
|
"media:config",
|
|
}
|
|
|
|
local function get_locale()
|
|
return Locales[Config.Bridge.Locale] or Locales["en"]
|
|
end
|
|
|
|
local function send_open_message()
|
|
if not device_payload then
|
|
return
|
|
end
|
|
|
|
local payload = device_payload
|
|
payload.lang = Config.Bridge.Locale
|
|
payload.locales = get_locale().Nui
|
|
SendNUIMessage({
|
|
type = "app:open",
|
|
data = payload,
|
|
})
|
|
end
|
|
|
|
local function open_phone()
|
|
if is_open or not device_payload then
|
|
return
|
|
end
|
|
|
|
send_open_message()
|
|
end
|
|
|
|
local function close_phone()
|
|
open_requested = false
|
|
if not is_open then
|
|
return
|
|
end
|
|
|
|
is_open = false
|
|
TriggerEvent("sky_phone:nuiClosed")
|
|
SetNuiFocus(notification_focus or sim_picker_open, notification_focus or sim_picker_open)
|
|
SendNUIMessage({ type = "app:close" })
|
|
Bridge.Callbacks.Trigger("sky_phone:device:close", {})
|
|
end
|
|
|
|
local function leave_call_voice()
|
|
if call_channel == 0 then
|
|
return
|
|
end
|
|
if Config.Calls.VoiceProvider == "pma" and GetResourceState("pma-voice") == "started" then
|
|
exports["pma-voice"]:setCallChannel(0)
|
|
end
|
|
call_channel = 0
|
|
end
|
|
|
|
local function join_call_voice(channel)
|
|
if Config.Calls.VoiceProvider ~= "pma" then
|
|
Bridge.Debug("error", "[sky_phone] Unsupported voice provider '%s'.", tostring(Config.Calls.VoiceProvider))
|
|
return false
|
|
end
|
|
if GetResourceState("pma-voice") ~= "started" then
|
|
Bridge.Debug("error", "[sky_phone] Configured pma-voice provider is not started.")
|
|
return false
|
|
end
|
|
call_channel = tonumber(channel) or 0
|
|
exports["pma-voice"]:setCallChannel(call_channel)
|
|
return true
|
|
end
|
|
|
|
if Config.Phone.DevelopmentCommand then
|
|
RegisterCommand(Config.Command, function()
|
|
if is_open then
|
|
close_phone()
|
|
return
|
|
end
|
|
Bridge.Callbacks.Trigger("sky_phone:device:development-open", {})
|
|
end, false)
|
|
end
|
|
|
|
RegisterNUICallback("ui:ready", function(_, cb)
|
|
Bridge.Debug("debug", "[sky_phone] NUI reported ready.", { always = true })
|
|
if open_requested and device_payload then
|
|
send_open_message()
|
|
end
|
|
|
|
cb({ success = true })
|
|
end)
|
|
|
|
RegisterNUICallback("ui:opened", function(_, cb)
|
|
if not open_requested or not device_payload then
|
|
Bridge.Debug(
|
|
"warn",
|
|
"[sky_phone] Ignored a NUI open confirmation without a pending device open.",
|
|
{ always = true }
|
|
)
|
|
cb({ success = false, error = "open_not_requested" })
|
|
return
|
|
end
|
|
|
|
is_open = true
|
|
notification_focus = false
|
|
SetNuiFocus(true, true)
|
|
cb({ success = true })
|
|
end)
|
|
|
|
RegisterNUICallback("close", function(_, cb)
|
|
close_phone()
|
|
cb({ success = true })
|
|
end)
|
|
|
|
RegisterNUICallback("notification:focus", function(data, cb)
|
|
notification_focus = data.active == true and not is_open
|
|
SetNuiFocus(is_open or notification_focus, is_open or notification_focus)
|
|
cb({ success = true })
|
|
end)
|
|
|
|
RegisterNUICallback("sim:picker-close", function(_, cb)
|
|
sim_picker_open = false
|
|
SetNuiFocus(is_open or notification_focus, is_open or notification_focus)
|
|
cb({ success = true })
|
|
end)
|
|
|
|
RegisterNUICallback("map:getPlayerCoords", function(_, cb)
|
|
local coords = GetEntityCoords(PlayerPedId())
|
|
cb({
|
|
success = true,
|
|
data = {
|
|
coords = {
|
|
x = coords.x,
|
|
y = coords.y,
|
|
z = coords.z
|
|
}
|
|
}
|
|
})
|
|
end)
|
|
|
|
local weather_types = {
|
|
[joaat("EXTRASUNNY")] = "sunny",
|
|
[joaat("CLEAR")] = "clear",
|
|
[joaat("CLOUDS")] = "partly_cloudy",
|
|
[joaat("OVERCAST")] = "cloudy",
|
|
[joaat("RAIN")] = "rain",
|
|
[joaat("CLEARING")] = "rain",
|
|
[joaat("THUNDER")] = "thunder",
|
|
[joaat("SMOG")] = "fog",
|
|
[joaat("FOGGY")] = "fog",
|
|
[joaat("NEUTRAL")] = "cloudy",
|
|
[joaat("SNOW")] = "snow",
|
|
[joaat("BLIZZARD")] = "snow",
|
|
[joaat("SNOWLIGHT")] = "snow",
|
|
[joaat("XMAS")] = "snow",
|
|
[joaat("HALLOWEEN")] = "cloudy",
|
|
}
|
|
|
|
local function weather_region(coords)
|
|
if coords.x > 2500.0 and coords.y < -3000.0 then
|
|
return "cayo_perico"
|
|
end
|
|
if coords.y > 900.0 then
|
|
return "blaine_county"
|
|
end
|
|
return "los_santos"
|
|
end
|
|
|
|
RegisterNUICallback("weather:get", function(_, cb)
|
|
local coords = GetEntityCoords(PlayerPedId())
|
|
local weather_hash = GetPrevWeatherTypeHashName()
|
|
local next_weather_hash = GetNextWeatherTypeHashName()
|
|
cb({
|
|
success = true,
|
|
data = {
|
|
condition = weather_types[weather_hash] or "clear",
|
|
nextCondition = weather_types[next_weather_hash] or weather_types[weather_hash] or "clear",
|
|
region = weather_region(coords),
|
|
clock = {
|
|
year = GetClockYear(),
|
|
month = GetClockMonth() + 1,
|
|
day = GetClockDayOfMonth(),
|
|
hour = GetClockHours(),
|
|
minute = GetClockMinutes(),
|
|
},
|
|
windSpeed = math.max(0.0, GetWindSpeed()),
|
|
rainLevel = math.max(0.0, math.min(1.0, GetRainLevel())),
|
|
},
|
|
})
|
|
end)
|
|
|
|
for _, callback_name in ipairs(server_callbacks) do
|
|
RegisterNUICallback(callback_name, function(data, cb)
|
|
local result = Bridge.Callbacks.Trigger("sky_phone:" .. callback_name, data)
|
|
if result then
|
|
cb(result)
|
|
return
|
|
end
|
|
|
|
cb({ success = false, error = "request_failed" })
|
|
end)
|
|
end
|
|
|
|
RegisterNetEvent("sky_phone:device:open", function(data)
|
|
Bridge.Debug(
|
|
"debug",
|
|
"[sky_phone] Client received device open for IMEI %s account_linked=%s.",
|
|
tostring(data.device.imei),
|
|
tostring(data.account ~= nil),
|
|
{ always = true }
|
|
)
|
|
device_payload = data
|
|
open_requested = true
|
|
open_phone()
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:device:updated", function(data)
|
|
device_payload = data
|
|
SendNUIMessage({ type = "device:updated", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:device:invalidated", function()
|
|
open_requested = false
|
|
device_payload = nil
|
|
close_phone()
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:device:error", function(error_code)
|
|
Bridge.Debug(
|
|
"debug",
|
|
"[sky_phone] Client received device error: %s.",
|
|
tostring(error_code),
|
|
{ always = true }
|
|
)
|
|
local message = get_locale().DeviceErrors[error_code] or get_locale().DeviceErrors.default
|
|
Bridge.Framework.Notify("iFruit", message, "error", 5000)
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:mail:changed", function(data)
|
|
SendNUIMessage({ type = "mail:changed", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:mail:new", function(data)
|
|
local mail_locale = get_locale().Nui.Apps.mail
|
|
data.title = mail_locale.name
|
|
data.text = mail_locale.newMessage:gsub("{sender}", tostring(data.sender))
|
|
SendNUIMessage({ type = "mail:new", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:marketplace:changed", function(data)
|
|
SendNUIMessage({ type = "marketplace:changed", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:marketplace:new-message", function(data)
|
|
local marketplace_locale = get_locale().Nui.Apps.citymarkt
|
|
data.title = marketplace_locale.name
|
|
if data.kind == "offer" then
|
|
data.text = marketplace_locale.newOffer
|
|
:gsub("{sender}", tostring(data.sender))
|
|
:gsub("{price}", tostring(data.amount))
|
|
elseif data.kind == "offer-response" and data.action == "accepted" then
|
|
data.text = marketplace_locale.offerAcceptedNotification
|
|
:gsub("{sender}", tostring(data.sender))
|
|
:gsub("{price}", tostring(data.amount))
|
|
elseif data.kind == "offer-response" and data.action == "rejected" then
|
|
data.text = marketplace_locale.offerRejectedNotification
|
|
:gsub("{sender}", tostring(data.sender))
|
|
:gsub("{price}", tostring(data.amount))
|
|
else
|
|
data.text = marketplace_locale.newMessage:gsub("{sender}", tostring(data.sender))
|
|
end
|
|
SendNUIMessage({ type = "marketplace:new-message", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:calendar:reminder", function(data)
|
|
local calendar_locale = get_locale().Nui.Apps.calendar
|
|
data.title = calendar_locale.name
|
|
data.text = calendar_locale.reminder:gsub("{title}", tostring(data.eventTitle))
|
|
SendNUIMessage({ type = "calendar:reminder", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:sim:picker", function(data)
|
|
sim_picker_open = true
|
|
SetNuiFocus(true, true)
|
|
SendNUIMessage({ type = "sim:picker", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:sim:picker-close", function()
|
|
sim_picker_open = false
|
|
SetNuiFocus(is_open or notification_focus, is_open or notification_focus)
|
|
SendNUIMessage({ type = "sim:picker-close" })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:contacts:changed", function()
|
|
SendNUIMessage({ type = "contacts:changed" })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:calls:changed", function()
|
|
SendNUIMessage({ type = "calls:changed" })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:banking:changed", function()
|
|
SendNUIMessage({ type = "banking:changed" })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:messages:changed", function(data)
|
|
SendNUIMessage({ type = "messages:changed", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:messages:new", function(data)
|
|
local messages_locale = get_locale().Nui.Apps.messages
|
|
data.title = messages_locale.name
|
|
data.text = messages_locale.newMessage:gsub("{sender}", tostring(data.sender))
|
|
SendNUIMessage({ type = "messages:new", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:darkchat:changed", function(data)
|
|
SendNUIMessage({ type = "darkchat:changed", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:darkchat:new", function(data)
|
|
local darkchat_locale = get_locale().Nui.Apps.darkchat
|
|
data.title = darkchat_locale.name
|
|
if data.notificationMode == "private" then
|
|
data.sender = nil
|
|
data.text = darkchat_locale.privateNotification
|
|
elseif data.notificationMode == "hidden" then
|
|
data.sender = nil
|
|
data.text = ""
|
|
else
|
|
data.text = darkchat_locale.newMessage:gsub("{sender}", tostring(data.sender))
|
|
end
|
|
SendNUIMessage({ type = "darkchat:new", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:call:incoming", function(data)
|
|
notification_focus = true
|
|
SetNuiFocus(true, true)
|
|
SendNUIMessage({ type = "call:incoming", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:call:state", function(data)
|
|
if data.state == "connected" and data.channel then
|
|
if not join_call_voice(data.channel) then
|
|
TriggerEvent("sky_phone:device:error", "voice_unavailable")
|
|
end
|
|
elseif data.state ~= "ringing" then
|
|
leave_call_voice()
|
|
end
|
|
SendNUIMessage({ type = "call:state", data = data })
|
|
end)
|
|
|
|
CreateThread(function()
|
|
if Config.Phone.DevelopmentCommand then
|
|
TriggerEvent("chat:addSuggestion", "/" .. Config.Command, get_locale().CommandDescription)
|
|
end
|
|
end)
|
|
|
|
AddEventHandler("onResourceStop", function(resource_name)
|
|
if resource_name ~= GetCurrentResourceName() then
|
|
return
|
|
end
|
|
|
|
if is_open or notification_focus then
|
|
SetNuiFocus(false, false)
|
|
end
|
|
|
|
leave_call_voice()
|
|
|
|
if Config.Phone.DevelopmentCommand then
|
|
TriggerEvent("chat:removeSuggestion", "/" .. Config.Command)
|
|
end
|
|
end)
|