diff --git a/README.md b/README.md index c1976ac..8722066 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ Sky Phone is built to be the **free FiveM phone you can choose without accepting | **Inventories** | ox_inventory, qb-inventory, lj-inventory, qs-inventory, codem-inventory, core_inventory, mf-inventory, smx-inventory, hex_4_inventory, and native ESX inventory | | **Calls** | YACA, PMA Voice, SaltyChat | | **Radio** | YACA, PMA Voice, SaltyChat | -| **Housing** | ESX Property, qbx_properties | +| **Housing** | RTX Housing, Quasar Housing, VMS Housing, RX Housing, NoLag Properties, SN Properties, ESX Property, qbx_properties | | **Garages** | Built-in/custom data and a broad set of popular garage providers configured through the bridge | | **Custom app contracts** | Sky Phone, LB Phone, 17Movement, High Phone, Quasar Smartphone, YSeries | | **Languages** | English, German | @@ -525,7 +525,7 @@ Select the provider under `Config.Garage.System`. Vehicle images use the configu ### Housing -Select the provider under `Config.Housing.System`. Automatic mode supports the configured provider priority. +Select `rtx`, `quasar`, `vms`, `rx`, `nolag`, `sn`, `esx_property`, or `qbx_properties` under `Config.Housing.System`. Automatic mode uses `Config.Housing.AutoPriority` and keeps the existing `esx_property` and `qbx_properties` defaults ahead of newly supported providers. Select a provider explicitly when multiple housing resources are running. Each bridge exposes only the capabilities supported by the documented provider API. ### Companies diff --git a/frontend/src/components/PhoneSetupAssistant.contract.test.ts b/frontend/src/components/PhoneSetupAssistant.contract.test.ts index 98054a9..29437f8 100644 --- a/frontend/src/components/PhoneSetupAssistant.contract.test.ts +++ b/frontend/src/components/PhoneSetupAssistant.contract.test.ts @@ -17,7 +17,9 @@ describe('PhoneSetupAssistant contract', () => { expect(source).toContain('WALLPAPER_IDS') expect(source).toContain('setAllAppNotifications') expect(source).toContain('appStore.claimApp') - expect(source).toContain('phone.completeSetup()') + expect(source).toContain('await phone.completeSetup()') + expect(source).toContain(':disabled="setupCompleteBusy"') + expect(source).toContain("phone.t('Setup.ready.saveFailed')") }) it('persists progress and supports resuming or moving backward', () => { diff --git a/frontend/src/components/PhoneSetupAssistant.vue b/frontend/src/components/PhoneSetupAssistant.vue index 06c39f0..f19b8fc 100644 --- a/frontend/src/components/PhoneSetupAssistant.vue +++ b/frontend/src/components/PhoneSetupAssistant.vue @@ -53,6 +53,8 @@ const passcodeLength = ref<4 | 6>(phone.security.length === 4 ? 4 : 6) const notificationsEnabled = ref(true) const notificationSounds = ref(true) const selectedApps = ref(['banking', 'garage', 'skyride']) +const setupCompleteBusy = ref(false) +const setupCompleteError = ref('') const setupApps = ( ['banking', 'garage', 'skyride', 'citymarkt', 'picstagram', 'snake'] as const @@ -204,8 +206,16 @@ function choosePasscodeLength(length: 4 | 6): void { passcodeResetKey.value += 1 } -function finish(): void { - phone.completeSetup() +async function finish(): Promise { + if (setupCompleteBusy.value) return + setupCompleteBusy.value = true + setupCompleteError.value = '' + const completed = await phone.completeSetup() + setupCompleteBusy.value = false + if (!completed) { + setupCompleteError.value = phone.t('Setup.ready.saveFailed') + return + } emit('complete') } @@ -794,12 +804,29 @@ function skipSetupForDevelopment(): void { }} - {{ - phone.t('Setup.ready.enter') - }} + + + {{ phone.t('Setup.ready.enter') }} + +