370 lines
10 KiB
Vue
370 lines
10 KiB
Vue
<script setup lang="ts">
|
|
import OptionsMenu from "./Options/Menu.vue";
|
|
import OptionsRenderingMode from "./Options/RenderingMode.vue";
|
|
import OptionsLanguage from "./Options/Language.vue";
|
|
import Options2048 from "./Options/2048.vue";
|
|
|
|
import UserMenu from "./User/Menu.vue";
|
|
import UserColor from "./User/Color.vue";
|
|
import UserBirthday from "./User/Birthday.vue";
|
|
import UserUserName from "./User/UserName.vue";
|
|
import UserSnake from "./User/Snake.vue";
|
|
|
|
import ClockMenu from "./Clock/Menu.vue";
|
|
import ClockAchievements from "./Clock/Achievements.vue";
|
|
import ClockDate from "./Clock/Date.vue";
|
|
import ClockTime from "./Clock/Time.vue";
|
|
import TouchScreenMenu from "./TouchScreen/Menu.vue";
|
|
import TouchScreenTapTap from "./TouchScreen/TapTap.vue";
|
|
import Selector from "~/components/Common/ButtonSelector.vue";
|
|
|
|
const app = useAppStore();
|
|
const store = useSettingsStore();
|
|
const { assets } = useAssets();
|
|
const { onRender } = useScreen();
|
|
|
|
onRender((ctx) => {
|
|
if (store.submenuBackground.opacity > 0) {
|
|
ctx.globalAlpha = store.submenuBackground.opacity;
|
|
ctx.translate(0, store.submenuBackground.offsetY);
|
|
assets.images.home.topScreen.background.draw(ctx, 0, 0);
|
|
}
|
|
});
|
|
|
|
if (app.previousScreen === "home") {
|
|
store.selectedButton = "options";
|
|
}
|
|
|
|
const isMainMenu = (button: string): button is SettingsMenu =>
|
|
SETTINGS_MENUS.includes(button as SettingsMenu);
|
|
|
|
const isSubMenu = (button: string): button is SettingsSubMenu =>
|
|
SETTINGS_SUB_MENUS.includes(button as SettingsSubMenu);
|
|
|
|
const getParentMenu = (submenu: string): SettingsMenu => {
|
|
const match = submenu.match(/^(options|clock|user|touchScreen)/);
|
|
if (!match?.[1]) throw new Error(`Invalid submenu: '${submenu}'`);
|
|
return match[1] as SettingsMenu;
|
|
};
|
|
|
|
const { select, selected, pressed, selectorPosition } = useButtonNavigation({
|
|
buttons: {
|
|
options: [31, 119, 49, 49],
|
|
optionsLanguage: [31, 71, 49, 49],
|
|
options2048: [79, 71, 49, 49],
|
|
optionsRenderingMode: [31, 23, 49, 49],
|
|
|
|
clock: [79, 119, 49, 49],
|
|
clockAchievements: [79, 71, 49, 49],
|
|
clockTime: [127, 71, 49, 49],
|
|
clockDate: [79, 23, 49, 49],
|
|
|
|
user: [127, 119, 49, 49],
|
|
userBirthday: [79, 71, 49, 49],
|
|
userUserName: [127, 71, 49, 49],
|
|
userSnake: [175, 71, 49, 49],
|
|
userColor: [127, 23, 49, 49],
|
|
|
|
touchScreen: [175, 119, 49, 49],
|
|
},
|
|
initialButton: store.selectedButton,
|
|
onActivate: (buttonName) => {
|
|
if (isSubMenu(buttonName)) {
|
|
store.openSubMenu(buttonName);
|
|
} else if (buttonName === "touchScreen") {
|
|
store.openSubMenu("touchScreenTapTap");
|
|
} else {
|
|
if (!store.menuExpanded) {
|
|
assets.audio.settingsMenuOpen.play();
|
|
} else {
|
|
assets.audio.tinyClick.play(0.8);
|
|
}
|
|
if (buttonName === "options") select("optionsLanguage");
|
|
if (buttonName === "clock") select("clockAchievements");
|
|
if (buttonName === "user") select("userUserName");
|
|
}
|
|
},
|
|
navigation: {
|
|
options: {
|
|
right: "clock",
|
|
up: "optionsLanguage",
|
|
},
|
|
optionsLanguage: {
|
|
down: "options",
|
|
up: "optionsRenderingMode",
|
|
right: "options2048",
|
|
},
|
|
options2048: {
|
|
down: ["options", false],
|
|
left: "optionsLanguage",
|
|
up: ["optionsRenderingMode", false],
|
|
},
|
|
optionsRenderingMode: {
|
|
right: ["options2048", false],
|
|
down: "optionsLanguage",
|
|
},
|
|
|
|
clock: {
|
|
left: "options",
|
|
right: "user",
|
|
up: "clockAchievements",
|
|
},
|
|
clockAchievements: {
|
|
down: "clock",
|
|
up: "clockDate",
|
|
right: "clockTime",
|
|
},
|
|
clockTime: {
|
|
down: ["clock", false],
|
|
left: "clockAchievements",
|
|
up: ["clockDate", false],
|
|
},
|
|
clockDate: {
|
|
right: ["clockTime", false],
|
|
down: "clockAchievements",
|
|
},
|
|
|
|
user: {
|
|
left: "clock",
|
|
right: "touchScreen",
|
|
up: "userUserName",
|
|
},
|
|
userBirthday: {
|
|
down: ["user", false],
|
|
up: ["userColor", false],
|
|
right: "userUserName",
|
|
},
|
|
userUserName: {
|
|
down: "user",
|
|
left: "userBirthday",
|
|
right: "userSnake",
|
|
up: "userColor",
|
|
},
|
|
userSnake: {
|
|
down: ["user", false],
|
|
left: "userUserName",
|
|
up: ["userColor", false],
|
|
},
|
|
userColor: {
|
|
left: ["userBirthday", false],
|
|
right: ["userSnake", false],
|
|
down: "userUserName",
|
|
},
|
|
|
|
touchScreen: {
|
|
left: "user",
|
|
},
|
|
},
|
|
canClickButton: (buttonName) => {
|
|
if (isSubMenu(buttonName)) {
|
|
const parent = getParentMenu(buttonName);
|
|
return store.currentMenu === parent && store.menuExpanded;
|
|
}
|
|
return true;
|
|
},
|
|
onNavigate: (buttonName) => {
|
|
if (isMainMenu(buttonName)) {
|
|
if (store.menuExpanded) {
|
|
assets.audio.settingsMenuClose.play();
|
|
} else {
|
|
assets.audio.tinyClick.play(0.8);
|
|
}
|
|
} else {
|
|
if (!store.menuExpanded) {
|
|
assets.audio.settingsMenuOpen.play();
|
|
} else {
|
|
assets.audio.tinyClick.play(0.8);
|
|
}
|
|
}
|
|
},
|
|
disabled: computed(
|
|
() =>
|
|
store.currentSubMenu !== null ||
|
|
store.submenuTransition.opacity < 1 ||
|
|
store.isIntro ||
|
|
store.isOutro ||
|
|
store.animatingNotification,
|
|
),
|
|
selectorAnimation: {
|
|
duration: 0.11,
|
|
ease: "none",
|
|
},
|
|
});
|
|
|
|
const isSubmenuSelected = computed(() => isSubMenu(selected.value));
|
|
|
|
const selectedSubmenuExtraOffsetY = computed(
|
|
() =>
|
|
store.submenuTransition.selectorOffsetY - store.submenuTransition.offsetY,
|
|
);
|
|
|
|
const isAnyOtherMenuOpen = (menu: SettingsMenu) => {
|
|
if (store.currentSubMenu) {
|
|
return !store.currentSubMenu.startsWith(menu);
|
|
}
|
|
if (isSubmenuSelected.value) {
|
|
return getParentMenu(selected.value) !== menu;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
watch(
|
|
selected,
|
|
(newSelected) => {
|
|
store.selectedButton = newSelected;
|
|
|
|
if (store.currentSubMenu === null) {
|
|
if (isMainMenu(newSelected)) {
|
|
store.openMenu(newSelected, false);
|
|
} else if (isSubMenu(newSelected)) {
|
|
const parentMenu = getParentMenu(newSelected);
|
|
if (parentMenu) {
|
|
store.openMenu(parentMenu, true);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{ immediate: true },
|
|
);
|
|
|
|
const viewComponents: Record<string, Component> = {
|
|
optionsRenderingMode: OptionsRenderingMode,
|
|
optionsLanguage: OptionsLanguage,
|
|
options2048: Options2048,
|
|
|
|
clockAchievements: ClockAchievements,
|
|
clockDate: ClockDate,
|
|
clockTime: ClockTime,
|
|
|
|
userColor: UserColor,
|
|
userBirthday: UserBirthday,
|
|
userUserName: UserUserName,
|
|
userSnake: UserSnake,
|
|
|
|
touchScreenTapTap: TouchScreenTapTap,
|
|
};
|
|
|
|
const selectorXOffset = computed(() => {
|
|
const menu = isMainMenu(selected.value)
|
|
? selected.value
|
|
: getParentMenu(selected.value);
|
|
|
|
switch (menu) {
|
|
case "clock":
|
|
return Math.min(0, store.menuOffsets[1]);
|
|
case "user":
|
|
return Math.min(0, store.menuOffsets[1] + store.menuOffsets[2]);
|
|
case "touchScreen":
|
|
return Math.min(
|
|
0,
|
|
store.menuOffsets[1] + store.menuOffsets[2] + store.menuOffsets[3],
|
|
);
|
|
default:
|
|
return 0;
|
|
}
|
|
});
|
|
|
|
const selectorTransitionOffsetY = computed(() => {
|
|
if (isSubmenuSelected.value || selected.value === "touchScreen") {
|
|
return store.submenuTransition.selectorOffsetY;
|
|
}
|
|
return store.submenuTransition.offsetY;
|
|
});
|
|
|
|
const handleActivateA = () => {
|
|
if (store.isIntro || store.isOutro || store.submenuTransition.opacity < 1)
|
|
return;
|
|
|
|
if (isSubMenu(selected.value)) {
|
|
store.openSubMenu(selected.value);
|
|
} else if (selected.value === "touchScreen") {
|
|
store.openSubMenu("touchScreenTapTap");
|
|
} else {
|
|
if (!store.menuExpanded) {
|
|
assets.audio.settingsMenuOpen.play();
|
|
} else {
|
|
assets.audio.tinyClick.play(0.8);
|
|
}
|
|
if (selected.value === "options") select("optionsLanguage");
|
|
if (selected.value === "clock") select("clockAchievements");
|
|
if (selected.value === "user") select("userUserName");
|
|
}
|
|
};
|
|
|
|
const handleActivateB = () => {
|
|
if (store.isIntro || store.isOutro || store.submenuTransition.opacity < 1)
|
|
return;
|
|
|
|
if (isSubmenuSelected.value) {
|
|
assets.audio.settingsMenuClose.play();
|
|
select(getParentMenu(selected.value));
|
|
} else {
|
|
store.animateOutro();
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<template v-if="!store.currentSubMenu">
|
|
<TouchScreenMenu
|
|
:x="
|
|
177 + store.menuOffsets[1] + store.menuOffsets[2] + store.menuOffsets[3]
|
|
"
|
|
:y="
|
|
121 +
|
|
store.menuYOffset +
|
|
(selected === 'touchScreen'
|
|
? store.submenuTransition.selectorOffsetY
|
|
: store.submenuTransition.offsetY)
|
|
"
|
|
:opacity="store.submenuTransition.opacity"
|
|
:pressed="pressed"
|
|
:is-any-other-menu-open="isAnyOtherMenuOpen('touchScreen')"
|
|
/>
|
|
<UserMenu
|
|
:x="129 + store.menuOffsets[1] + store.menuOffsets[2]"
|
|
:y="121 + store.menuYOffset + store.submenuTransition.offsetY"
|
|
:opacity="store.submenuTransition.opacity"
|
|
:pressed="pressed"
|
|
:is-any-other-menu-open="isAnyOtherMenuOpen('user')"
|
|
:submenu-extra-offset-y="selectedSubmenuExtraOffsetY"
|
|
/>
|
|
<ClockMenu
|
|
:x="81 + store.menuOffsets[1]"
|
|
:y="121 + store.menuYOffset + store.submenuTransition.offsetY"
|
|
:opacity="store.submenuTransition.opacity"
|
|
:pressed="pressed"
|
|
:is-any-other-menu-open="isAnyOtherMenuOpen('clock')"
|
|
:submenu-extra-offset-y="selectedSubmenuExtraOffsetY"
|
|
/>
|
|
<OptionsMenu
|
|
:x="33"
|
|
:y="121 + store.menuYOffset + store.submenuTransition.offsetY"
|
|
:opacity="store.submenuTransition.opacity"
|
|
:pressed="pressed"
|
|
:is-any-other-menu-open="isAnyOtherMenuOpen('options')"
|
|
:submenu-extra-offset-y="selectedSubmenuExtraOffsetY"
|
|
/>
|
|
|
|
<Selector
|
|
:rect="[
|
|
selectorPosition[0] + selectorXOffset,
|
|
selectorPosition[1] + store.menuYOffset + selectorTransitionOffsetY,
|
|
selectorPosition[2],
|
|
selectorPosition[3],
|
|
]"
|
|
:opacity="store.submenuTransition.opacity"
|
|
/>
|
|
|
|
<CommonButtons
|
|
:y-offset="store.barOffsetY + store.submenuButtonsOffsetY"
|
|
:b-label="isSubmenuSelected ? $t('common.goBack') : $t('common.quit')"
|
|
:a-label="$t('common.select')"
|
|
no-keyboard-a
|
|
@activate-a="handleActivateA()"
|
|
@activate-b="handleActivateB()"
|
|
/>
|
|
</template>
|
|
<component :is="viewComponents[store.currentSubMenu]" v-else />
|
|
</template>
|