ENH - expand iOS settings controls

This commit is contained in:
Leon.Schmidt
2026-08-09 02:24:52 +02:00
parent 2ca96504d3
commit bb5e7fae2c
5 changed files with 286 additions and 14 deletions
@@ -0,0 +1,31 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" role="img" aria-label="Settings">
<defs>
<linearGradient id="settings-bg" x1="18" y1="8" x2="111" y2="121" gradientUnits="userSpaceOnUse">
<stop stop-color="#c8ccd3"/>
<stop offset="0.48" stop-color="#858b96"/>
<stop offset="1" stop-color="#505660"/>
</linearGradient>
<linearGradient id="settings-gear" x1="38" y1="31" x2="89" y2="98" gradientUnits="userSpaceOnUse">
<stop stop-color="#ffffff"/>
<stop offset="1" stop-color="#e7e9ee"/>
</linearGradient>
<filter id="settings-shadow" x="15" y="15" width="98" height="98" filterUnits="userSpaceOnUse">
<feDropShadow dx="0" dy="3" stdDeviation="3" flood-color="#20242b" flood-opacity=".32"/>
</filter>
</defs>
<rect width="128" height="128" rx="29" fill="url(#settings-bg)"/>
<path d="M12 34C30 17 52 10 80 13c18 2 30 9 38 18v-2C118 13 105 0 89 0H29C13 0 0 13 0 29v25c2-7 6-14 12-20Z" fill="#ffffff" fill-opacity=".18"/>
<g fill="url(#settings-gear)" filter="url(#settings-shadow)">
<rect x="57" y="20" width="14" height="27" rx="6"/>
<rect x="57" y="81" width="14" height="27" rx="6"/>
<rect x="81" y="57" width="27" height="14" rx="6"/>
<rect x="20" y="57" width="27" height="14" rx="6"/>
<rect x="76" y="25" width="14" height="29" rx="6" transform="rotate(45 83 39.5)"/>
<rect x="38" y="74" width="14" height="29" rx="6" transform="rotate(45 45 88.5)"/>
<rect x="74" y="76" width="29" height="14" rx="6" transform="rotate(45 88.5 83)"/>
<rect x="25" y="38" width="29" height="14" rx="6" transform="rotate(45 39.5 45)"/>
<circle cx="64" cy="64" r="34"/>
</g>
<circle cx="64" cy="64" r="15" fill="#626873"/>
<circle cx="64" cy="64" r="11" fill="#747a85" stroke="#ffffff" stroke-opacity=".35" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

