ADD - share own contact from Control Center

This commit is contained in:
smx.pusha
2026-08-12 09:12:10 +02:00
parent 25ae1b31c1
commit 65e30dc32c
6 changed files with 130 additions and 26 deletions
+46 -7
View File
@@ -10,6 +10,7 @@ import {
Pause,
Plane,
Play,
RadioTower,
Signal,
SkipBack,
SkipForward,
@@ -30,6 +31,8 @@ import { useRouter } from 'vue-router'
import { usePhoneStore } from '@/stores/phone'
import { useMusicStore } from '@/stores/music'
import { useEasyShareStore } from '@/stores/easyshare'
import type { EasySharePayload } from '@/types/easyshare'
import { nuiCall } from '@/utils/nui'
const props = defineProps<{ opened: boolean }>()
@@ -44,6 +47,7 @@ type ConnectivityPreference =
const phone = usePhoneStore()
const music = useMusicStore()
const easyShare = useEasyShareStore()
const router = useRouter()
const panel = ref<HTMLElement | null>(null)
const brightness = ref(phone.preferences.settings.screenBrightness)
@@ -56,6 +60,7 @@ const volume = ref(
)
const flashlightActive = ref(false)
const flashlightPending = ref(false)
const easySharePending = ref(false)
const previousAlertVolume = ref(volume.value || 75)
const inactiveGlassColors = {
@@ -87,6 +92,10 @@ const flashlightColors = computed(() =>
}
: inactiveGlassColors,
)
const easyShareColors = {
bgIos: 'bg-[#0a84ff]',
shadowIos: 'shadow-ios-dark-glass',
}
const brightnessStyle = computed<CSSProperties>(() => ({
'--control-level': `${brightness.value}%`,
}))
@@ -202,6 +211,23 @@ async function toggleFlashlight(): Promise<void> {
flashlightPending.value = false
}
async function shareOwnContact(): Promise<void> {
if (easySharePending.value) return
easySharePending.value = true
const response = await nuiCall<EasySharePayload>('easyshare:own-contact')
easySharePending.value = false
if (!response.success || !response.data) {
console.error(
'[ControlCenter] Could not load own EasyShare contact.',
response.error,
)
return
}
emit('close')
easyShare.open(response.data)
await easyShare.showNearby()
}
function openApp(path: string): void {
emit('close')
void router.push(path)
@@ -360,9 +386,7 @@ onBeforeUnmount(() => {
</div>
<div class="control-center__middle-grid">
<div
class="control-center__round-control control-center__round-control--wide"
>
<div class="control-center__round-control">
<k-glass
component="button"
type="button"
@@ -385,6 +409,20 @@ onBeforeUnmount(() => {
</k-glass>
</div>
<div class="control-center__round-control">
<k-glass
component="button"
type="button"
class="control-center__round-button control-center__round-button--easyshare"
:colors="easyShareColors"
:disabled="easySharePending || !phone.device?.sim"
:aria-label="phone.t('ControlCenter.easyShareContact')"
@click="shareOwnContact"
>
<RadioTower aria-hidden="true" />
</k-glass>
</div>
<k-glass
class="control-center__slider control-center__slider--brightness"
:colors="inactiveGlassColors"
@@ -712,10 +750,6 @@ onBeforeUnmount(() => {
justify-content: center;
}
.control-center__round-control--wide {
grid-column: 1 / span 2;
}
.control-center__round-control > span,
.control-center__quick-action > span {
width: 100%;
@@ -746,6 +780,11 @@ onBeforeUnmount(() => {
color: #ff453a;
}
.control-center__round-button--easyshare {
background: #0a84ff !important;
box-shadow: 0 8px 22px rgb(10 132 255 / 34%) !important;
}
.control-center__focus-button {
display: flex;
grid-column: 1 / span 2;
+1
View File
@@ -3375,6 +3375,7 @@ const defaultLocales: LocaleTree = {
camera: 'Camera',
cellular: 'Cellular Data',
close: 'Close Control Center',
easyShareContact: 'Share my contact with nearby players',
flashlight: 'Flashlight',
focus: 'Focus',
label: 'Control Center',
+15
View File
@@ -6868,6 +6868,21 @@ app.post('/api/:endpoint', (request, response) => {
})
return
}
if (endpoint === 'easyshare:own-contact') {
response.json({
success: true,
data: {
appId: 'phone',
copyText: 'Alex Morgan\n5551234567',
id: 'self',
kind: 'contact',
meta: { name: 'Alex Morgan', phoneNumber: '5551234567' },
subtitle: '5551234567',
title: 'Alex Morgan',
},
})
return
}
if (endpoint === 'easyshare:set-visibility') {
easyShareVisibility = request.body.visibility
response.json({ success: true, data: { visibility: easyShareVisibility } })
+1 -1
View File
@@ -72,7 +72,7 @@ Locales["en"] = {
},
ControlCenter = {
airplaneMode = "Airplane Mode", bluetooth = "Bluetooth", brightness = "Brightness", calculator = "Calculator",
camera = "Camera", cellular = "Cellular Data", close = "Close Control Center", flashlight = "Flashlight",
camera = "Camera", cellular = "Cellular Data", close = "Close Control Center", easyShareContact = "Share my contact with nearby players", flashlight = "Flashlight",
focus = "Focus", label = "Control Center", media = "Media", muteRingtone = "Mute ringtone and notifications", next = "Next track", notPlaying = "Not Playing",
open = "Open Control Center", play = "Play", previous = "Previous track", quickActions = "Quick actions",
timer = "Timer", unmuteRingtone = "Unmute ringtone and notifications", volume = "Volume", wifi = "Wi-Fi",
+1
View File
@@ -217,6 +217,7 @@ local server_callbacks = {
"messages:delete",
"messages:gifs",
"easyshare:bootstrap",
"easyshare:own-contact",
"easyshare:set-visibility",
"easyshare:request",
"easyshare:respond",
+66 -18
View File
@@ -604,25 +604,36 @@ local function sanitize_payload(source, device, data)
local condition, owner_params = owner_condition(device)
if data.kind == "contact" and type(payload.id) == "string" then
local params = { payload.id }
append_params(params, owner_params)
local rows = Bridge.Database.Query(([[
SELECT `name`, `phone_number`, `organization`, `notes`
FROM `sky_phone_contacts` WHERE `contact_id` = ? AND %s LIMIT 1
]]):format(condition), params)
local contact = rows[1]
if not contact then
return nil, "not_owned"
if app_id == "phone" and payload.id == "self" then
local contact = canonical_own_contact(source, device)
if not contact then
return nil, "sim_required"
end
payload.title = contact.title
payload.subtitle = contact.subtitle
payload.copyText = contact.copyText
payload.meta = contact.meta
else
local params = { payload.id }
append_params(params, owner_params)
local rows = Bridge.Database.Query(([[
SELECT `name`, `phone_number`, `organization`, `notes`
FROM `sky_phone_contacts` WHERE `contact_id` = ? AND %s LIMIT 1
]]):format(condition), params)
local contact = rows[1]
if not contact then
return nil, "not_owned"
end
payload.title = contact.name
payload.subtitle = contact.phone_number
payload.copyText = ("%s\n%s"):format(contact.name, contact.phone_number)
payload.meta = {
name = contact.name,
notes = contact.notes,
organization = contact.organization,
phoneNumber = contact.phone_number,
}
end
payload.title = contact.name
payload.subtitle = contact.phone_number
payload.copyText = ("%s\n%s"):format(contact.name, contact.phone_number)
payload.meta = {
name = contact.name,
notes = contact.notes,
organization = contact.organization,
phoneNumber = contact.phone_number,
}
elseif data.kind == "note" and type(payload.id) == "string" then
local params = { payload.id }
append_params(params, owner_params)
@@ -808,6 +819,25 @@ local function apply_received_payload(transfer)
return true
end
local function canonical_own_contact(source, device)
if not device.phone_number then
return nil
end
local name = display_name(source)
return {
appId = "phone",
kind = "contact",
id = "self",
title = name,
subtitle = device.phone_number,
copyText = ("%s\n%s"):format(name, device.phone_number),
meta = {
name = name,
phoneNumber = device.phone_number,
},
}
end
local function advance_transfer(id)
local transfer = active_transfers[id]
if not transfer or transfer.status ~= "transferring" then
@@ -890,6 +920,24 @@ Bridge.Callbacks.Register("sky_phone:easyshare:bootstrap", function(source)
}
end)
Bridge.Callbacks.Register("sky_phone:easyshare:own-contact", function(source)
if not Config.EasyShare.Enabled then
return { success = false, error = "disabled" }
end
if not SkyPhone.AllowOperation(source, "easyshare_own_contact", Config.EasyShare.BootstrapRequestsPerMinute, 60) then
return { success = false, error = "rate_limited" }
end
local device, error_response = current_device(source)
if not device then
return error_response
end
local payload = canonical_own_contact(source, device)
if not payload then
return { success = false, error = "sim_required" }
end
return { success = true, data = payload }
end)
Bridge.Callbacks.Register("sky_phone:easyshare:set-visibility", function(source, data)
if not Config.EasyShare.Enabled then
return { success = false, error = "disabled" }