feat(settings/clock/alarm): implement (achievements)

This commit is contained in:
2026-01-24 22:48:04 +01:00
parent 537980dfc0
commit 944f84944c
10 changed files with 146 additions and 0 deletions

Binary file not shown.

View File

@@ -0,0 +1,133 @@
<script setup lang="ts">
import { SettingsBottomScreenNumberInput as NumberInput } from "#components";
const APP_COLOR_TO_FONT_COLOR: Record<string, string> = {
"#61829a": "#fbfbfb", // cyan
"#ba4900": "#fbe3d3", // maroon
"#fb0018": "#fbcbd3", // red
"#fb8afb": "#fbebfb", // pink
"#fb9200": "#fbf3e3", // orange
"#f3e300": "#fbfbdb", // yellow
"#aafb00": "#fbfbfb", // lime
"#00fb00": "#fbfbfb", // green
"#00a238": "#fbfbfb", // dark green
"#49db8a": "#ebfbf3", // duck
"#30baf3": "#fbfbfb", // light blue
"#0059f3": "#dbebfb", // blue
"#000092": "#ebebfb", // dark blue
"#8a00d3": "#f3dbfb", // purple
"#d300eb": "#fbfbfb", // magenta
"#fb0092": "#ebe3f3", // fuschia
};
const { assets } = useAssets();
const achievementAssets =
assets.images.settings.bottomScreen.clock.achievements;
const { onRender, onClick } = useScreen();
const app = useAppStore();
const store = useSettingsStore();
const achievements = useAchievementsStore();
const confirmationModal = useConfirmationModal();
const handleCancel = () => {
store.closeSubMenu();
};
const handleReset = () => {
confirmationModal.open({
text: $t("settings.clock.alarm.resetConfirmation"),
onConfirm: () => {
achievements.reset();
},
});
};
const handleVisitAll = () => {
throw new Error("Not implemented");
};
onClick((x, y) => {
const viewAllRect = achievementAssets.viewAllButton.rect;
if (rectContains([127, 2, viewAllRect.width, viewAllRect.height], [x, y])) {
handleVisitAll();
}
});
useKeyDown((key) => {
if (key === "NDS_X") {
handleVisitAll();
}
});
onRender((ctx) => {
assets.images.home.topScreen.background.draw(ctx, 0, 0);
// slash divider
ctx.textBaseline = "top";
ctx.fillStyle = "#515151";
ctx.fillRect(7 * 16 - 1, 4 * 16 - 1, 16 * 3 + 1, 16 * 3 + 1);
ctx.fillStyle = achievements.allObtained ? app.color.hex : "#797979";
ctx.fillRect(7 * 16, 4 * 16, 16 * 3 - 1, 16 * 3 - 1);
ctx.font = "39px NDS39";
ctx.letterSpacing = "2px";
ctx.fillStyle = achievements.allObtained
? APP_COLOR_TO_FONT_COLOR[app.color.hex]!
: "#fbfbfb";
ctx.fillText("/", 7 * 16 + 3, 4 * 16 + 4);
});
onRender((ctx) => {
achievementAssets.viewAllButton.draw(ctx, 127, 2);
achievementAssets.smallTrophy.draw(ctx, 131, 6);
const GAP = 4;
ctx.font = "10px NDS10";
ctx.textBaseline = "top";
ctx.fillStyle = "#010101";
const { actualBoundingBoxRight: textWidth } = ctx.measureText("View All");
const totalWidth = achievementAssets.X.rect.width + GAP + textWidth;
const left = Math.ceil(
145 +
(achievementAssets.viewAllButton.rect.width - 18) / 2 -
totalWidth / 2,
);
achievementAssets.X.draw(ctx, left, 7);
fillTextHCentered(
ctx,
"View All",
left + achievementAssets.X.rect.width + GAP,
7,
textWidth,
);
}, 1000);
</script>
<template>
<NumberInput
:model-value="achievements.achievements.length"
title="Obtained"
:x="4 * 16 - 1"
:selected="achievements.allObtained"
:disabled="true"
/>
<NumberInput
:model-value="ACHIEVEMENTS.length"
title="Total"
:x="9 * 16 - 1"
:selected="achievements.allObtained"
:disabled="true"
/>
<CommonButtons
:y-offset="confirmationModal.buttonsYOffset"
b-label="Cancel"
a-label="Reset"
@activate-b="handleCancel()"
@activate-a="handleReset()"
/>
</template>

View File

@@ -11,6 +11,7 @@ import UserUserName from "./User/UserName.vue";
import UserPersonalMessage from "./User/PersonalMessage.vue";
import ClockMenu from "./Clock/Menu.vue";
import ClockAlarm from "./Clock/Alarm.vue";
import ClockDate from "./Clock/Date.vue";
import ClockTime from "./Clock/Time.vue";
import TouchScreenMenu from "./TouchScreen/Menu.vue";
@@ -172,6 +173,7 @@ const viewComponents: Record<string, Component> = {
optionsLanguage: OptionsLanguage,
optionsGbaMode: OptionsGbaMode,
clockAlarm: ClockAlarm,
clockDate: ClockDate,
clockTime: ClockTime,

View File

@@ -72,8 +72,12 @@ export const useAchievementsStore = defineStore("achievements", () => {
};
return {
// TODO: rename to unlocked
achievements: computed(() => storage.value.unlocked),
advancement: computed(() => storage.value.advancement),
allObtained: computed(
() => storage.value.unlocked.length === ACHIEVEMENTS.length,
),
unlock,
reset,
isUnlocked: computed(