mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-09-04 17:23:25 +00:00
ENH - rework homescreen editing and widgets
This commit is contained in:
@@ -1,13 +1,12 @@
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import {
|
||||
DEFAULT_INSTALLED_PHONE_APP_IDS,
|
||||
} from '@/config/apps'
|
||||
import { DEFAULT_INSTALLED_PHONE_APP_IDS } from '@/config/apps'
|
||||
import { useAppStoreStore } from '@/stores/app-store'
|
||||
import {
|
||||
getHomeFolder,
|
||||
HOME_GRID_PAGE_SIZE,
|
||||
HOME_LAYOUT_VERSION,
|
||||
removeHomeApp,
|
||||
} from '@/utils/homeLayout'
|
||||
|
||||
@@ -112,7 +111,7 @@ describe('app store', () => {
|
||||
})
|
||||
|
||||
expect(apps.claimedApps).toEqual(['external-radio'])
|
||||
expect(apps.homeLayout.version).toBe(5)
|
||||
expect(apps.homeLayout.version).toBe(HOME_LAYOUT_VERSION)
|
||||
expect(apps.homeLayout.grid).toContain('external-radio')
|
||||
const pageAppCount = apps.homeLayout.grid
|
||||
.slice(0, HOME_GRID_PAGE_SIZE)
|
||||
@@ -122,7 +121,7 @@ describe('app store', () => {
|
||||
expect(mocks.phone.saveDeviceNamespace).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('keeps external app state from current version 5 layouts', () => {
|
||||
it('keeps external app state from current layouts', () => {
|
||||
const apps = useAppStoreStore()
|
||||
|
||||
apps.hydrate({
|
||||
@@ -131,7 +130,8 @@ describe('app store', () => {
|
||||
dock: [],
|
||||
grid: ['external-radio'],
|
||||
hidden: [],
|
||||
version: 5,
|
||||
pageCount: 1,
|
||||
version: HOME_LAYOUT_VERSION,
|
||||
},
|
||||
launchCounts: { 'external-radio': 3 },
|
||||
})
|
||||
@@ -142,7 +142,7 @@ describe('app store', () => {
|
||||
expect(mocks.phone.saveDeviceNamespace).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('persists a page-aware version 3 to version 5 migration once', () => {
|
||||
it('persists a page-aware version 3 migration once', () => {
|
||||
const apps = useAppStoreStore()
|
||||
const grid = Array.from({ length: 40 }, () => null as string | null)
|
||||
grid[20] = 'external-page-two'
|
||||
@@ -152,7 +152,7 @@ describe('app store', () => {
|
||||
homeLayout: { dock: [], grid, hidden: [], version: 3 },
|
||||
})
|
||||
|
||||
expect(apps.homeLayout.version).toBe(5)
|
||||
expect(apps.homeLayout.version).toBe(HOME_LAYOUT_VERSION)
|
||||
expect(apps.homeLayout.grid[20]).not.toBe('external-page-two')
|
||||
expect(apps.homeLayout.grid[24]).toBe('external-page-two')
|
||||
expect(mocks.phone.saveDeviceNamespace).toHaveBeenCalledTimes(1)
|
||||
@@ -331,6 +331,53 @@ describe('app store', () => {
|
||||
expect(mocks.phone.saveDeviceNamespace).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('persists widget reflow without pulling apps back a page', () => {
|
||||
const apps = useAppStoreStore()
|
||||
apps.hydrate(null)
|
||||
mocks.phone.saveDeviceNamespace.mockClear()
|
||||
const originalApps = apps.homeLayout.grid.filter(Boolean)
|
||||
|
||||
expect(
|
||||
apps.applyWidgetGridCapacities(
|
||||
[10, HOME_GRID_PAGE_SIZE],
|
||||
[HOME_GRID_PAGE_SIZE, 10],
|
||||
),
|
||||
).toBe(true)
|
||||
expect(
|
||||
apps.homeLayout.grid.slice(0, HOME_GRID_PAGE_SIZE).filter(Boolean),
|
||||
).toEqual(originalApps.slice(0, 10))
|
||||
expect(
|
||||
apps.homeLayout.grid
|
||||
.slice(HOME_GRID_PAGE_SIZE, HOME_GRID_PAGE_SIZE * 2)
|
||||
.filter(Boolean),
|
||||
).toEqual(originalApps.slice(10))
|
||||
expect(mocks.phone.saveDeviceNamespace).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('persists and restores an otherwise empty extra page', () => {
|
||||
const apps = useAppStoreStore()
|
||||
apps.hydrate(null)
|
||||
mocks.phone.saveDeviceNamespace.mockClear()
|
||||
|
||||
expect(apps.addHomePage()).toBe(true)
|
||||
expect(apps.homeLayout.pageCount).toBe(2)
|
||||
expect(mocks.phone.saveDeviceNamespace).toHaveBeenCalledTimes(1)
|
||||
|
||||
const persisted = mocks.phone.saveDeviceNamespace.mock.calls[0]?.[1] as {
|
||||
homeLayout: typeof apps.homeLayout
|
||||
}
|
||||
apps.hydrate({
|
||||
...persisted,
|
||||
homeLayout: {
|
||||
...persisted.homeLayout,
|
||||
grid: persisted.homeLayout.grid.slice(0, HOME_GRID_PAGE_SIZE),
|
||||
},
|
||||
})
|
||||
|
||||
expect(apps.homeLayout.pageCount).toBe(2)
|
||||
expect(apps.homeLayout.grid).toHaveLength(HOME_GRID_PAGE_SIZE * 2)
|
||||
})
|
||||
|
||||
it('persists the complete folder lifecycle through store actions', () => {
|
||||
const apps = useAppStoreStore()
|
||||
apps.hydrate(null)
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
moveHomeApp,
|
||||
moveHomeAppToGridPage,
|
||||
parseHomeLayout,
|
||||
reflowHomeGridForWidgetChange,
|
||||
renameHomeFolder,
|
||||
removeHomeApp,
|
||||
restoreHomeApp,
|
||||
@@ -230,7 +231,10 @@ export const useAppStoreStore = defineStore('app-store', {
|
||||
? (data.homeLayout as { version?: unknown }).version
|
||||
: undefined
|
||||
const supportsPersistedExternalApps =
|
||||
layoutVersion === 3 || layoutVersion === 4 || layoutVersion === 5
|
||||
layoutVersion === 3 ||
|
||||
layoutVersion === 4 ||
|
||||
layoutVersion === 5 ||
|
||||
layoutVersion === 6
|
||||
this.claimedApps = Array.isArray(data?.claimedApps)
|
||||
? data.claimedApps.filter(
|
||||
(id): id is LaunchablePhoneAppId =>
|
||||
@@ -291,7 +295,8 @@ export const useAppStoreStore = defineStore('app-store', {
|
||||
removedLegacyDefaults ||
|
||||
layoutVersion === 2 ||
|
||||
layoutVersion === 3 ||
|
||||
layoutVersion === 4
|
||||
layoutVersion === 4 ||
|
||||
layoutVersion === 5
|
||||
) {
|
||||
this.persist()
|
||||
}
|
||||
@@ -374,6 +379,22 @@ export const useAppStoreStore = defineStore('app-store', {
|
||||
this.persist()
|
||||
return true
|
||||
},
|
||||
applyWidgetGridCapacities(
|
||||
previousCapacities: readonly number[],
|
||||
nextCapacities: readonly number[],
|
||||
): boolean {
|
||||
const next = reflowHomeGridForWidgetChange(
|
||||
this.homeLayout,
|
||||
previousCapacities,
|
||||
nextCapacities,
|
||||
)
|
||||
if (!next) return false
|
||||
if (next !== this.homeLayout) {
|
||||
this.homeLayout = next
|
||||
this.persist()
|
||||
}
|
||||
return true
|
||||
},
|
||||
createHomeFolder(
|
||||
from: HomeArea,
|
||||
sourceIndex: number,
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
import { usePhoneStore } from '@/stores/phone'
|
||||
import type { WidgetKind, WidgetSettings, WidgetSize } from '@/types/widgets'
|
||||
import type {
|
||||
WidgetKind,
|
||||
WidgetLayout,
|
||||
WidgetSettings,
|
||||
WidgetSize,
|
||||
} from '@/types/widgets'
|
||||
import {
|
||||
addWidget,
|
||||
createDefaultWidgetLayout,
|
||||
@@ -18,6 +23,12 @@ export const useWidgetsStore = defineStore('widgets', {
|
||||
layout: createDefaultWidgetLayout(),
|
||||
}),
|
||||
actions: {
|
||||
applyLayout(layout: WidgetLayout): boolean {
|
||||
if (layout === this.layout) return false
|
||||
this.layout = layout
|
||||
this.persist()
|
||||
return true
|
||||
},
|
||||
add(kind: WidgetKind, size: WidgetSize, page: number): string | null {
|
||||
const previousIds = new Set(
|
||||
this.layout.instances.map((instance) => instance.id),
|
||||
|
||||
Reference in New Issue
Block a user