+1 -1
View File
@@ -39,7 +39,7 @@ import darkChatIcon from '@/assets/img/app-icons/darkchat.svg'
import notesIcon from '@/assets/img/app-icons/notes.webp'
import photosIcon from '@/assets/img/app-icons/gallery.webp'
import phoneIcon from '@/assets/img/app-icons/phone.webp'
import settingsIcon from '@/assets/img/app-icons/settings.webp'
import settingsIcon from '@/assets/img/app-icons/settings.svg'
import snakeIcon from '@/assets/img/app-icons/snake.webp'
import memoryIcon from '@/assets/img/app-icons/memory.webp'
import numberMergeIcon from '@/assets/img/app-icons/number-merge.webp'
+21 -4
View File
@@ -1455,6 +1455,17 @@ const defaultLocales: LocaleTree = {
general: 'General Settings',
security: 'Passcode & Security',
appearance: 'Appearance',
connectivity: 'Connectivity',
connections: 'Connections',
wifi: 'Wi-Fi',
bluetooth: 'Bluetooth',
cellular: 'Cellular',
connectivityDescription:
'Airplane Mode temporarily disables wireless connections. Wi-Fi, Bluetooth, and cellular settings are saved on this phone.',
focus: 'Focus',
focusMode: 'Focus',
focusDescription:
'Focus silences non-critical notifications while keeping alarms and important alerts available.',
allowNotifications: 'Allow Notifications',
notificationSounds: 'Sounds',
notificationDuration: 'Notification Duration',
@@ -1469,6 +1480,8 @@ const defaultLocales: LocaleTree = {
dark: 'Dark',
phoneScale: 'Phone Scale',
phoneFrame: 'Phone Frame',
screenBrightness: 'Screen Brightness',
rotationLock: 'Rotation Lock',
about: 'About',
deviceName: 'Device Name',
deviceNameValue: 'Sky Phone',
@@ -1535,6 +1548,11 @@ const defaultLocales: LocaleTree = {
toggle: {
airplaneMode: 'Toggle Airplane Mode',
streamerMode: 'Toggle Streamer Mode',
focusMode: 'Toggle Focus',
wifiEnabled: 'Toggle Wi-Fi',
bluetoothEnabled: 'Toggle Bluetooth',
cellularEnabled: 'Toggle Cellular Data',
rotationLocked: 'Toggle Rotation Lock',
notifications: 'Toggle notifications for {app}',
notificationSounds: 'Toggle notification sounds for {app}',
},
@@ -1840,10 +1858,9 @@ export const usePhoneStore = defineStore('phone', {
async unlockWithPasscode(
passcode: string,
): Promise<NuiResponse<PasscodeResponseData>> {
const response = await nuiCall<PasscodeResponseData>(
'security:unlock',
{ passcode },
)
const response = await nuiCall<PasscodeResponseData>('security:unlock', {
passcode,
})
if (response.success && response.data?.security) {
this.security = response.data.security
}
+226 -8
View File
@@ -24,17 +24,22 @@ import {
} from 'konsta/vue'
import {
BellRing,
Bluetooth,
Check,
EyeOff,
KeyRound,
Monitor,
Moon,
Plane,
RotateCcw,
RotateCw,
Settings,
Signal,
Smartphone,
Sun,
UserRound,
Volume2,
Wifi,
} from 'lucide-vue-next'
import {
computed,
@@ -81,10 +86,18 @@ type SettingsView =
| 'notifications'
| 'notification-detail'
| 'sounds'
| 'connectivity'
| 'focus'
| 'general'
| 'appearance'
| 'wallpaper'
type RootToggleKey = 'airplaneMode' | 'streamerMode'
type RootToggleKey =
| 'airplaneMode'
| 'streamerMode'
| 'focusMode'
| 'wifiEnabled'
| 'bluetoothEnabled'
| 'cellularEnabled'
type SubmenuView = Exclude<SettingsView, 'root' | 'notification-detail'>
type PasscodeFlow =
| 'set-new'
@@ -171,6 +184,18 @@ const serviceRows = [
},
]
const preferenceRows = [
{
key: 'connectivity',
view: 'connectivity' as const,
icon: Wifi,
iconColor: '#007aff',
},
{
key: 'focus',
view: 'focus' as const,
icon: Moon,
iconColor: '#5856d6',
},
{
key: 'security',
view: 'security' as const,
@@ -197,6 +222,27 @@ const preferenceRows = [
},
]
const connectivityRows = [
{
key: 'wifi',
preferenceKey: 'wifiEnabled' as const,
icon: Wifi,
iconColor: '#007aff',
},
{
key: 'bluetooth',
preferenceKey: 'bluetoothEnabled' as const,
icon: Bluetooth,
iconColor: '#007aff',
},
{
key: 'cellular',
preferenceKey: 'cellularEnabled' as const,
icon: Signal,
iconColor: '#34c759',
},
]
const normalizedQuery = computed(() => query.value.trim().toLowerCase())
const visibleToggleRows = computed(() =>
toggleRows.filter((row) => matchesSearch(row.key)),
@@ -233,7 +279,10 @@ const passcodeTitle = computed(() => {
if (passcodeFlow.value === 'set-confirm') {
return phone.t('Apps.settings.passcode.confirmNew')
}
if (passcodeFlow.value === 'change-current' || passcodeFlow.value === 'disable') {
if (
passcodeFlow.value === 'change-current' ||
passcodeFlow.value === 'disable'
) {
return phone.t('Apps.settings.passcode.enterCurrent')
}
if (passcodeFlow.value === 'change-confirm') {
@@ -402,7 +451,8 @@ function updateNumberPreference(
| 'notificationDurationSeconds'
| 'notificationVolume'
| 'phoneScale'
| 'ringtoneVolume',
| 'ringtoneVolume'
| 'screenBrightness',
event: Event,
): void {
phone.setPreference(
@@ -700,10 +750,11 @@ onBeforeUnmount(() => {
<component :is="row.icon" :size="17" :stroke-width="2.25" />
</span>
</template>
<template v-if="row.key === 'security'" #after>
<template v-if="row.key === 'security' || row.key === 'focus'" #after>
{{
phone.t(
phone.security.enabled
(row.key === 'security' && phone.security.enabled) ||
(row.key === 'focus' && phone.preferences.settings.focusMode)
? 'Apps.settings.on'
: 'Apps.settings.off',
)
@@ -714,7 +765,13 @@ onBeforeUnmount(() => {
</template>
<template v-else>
<k-navbar :title="activeTitle" class="top-0 sticky z-20">
<k-navbar
:title="activeTitle"
:class="[
'settings-detail-navbar sticky z-20',
{ 'settings-detail-navbar--dark': phone.isDarkMode },
]"
>
<template #left>
<k-navbar-back-link
component="button"
@@ -879,7 +936,9 @@ onBeforeUnmount(() => {
</k-block>
<template v-if="!phone.security.enabled">
<k-block-title>{{ phone.t('Apps.settings.passcode.codeLength') }}</k-block-title>
<k-block-title>{{
phone.t('Apps.settings.passcode.codeLength')
}}</k-block-title>
<k-block>
<k-segmented strong rounded>
<k-segmented-button
@@ -920,7 +979,9 @@ onBeforeUnmount(() => {
"
/>
</k-list>
<k-block-title>{{ phone.t('Apps.settings.passcode.codeLength') }}</k-block-title>
<k-block-title>{{
phone.t('Apps.settings.passcode.codeLength')
}}</k-block-title>
<k-block>
<k-segmented strong rounded>
<k-segmented-button
@@ -1132,6 +1193,80 @@ onBeforeUnmount(() => {
</k-list>
</template>
<template v-else-if="activeView === 'connectivity'">
<k-list strong inset>
<k-list-item :title="phone.t('Apps.settings.airplaneMode')">
<template #media>
<span class="settings-row-icon bg-[#ff9500]">
<Plane :size="17" :stroke-width="2.25" />
</span>
</template>
<template #after>
<k-toggle
:checked="phone.preferences.settings.airplaneMode"
:aria-label="phone.t('Apps.settings.toggle.airplaneMode')"
@change="toggleRootSetting('airplaneMode')"
/>
</template>
</k-list-item>
</k-list>
<k-block-title>{{
phone.t('Apps.settings.connections')
}}</k-block-title>
<k-list strong inset>
<k-list-item
v-for="row in connectivityRows"
:key="row.key"
:title="phone.t(`Apps.settings.${row.key}`)"
>
<template #media>
<span
class="settings-row-icon"
:style="{ backgroundColor: row.iconColor }"
>
<component :is="row.icon" :size="17" :stroke-width="2.25" />
</span>
</template>
<template #after>
<k-toggle
:checked="phone.preferences.settings[row.preferenceKey]"
:disabled="phone.preferences.settings.airplaneMode"
:aria-label="
phone.t(`Apps.settings.toggle.${row.preferenceKey}`)
"
@change="toggleRootSetting(row.preferenceKey)"
/>
</template>
</k-list-item>
</k-list>
<k-block class="text-sm leading-5 opacity-60">
{{ phone.t('Apps.settings.connectivityDescription') }}
</k-block>
</template>
<template v-else-if="activeView === 'focus'">
<k-list strong inset>
<k-list-item :title="phone.t('Apps.settings.focusMode')">
<template #media>
<span class="settings-row-icon bg-[#5856d6]">
<Moon :size="17" :stroke-width="2.25" />
</span>
</template>
<template #after>
<k-toggle
:checked="phone.preferences.settings.focusMode"
:aria-label="phone.t('Apps.settings.toggle.focusMode')"
@change="toggleRootSetting('focusMode')"
/>
</template>
</k-list-item>
</k-list>
<k-block class="text-sm leading-5 opacity-60">
{{ phone.t('Apps.settings.focusDescription') }}
</k-block>
</template>
<template v-else-if="activeView === 'general'">
<k-block-title>
{{ phone.t('Apps.settings.notificationDuration') }} ·
@@ -1243,6 +1378,48 @@ onBeforeUnmount(() => {
</k-list-item>
</k-list>
<k-block-title>
{{ phone.t('Apps.settings.screenBrightness') }} ·
{{ phone.preferences.settings.screenBrightness }}%
</k-block-title>
<k-list strong inset>
<k-list-item>
<template #inner>
<div class="flex w-full items-center gap-3">
<Sun :size="16" class="shrink-0 opacity-55" />
<k-range
class="w-full"
:value="phone.preferences.settings.screenBrightness"
:min="10"
:max="100"
:aria-label="phone.t('Apps.settings.screenBrightness')"
@input="updateNumberPreference('screenBrightness', $event)"
/>
<Sun :size="23" class="shrink-0" />
</div>
</template>
</k-list-item>
<k-list-item :title="phone.t('Apps.settings.rotationLock')">
<template #media>
<span class="settings-row-icon bg-[#ff9500]">
<RotateCw :size="17" :stroke-width="2.25" />
</span>
</template>
<template #after>
<k-toggle
:checked="phone.preferences.settings.rotationLocked"
:aria-label="phone.t('Apps.settings.toggle.rotationLocked')"
@change="
phone.setPreference(
'rotationLocked',
!phone.preferences.settings.rotationLocked,
)
"
/>
</template>
</k-list-item>
</k-list>
<k-block-title>
{{ phone.t('Apps.settings.phoneScale') }} ·
{{ phone.preferences.settings.phoneScale }}%
@@ -1456,3 +1633,44 @@ onBeforeUnmount(() => {
{{ accountToast }}
</k-toast>
</template>
<style scoped>
.settings-row-icon {
display: flex;
width: 28px;
height: 28px;
flex-shrink: 0;
align-items: center;
justify-content: center;
border-radius: 7px;
color: #fff;
box-shadow:
inset 0 1px 0 rgb(255 255 255 / 35%),
0 1px 2px rgb(0 0 0 / 25%);
}
.settings-detail-navbar {
top: 0 !important;
background: rgb(248 248 248 / 94%);
backdrop-filter: blur(20px) saturate(180%);
-webkit-backdrop-filter: blur(20px) saturate(180%);
}
.settings-detail-navbar::before {
position: absolute;
right: 0;
bottom: 100%;
left: 0;
height: 44px;
background: rgb(248 248 248);
content: '';
}
.settings-detail-navbar--dark {
background: rgb(0 0 0 / 94%);
}
.settings-detail-navbar--dark::before {
background: #000;
}
</style>
+7 -1
View File
@@ -582,10 +582,14 @@ Locales["en"] = {
accountStorage = "Cloud Storage", accountStorageValue = "On Device", accountPurchases = "Media & Purchases",
accountPurchasesValue = "Available", notifications = "Notifications", sounds = "Sounds & Haptics",
general = "General Settings", security = "Passcode & Security", appearance = "Appearance", allowNotifications = "Allow Notifications",
connectivity = "Connectivity", connections = "Connections", wifi = "Wi-Fi", bluetooth = "Bluetooth", cellular = "Cellular",
connectivityDescription = "Airplane Mode temporarily disables wireless connections. Wi-Fi, Bluetooth, and cellular settings are saved on this phone.",
focus = "Focus", focusMode = "Focus", focusDescription = "Focus silences non-critical notifications while keeping alarms and important alerts available.",
notificationSounds = "Sounds", notificationDuration = "Notification Duration", seconds = "{seconds} seconds",
ringtoneVolume = "Ringtone Volume", notificationVolume = "Notification Volume",
ringtone = "Ringtone", notificationSound = "Notification Sound", appearanceMode = "Appearance Mode",
automatic = "Automatic", light = "Light", dark = "Dark", phoneScale = "Phone Scale", phoneFrame = "Phone Frame",
screenBrightness = "Screen Brightness", rotationLock = "Rotation Lock",
about = "About", deviceName = "Device Name", deviceNameValue = "Sky Phone", softwareVersion = "Software Version",
language = "Language", languageValue = "English", localStorage = "Local Storage", localStorageValue = "On Device",
back = "Settings", wallpaperPicker = "Built-in Wallpapers", deviceInformation = "Device Information",
@@ -611,7 +615,9 @@ Locales["en"] = {
device_not_found = "That device is no longer linked.", default = "The account request failed.",
},
toggle = {
airplaneMode = "Toggle Airplane Mode", streamerMode = "Toggle Streamer Mode",
airplaneMode = "Toggle Airplane Mode", streamerMode = "Toggle Streamer Mode", focusMode = "Toggle Focus",
wifiEnabled = "Toggle Wi-Fi", bluetoothEnabled = "Toggle Bluetooth", cellularEnabled = "Toggle Cellular Data",
rotationLocked = "Toggle Rotation Lock",
notifications = "Toggle notifications for {app}", notificationSounds = "Toggle notification sounds for {app}",
},
frames = { black = "Black", blue = "Blue", green = "Green", lavender = "Lavender", white = "White" },