ENH - merge Picstagram Sky UI updates

Merge the Picstagram Sky UI work and its dependent phone, media, voice, gallery, app store, setup, and UI parity updates into weather-app.

Resolve the frontend development port configuration and retain the Sky UI EasyShare implementation. Frontend validation and local resource deployment completed; included configuration, locale, and SQL updates require no separate migration step beyond this merge.
This commit is contained in:
Type
2026-08-14 17:12:31 +02:00
195 changed files with 29814 additions and 6854 deletions
+53 -11
View File
@@ -16,6 +16,7 @@ import PhoneMediaCapture from '@/components/PhoneMediaCapture.vue'
import PhoneMemoRecorder from '@/components/PhoneMemoRecorder.vue'
import PhoneLockScreen from '@/components/PhoneLockScreen.vue'
import PhonePasscode from '@/components/PhonePasscode.vue'
import PhoneSetupAssistant from '@/components/PhoneSetupAssistant.vue'
import PhoneNotifications from '@/components/PhoneNotifications.vue'
import NotificationPhonePreview from '@/components/NotificationPhonePreview.vue'
import PhoneStatusBar from '@/components/PhoneStatusBar.vue'
@@ -204,7 +205,15 @@ type PicstagramVerificationData = {
type PicstagramNotificationData = {
actor?: string
device?: PhoneNotificationDevicePayload
kind?: 'like' | 'comment' | 'follow' | 'follow_request' | 'verified'
kind?:
| 'like'
| 'comment'
| 'comment_like'
| 'reply'
| 'follow'
| 'follow_request'
| 'request_accepted'
| 'verified'
postId?: string
text?: string
title?: string
@@ -244,6 +253,9 @@ const PHONE_PORTRAIT_WIDTH = 390
const PHONE_PORTRAIT_HEIGHT = 844
const MIN_PRODUCTION_PHONE_ZOOM = 260 / PHONE_PORTRAIT_WIDTH
const isDevelopment = import.meta.env.DEV
const developmentParameters = new URLSearchParams(window.location.search)
const developmentLockScreenPreview =
isDevelopment && developmentParameters.has('lockScreenPreview')
const phone = usePhoneStore()
const account = useAccountStore()
@@ -290,11 +302,19 @@ const passcodeError = ref('')
const passcodeResetKey = ref(0)
const passcodeRetrySeconds = ref(0)
const passcodeVisible = ref(false)
const setupPreviewDismissed = ref(false)
const pendingUnlockRoute = ref<string | null>(null)
const unlockedServicesLoaded = ref(false)
const controlCenterOpened = ref(false)
const activitySuspended = ref(false)
const simPicker = ref<SimPickerPayload | null>(null)
const setupRequired = computed(
() =>
!phone.preferences.settings.setupCompleted ||
(isDevelopment &&
developmentParameters.has('setupPreview') &&
!setupPreviewDismissed.value),
)
const systemColorScheme = window.matchMedia('(prefers-color-scheme: dark)')
const viewportScale = ref(getViewportScale())
const phoneBaseZoom = computed(
@@ -475,6 +495,16 @@ function loadUnlockedPhoneData(): void {
}
}
function completePhoneSetup(): void {
setupPreviewDismissed.value = true
isLocked.value = false
isUnlocking.value = false
passcodeVisible.value = false
controlCenterOpened.value = false
void router.replace('/')
loadUnlockedPhoneData()
}
async function hydrateDevelopmentPhone(): Promise<void> {
const response = await nuiCall<PhoneOpenPayload>('development:bootstrap')
if (response.success && response.data) {
@@ -1222,7 +1252,6 @@ onMounted(() => {
}
}, 1000)
if (isDevelopment) {
const developmentParameters = new URLSearchParams(window.location.search)
void hydrateDevelopmentPhone()
if (developmentParameters.has('simPickerPreview')) {
simPicker.value = {
@@ -1293,7 +1322,9 @@ watch(
}
return
}
isLocked.value = true
isLocked.value = setupRequired.value
? false
: !isDevelopment || developmentLockScreenPreview
unlockedServicesLoaded.value = false
controlCenterOpened.value = false
weather.start()
@@ -1310,7 +1341,8 @@ watch(
startPasscodeLock(passcodeRetrySeconds.value)
}
phone.setLaunchOrigin(null)
void router.replace('/')
if (isLocked.value || setupRequired.value) void router.replace('/')
else loadUnlockedPhoneData()
},
)
@@ -1416,29 +1448,35 @@ onBeforeUnmount(() => {
v-if="!isLocked"
:active-call-return="showActiveCallReturn"
:control-center-opened="controlCenterOpened"
lockable
:interactive="!setupRequired"
:lockable="!setupRequired"
@active-call="returnToActiveCall"
@control-center="toggleControlCenter"
@lock="lockPhone"
/>
<SpringboardView v-if="!isDevelopmentRoute" />
<SpringboardView v-if="!isDevelopmentRoute && !setupRequired" />
<RouterView v-slot="{ Component }">
<Transition :name="appTransitionName">
<component
:is="Component"
v-if="isAppRoute || isDevelopmentRoute"
:key="route.path"
v-if="
!setupRequired && (isAppRoute || isDevelopmentRoute)
"
:key="
isDevelopmentRoute ? String(route.name) : route.path
"
/>
</Transition>
</RouterView>
<PhoneHomeIndicator v-if="!isLocked" />
<PhoneHomeIndicator v-if="!isLocked && !setupRequired" />
<PhoneControlCenter
v-if="!setupRequired"
:opened="controlCenterOpened"
@close="controlCenterOpened = false"
/>
<Transition name="lock-screen" @after-leave="completeUnlock">
<PhoneLockScreen
v-if="isLocked"
v-if="isLocked && !setupRequired"
:notifications="notifications.lockScreenNotifications"
@camera="unlockCamera"
@clear-notifications="notifications.clearLockScreen"
@@ -1449,7 +1487,7 @@ onBeforeUnmount(() => {
</Transition>
<Transition name="lock-screen">
<PhonePasscode
v-if="isLocked && passcodeVisible"
v-if="isLocked && passcodeVisible && !setupRequired"
:busy="passcodeBusy"
:disabled="passcodeRetrySeconds > 0"
:error="passcodeError"
@@ -1467,6 +1505,10 @@ onBeforeUnmount(() => {
@complete="submitUnlockPasscode"
/>
</Transition>
<PhoneSetupAssistant
v-if="setupRequired"
@complete="completePhoneSetup"
/>
<PhoneNotifications
:notification="notifications.current"
@close="notifications.dismissCurrent()"