ADD - register CityWarn phone app

Register CityWarn as a built-in, non-removable phone app with notification defaults and catalog ordering. Add its runtime WebP icon and update app inventory contracts to cover installation and launch metadata.
This commit is contained in:
Leon.Schmidt
2026-08-18 15:36:26 +02:00
parent 742b2d2a0d
commit 165d26ec9b
6 changed files with 32 additions and 2 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

+9 -1
View File
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest'
import { Newspaper } from 'lucide-vue-next'
import { Newspaper, Siren } from 'lucide-vue-next'
import { isPhoneAppId, PHONE_APPS } from './apps'
describe('app registry', () => {
@@ -84,6 +84,14 @@ describe('app registry', () => {
expect(PHONE_APPS.find((app) => app.id === 'weazel-news')?.icon).toBe(
Newspaper,
)
expect(PHONE_APPS.find((app) => app.id === 'citywarn')).toMatchObject({
category: 'utilities',
gridOrder: 30,
labelKey: 'Apps.citywarn.name',
route: '/apps/citywarn',
})
expect(PHONE_APPS.find((app) => app.id === 'citywarn')?.icon).toBe(Siren)
expect(isPhoneAppId('citywarn')).toBe(true)
expect(PHONE_APPS.find((app) => app.id === 'music')).toMatchObject({
category: 'utilities',
gridOrder: 26,
+18
View File
@@ -35,6 +35,7 @@ import {
UsersRound,
Building2,
Newspaper,
Siren,
HeartPulse,
ChartCandlestick,
} from 'lucide-vue-next'
@@ -80,6 +81,7 @@ import featherIcon from '@/assets/img/app-icons/feather.svg'
import crewLinkIcon from '@/assets/img/app-icons/crewlink.svg'
import companiesIcon from '@/assets/img/app-icons/companies.svg'
import weazelNewsIcon from '@/assets/img/app-icons/weazel-news.svg'
import cityWarnIcon from '@/assets/img/app-icons/citywarn.webp'
import type {
BuiltinPhoneAppDefinition,
BuiltinPhoneAppId,
@@ -91,6 +93,20 @@ import type {
} from '@/types/apps'
export const PHONE_APPS = shallowReactive<PhoneAppDefinition[]>([
{
category: 'utilities',
component: markRaw(
defineAsyncComponent(() => import('@/views/apps/CityWarnApp.vue')),
),
dockOrder: null,
gridOrder: 30,
icon: markRaw(Siren),
iconClass: 'app-icon--citywarn',
iconImage: cityWarnIcon,
id: 'citywarn',
labelKey: 'Apps.citywarn.name',
route: '/apps/citywarn',
},
{
category: 'utilities',
component: markRaw(
@@ -676,6 +692,7 @@ export const DEFAULT_INSTALLED_PHONE_APP_IDS: ReadonlySet<BuiltinPhoneAppId> =
'map',
'calendar',
'health',
'citywarn',
])
export const NON_REMOVABLE_PHONE_APP_IDS: ReadonlySet<LaunchablePhoneAppId> =
@@ -688,6 +705,7 @@ export const NON_REMOVABLE_PHONE_APP_IDS: ReadonlySet<LaunchablePhoneAppId> =
'messages',
'mail',
'health',
'citywarn',
])
export const PHONE_APP_IDS = PHONE_APPS.map((app) => app.id)
+3 -1
View File
@@ -33,7 +33,7 @@ describe('app store', () => {
vi.useRealTimers()
})
it('installs the fifteen system apps by default', () => {
it('installs the sixteen system apps by default', () => {
const apps = useAppStoreStore()
apps.hydrate(null)
@@ -54,6 +54,7 @@ describe('app store', () => {
'map',
'calendar',
'health',
'citywarn',
])
for (const appId of DEFAULT_INSTALLED_PHONE_APP_IDS) {
expect(apps.isInstalled(appId)).toBe(true)
@@ -62,6 +63,7 @@ describe('app store', () => {
expect(apps.isInstalled('feather')).toBe(false)
expect(apps.isInstalled('snake')).toBe(false)
expect(apps.isInstalled('health')).toBe(true)
expect(apps.isInstalled('citywarn')).toBe(true)
})
it('removes old automatic apps unless the player installed them', () => {
+1
View File
@@ -41,6 +41,7 @@ export type BuiltinPhoneAppId =
| 'crewlink'
| 'companies'
| 'weazel-news'
| 'citywarn'
declare const externalPhoneAppId: unique symbol
+1
View File
@@ -113,6 +113,7 @@ const DEFAULT_APP_NOTIFICATIONS: Record<
'sky-flappy': { enabled: true, sounds: true },
'neon-drop': { enabled: true, sounds: true },
citymarkt: { enabled: true, sounds: true },
citywarn: { enabled: true, sounds: true },
companies: { enabled: true, sounds: true },
'weazel-news': { enabled: true, sounds: true },
'local-pages': { enabled: true, sounds: true },