mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-09-03 05:01:47 +00:00
42ac955052
Add the Companies app, resilient call handling, custom app registry, vendor compatibility, storage policies, frontend bridge, tests, documentation, config, locale, and SQL migrations.
765 lines
24 KiB
Lua
765 lines
24 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 = {
|
|
"security:unlock",
|
|
"security:set-passcode",
|
|
"security:change-passcode",
|
|
"security:disable-passcode",
|
|
"device:save",
|
|
"device:notification-open",
|
|
"notifications:save",
|
|
"custom-app:storage:get",
|
|
"custom-app:storage:set",
|
|
"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",
|
|
"fliptok:register",
|
|
"fliptok:login",
|
|
"fliptok:logout",
|
|
"fliptok:bootstrap",
|
|
"fliptok:feed",
|
|
"fliptok:discover",
|
|
"fliptok:publish",
|
|
"fliptok:react",
|
|
"fliptok:follow",
|
|
"fliptok:comments",
|
|
"fliptok:comment",
|
|
"fliptok:view",
|
|
"fliptok:share",
|
|
"fliptok:profile",
|
|
"fliptok:update-profile",
|
|
"fliptok:activities",
|
|
"fliptok:mark-activities",
|
|
"fliptok:report",
|
|
"fliptok:admin-reports",
|
|
"fliptok:admin-resolve-report",
|
|
"fliptok:block",
|
|
"fliptok:delete",
|
|
"picstagram:register",
|
|
"picstagram:login",
|
|
"picstagram:logout",
|
|
"picstagram:bootstrap",
|
|
"picstagram:feed",
|
|
"picstagram:explore",
|
|
"picstagram:search",
|
|
"picstagram:saved",
|
|
"picstagram:profile",
|
|
"picstagram:update-profile",
|
|
"picstagram:publish-post",
|
|
"picstagram:update-post",
|
|
"picstagram:set-post-status",
|
|
"picstagram:react",
|
|
"picstagram:follow",
|
|
"picstagram:respond-follow",
|
|
"picstagram:comments",
|
|
"picstagram:comment",
|
|
"picstagram:remove-comment",
|
|
"picstagram:publish-story",
|
|
"picstagram:stories",
|
|
"picstagram:view-story",
|
|
"picstagram:story-viewers",
|
|
"picstagram:remove-story",
|
|
"picstagram:activities",
|
|
"picstagram:mark-activities",
|
|
"picstagram:block",
|
|
"picstagram:report",
|
|
"picstagram:admin-reports",
|
|
"picstagram:admin-resolve-report",
|
|
"feather:bootstrap",
|
|
"feather:create-profile",
|
|
"feather:update-profile",
|
|
"feather:feed",
|
|
"feather:explore",
|
|
"feather:network",
|
|
"feather:create-post",
|
|
"feather:react",
|
|
"feather:follow",
|
|
"feather:connections",
|
|
"feather:remove-connection",
|
|
"feather:profile",
|
|
"feather:bookmarks",
|
|
"feather:thread",
|
|
"feather:activities",
|
|
"feather:mark-activities",
|
|
"feather:delete",
|
|
"feather:block",
|
|
"feather:report",
|
|
"calendar:list",
|
|
"calendar:create",
|
|
"calendar:update",
|
|
"calendar:delete",
|
|
"music:bootstrap",
|
|
"music:add-youtube",
|
|
"music:remove-youtube",
|
|
"music:create-playlist",
|
|
"music:rename-playlist",
|
|
"music:delete-playlist",
|
|
"music:add-to-playlist",
|
|
"music:remove-from-playlist",
|
|
"map:markers",
|
|
"map:create-marker",
|
|
"map:delete-marker",
|
|
"crewlink:bootstrap",
|
|
"crewlink:create-profile",
|
|
"crewlink:update-profile",
|
|
"crewlink:create-group",
|
|
"crewlink:update-group",
|
|
"crewlink:delete-group",
|
|
"crewlink:set-active",
|
|
"crewlink:join-code",
|
|
"crewlink:rotate-code",
|
|
"crewlink:nearby",
|
|
"crewlink:invite-nearby",
|
|
"crewlink:respond-invite",
|
|
"crewlink:update-member",
|
|
"crewlink:transfer-owner",
|
|
"crewlink:remove-member",
|
|
"crewlink:leave",
|
|
"crewlink:create-ping",
|
|
"crewlink:remove-ping",
|
|
"crewlink:live",
|
|
"companies:list",
|
|
"companies:get",
|
|
"companies:my-requests",
|
|
"companies:get-request",
|
|
"companies:work-context",
|
|
"companies:work-queue",
|
|
"companies:list-members",
|
|
"companies:create-request",
|
|
"companies:cancel-request",
|
|
"companies:send-message",
|
|
"companies:claim-request",
|
|
"companies:assign-request",
|
|
"companies:update-request-status",
|
|
"companies:update-availability",
|
|
"companies:update-profile",
|
|
"companies:update-hours",
|
|
"companies:update-services",
|
|
"companies:publish-announcement",
|
|
"companies:set-call-availability",
|
|
"companies:call-customer",
|
|
"sim:insert",
|
|
"sim:eject",
|
|
"contacts:list",
|
|
"contacts:save",
|
|
"contacts:delete",
|
|
"calls:recents",
|
|
"calls:dial",
|
|
"calls:answer",
|
|
"calls:decline",
|
|
"calls:hangup",
|
|
"banking:overview",
|
|
"banking:transfer",
|
|
"billing:overview",
|
|
"billing:list",
|
|
"billing:detail",
|
|
"billing:markRead",
|
|
"billing:pay",
|
|
"billing:dispute",
|
|
"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",
|
|
"flare:bootstrap",
|
|
"flare:save-profile",
|
|
"flare:set-discovery",
|
|
"flare:swipe",
|
|
"flare:rewind",
|
|
"flare:unmatch",
|
|
"flare:thread",
|
|
"flare:send",
|
|
"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
|
|
SkyPhoneApps.SendCatalog()
|
|
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
|
|
TriggerEvent("sky_phone:animation:phone", false)
|
|
if not is_open then
|
|
return
|
|
end
|
|
|
|
is_open = false
|
|
SkyPhoneApps.SetPhoneOpen(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 })
|
|
TriggerEvent("sky_phone:client:nuiReady")
|
|
SkyPhoneApps.SendCatalog()
|
|
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
|
|
SkyPhoneApps.SetPhoneOpen(true)
|
|
notification_focus = false
|
|
SetNuiFocus(true, true)
|
|
TriggerEvent("sky_phone:animation:phone", 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)
|
|
|
|
RegisterNUICallback("map:setWaypoint", function(data, cb)
|
|
local coords = type(data) == "table" and data.coords or nil
|
|
local x = type(coords) == "table" and tonumber(coords.x) or nil
|
|
local y = type(coords) == "table" and tonumber(coords.y) or nil
|
|
if not x or not y or x ~= x or y ~= y or math.abs(x) > 10000.0 or math.abs(y) > 10000.0 then
|
|
cb({ success = false, error = "invalid_marker" })
|
|
return
|
|
end
|
|
|
|
SetNewWaypoint(x, y)
|
|
cb({ success = true })
|
|
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)
|
|
|
|
local function garage_vehicle_kind(model_hash, fallback)
|
|
if IsThisModelABoat(model_hash) then
|
|
return "boat"
|
|
end
|
|
if IsThisModelAPlane(model_hash) then
|
|
return "plane"
|
|
end
|
|
if IsThisModelAHeli(model_hash) then
|
|
return "helicopter"
|
|
end
|
|
if IsThisModelABike(model_hash) or IsThisModelABicycle(model_hash) then
|
|
return "bike"
|
|
end
|
|
return fallback
|
|
end
|
|
|
|
RegisterNUICallback("garage:vehicles", function(data, cb)
|
|
local result = Bridge.Callbacks.Trigger("sky_phone:garage:vehicles", data)
|
|
if not result or not result.success or type(result.data) ~= "table" then
|
|
cb(result or { success = false, error = "request_failed" })
|
|
return
|
|
end
|
|
for _, vehicle in ipairs(result.data.vehicles or {}) do
|
|
local model_hash = tonumber(vehicle.model)
|
|
if not model_hash and type(vehicle.model) == "string" and vehicle.model ~= "" then
|
|
model_hash = joaat(vehicle.model)
|
|
end
|
|
if model_hash then
|
|
local display_name = GetDisplayNameFromVehicleModel(model_hash)
|
|
local label = display_name and GetLabelText(display_name) or nil
|
|
if label and label ~= "NULL" and label ~= "CARNOTFOUND" then
|
|
vehicle.name = label
|
|
elseif type(vehicle.model) == "string" and vehicle.model ~= "" then
|
|
vehicle.name = vehicle.model
|
|
end
|
|
vehicle.kind = garage_vehicle_kind(model_hash, vehicle.kind)
|
|
end
|
|
end
|
|
cb(result)
|
|
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
|
|
TriggerEvent("sky_phone:animation:reset")
|
|
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:companies:changed", function(data)
|
|
SendNUIMessage({ type = "companies:changed", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:companies:notification", function(data)
|
|
local companies_locale = get_locale().Nui.Apps.companies
|
|
data.title = companies_locale.name
|
|
data.text = companies_locale.notifications[data.kind]
|
|
or companies_locale.notifications.requestUpdated
|
|
SendNUIMessage({ type = "companies:notification", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:fliptok:command-feedback", function(data)
|
|
Bridge.Framework.Notify("FlipTok", data.message, data.notificationType, 5000)
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:fliptok:verification-changed", function(data)
|
|
SendNUIMessage({ type = "fliptok:verification-changed", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:fliptok:new", function(data)
|
|
local fliptok_locale = get_locale().Nui.Apps.fliptok
|
|
local notification_text = fliptok_locale.notifications[data.kind] or fliptok_locale.notifications.default
|
|
data.title = fliptok_locale.name
|
|
data.text = notification_text:gsub("{actor}", tostring(data.actor or ""))
|
|
SendNUIMessage({ type = "fliptok:new", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:picstagram:command-feedback", function(data)
|
|
Bridge.Framework.Notify("Picstagram", data.message, data.notificationType, 5000)
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:picstagram:verification-changed", function(data)
|
|
SendNUIMessage({ type = "picstagram:verification-changed", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:picstagram:new", function(data)
|
|
local picstagram_locale = get_locale().Nui.Apps.picstagram
|
|
local notification_text = picstagram_locale.notifications[data.kind] or picstagram_locale.notifications.default
|
|
data.title = picstagram_locale.name
|
|
data.text = notification_text:gsub("{actor}", tostring(data.actor or ""))
|
|
SendNUIMessage({ type = "picstagram:new", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:feather:new", function(data)
|
|
local feather_locale = get_locale().Nui.Apps.feather
|
|
local notification_text = feather_locale.notifications[data.kind] or feather_locale.notifications.default
|
|
data.title = feather_locale.name
|
|
data.text = notification_text:gsub("{actor}", tostring(data.actor or ""))
|
|
SendNUIMessage({ type = "feather:new", 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:flare:match", function(data)
|
|
local flare_locale = get_locale().Nui.Apps.flare
|
|
data.title = flare_locale.name
|
|
data.text = flare_locale.newMatchNotification:gsub("{sender}", tostring(data.sender))
|
|
SendNUIMessage({ type = "flare:new-match", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:flare:message", function(data)
|
|
local flare_locale = get_locale().Nui.Apps.flare
|
|
data.title = flare_locale.name
|
|
data.text = flare_locale.newMessageNotification:gsub("{sender}", tostring(data.sender))
|
|
SendNUIMessage({ type = "flare:new-message", 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:billing:changed", function()
|
|
SendNUIMessage({ type = "billing:changed" })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:billing:new", function(data)
|
|
local billing_locale = get_locale().Nui.Apps.billing
|
|
data.title = billing_locale.name
|
|
data.text = billing_locale.notifications.newInvoice
|
|
:gsub("{issuer}", tostring(data.issuer))
|
|
:gsub("{amount}", ("%s %s"):format(tostring(data.amount), Config.Billing.Currency))
|
|
SendNUIMessage({ type = "billing:new", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:crewlink:changed", function(data)
|
|
SendNUIMessage({ type = "crewlink:changed", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:crewlink:notification", function(data)
|
|
local crewlink_locale = get_locale().Nui.Apps.crewlink
|
|
local notification_text = crewlink_locale.notifications[data.kind]
|
|
or crewlink_locale.notifications.default
|
|
data.title = crewlink_locale.name
|
|
data.text = notification_text
|
|
:gsub("{actor}", tostring(data.actor or ""))
|
|
:gsub("{group}", tostring(data.groupName or ""))
|
|
:gsub("{ping}", tostring(data.pingLabel or ""))
|
|
SendNUIMessage({ type = "crewlink:notification", data = data })
|
|
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)
|
|
TriggerEvent("sky_phone:animation:call", data)
|
|
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
|
|
TriggerEvent("sky_phone:animation:call", data)
|
|
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
|
|
|
|
TriggerEvent("sky_phone:animation:reset")
|
|
leave_call_voice()
|
|
|
|
if Config.Phone.DevelopmentCommand then
|
|
TriggerEvent("chat:removeSuggestion", "/" .. Config.Command)
|
|
end
|
|
end)
|