feat: [ongeki] username setting from webui

This commit is contained in:
Raymond
2026-06-06 22:43:41 -04:00
parent b2feb9a130
commit 819c058517
4 changed files with 80 additions and 80 deletions
@@ -9,23 +9,21 @@
import { download } from "../../libs/ui";
import UserOptionSlider from "./UserOptionSlider.svelte";
import type { GameUserOption } from "../../libs/generalTypes";
import InputField from "../ui/InputField.svelte";
const profileFields = [
['name', t('settings.mai2.name')],
]
let userNameField: any
let error: string
let submitting = ""
let loading = true
let values = Array(profileFields.length).fill('')
let changed: string[] = []
let userOptions: GameUserOption = {}
let userIsUsingPreset = false
USER.me().then(me =>
USER.me().then(me =>
GAME.userSummary(me.username, 'mai2').then(async ({name}) => {
values = [name]
userNameField = {key: "gameUsername", value: name, type: "String"}
userOptions = await SETTING.optionGet('mai2').catch(_ => {
error = t("userbox.error.nodata")
@@ -36,19 +34,6 @@
loading = false
}).catch(e => error = e.message));
function submit(field: string, value: string) {
if (submitting) return
submitting = field
switch (field) {
case 'name':
GAME.changeName('mai2', value).then(({newName}) => {
changed = changed.filter(c => c !== field)
values = [newName]
}).catch(e => error = e.message).finally(() => submitting = "")
break
}
}
async function exportBatchManual() {
submitting = "batchExport"
const DIFFICULTY_MAP: Record<number, string> = {
@@ -209,14 +194,14 @@
if(data.userData.classRank in CLASS_MAP){
output.classes["matchingClass"] = CLASS_MAP[data.userData.classRank]
}
download(JSON.stringify(output), `AquaDX_maimai2_BatchManualExport_${values[0]}.json`)
download(JSON.stringify(output), `AquaDX_maimai2_BatchManualExport_${userNameField.value}.json`)
submitting = ""
}
function exportData() {
submitting = "export"
GAME.export('mai2')
.then(data => download(JSON.stringify(data), `AquaDX_maimai2_export_${values[0]}.json`))
.then(data => download(JSON.stringify(data), `AquaDX_maimai2_export_${userNameField.value}.json`))
.catch(e => error = e.message)
.finally(() => submitting = "")
}
@@ -224,25 +209,8 @@
{#if !loading}
<div class="fields">
{#each profileFields as [field, name], i (field)}
<div class="field">
<label for={field}>{name}</label>
<div>
<input id={field} type="text"
bind:value={values[i]} on:input={() => changed = [...changed, field]}
placeholder={field === 'password' ? t('settings.profile.unchanged') : t('settings.profile.unset')}/>
{#if changed.includes(field) && values[i]}
<button transition:slide={{axis: 'x'}} on:click={() => submit(field, values[i])}>
{#if submitting === field}
<Icon icon="line-md:loading-twotone-loop"/>
{:else}
{t('settings.profile.save')}
{/if}
</button>
{/if}
</div>
</div>
{/each}
<InputField bind:field={userNameField}
callback={() => GAME.changeName('mai2', userNameField.value)}/>
{#if userIsUsingPreset}
<blockquote class="info">
{t('settings.options.all.preset-warning')}
@@ -250,46 +218,46 @@
{/if}
<div class="fields-ranges">
<!-- TODO: determine min & max -->
<UserOptionSlider
<UserOptionSlider
game="mai2" type="noteSpeed"
minValue={0} maxValue={37}
defaultValue={userOptions["noteSpeed"]}
getTextFunction={(value: number) => value >= 37 ? "SONIC" : `${(value / 4) + 1}`}
minValue={0} maxValue={37}
defaultValue={userOptions["noteSpeed"]}
getTextFunction={(value: number) => value >= 37 ? "SONIC" : `${(value / 4) + 1}`}
/>
<UserOptionSlider
<UserOptionSlider
game="mai2" type="touchSpeed"
minValue={0} maxValue={37}
defaultValue={userOptions["touchSpeed"]}
getTextFunction={(value: number) => value >= 37 ? "SONIC" : `${(value / 4) + 1}`}
minValue={0} maxValue={37}
defaultValue={userOptions["touchSpeed"]}
getTextFunction={(value: number) => value >= 37 ? "SONIC" : `${(value / 4) + 1}`}
/>
<UserOptionSlider
<UserOptionSlider
game="mai2" type="slideSpeed"
minValue={0} maxValue={20}
defaultValue={userOptions["slideSpeed"]}
getTextFunction={(value: number) => value == 10 ? "Normal" : `${value > 10 ? "Late" : "Fast"} ${(Math.abs(value - 10) / 10).toFixed(1)}`}
minValue={0} maxValue={20}
defaultValue={userOptions["slideSpeed"]}
getTextFunction={(value: number) => value == 10 ? "Normal" : `${value > 10 ? "Late" : "Fast"} ${(Math.abs(value - 10) / 10).toFixed(1)}`}
/>
<UserOptionSlider
game="mai2" type="headPhoneVolume"
minValue={0} maxValue={19}
defaultValue={userOptions["headPhoneVolume"]}
getTextFunction={(value: number) => `${((value / 19) * 100).toFixed(0)}%`}
<UserOptionSlider
game="mai2" type="headPhoneVolume"
minValue={0} maxValue={19}
defaultValue={userOptions["headPhoneVolume"]}
getTextFunction={(value: number) => `${((value / 19) * 100).toFixed(0)}%`}
/>
<UserOptionSlider
game="mai2" type="trackSkip"
minValue={0} maxValue={11}
defaultValue={userOptions["trackSkip"]}
<UserOptionSlider
game="mai2" type="trackSkip"
minValue={0} maxValue={11}
defaultValue={userOptions["trackSkip"]}
getTextFunction={(value: number) => [
t('settings.options.all.none'),
t('settings.options.all.push'),
`S`, `SS`, `SSS`,
t('settings.options.all.personal-best'),
t('settings.options.all.rival-score'),
t('settings.options.all.none'),
t('settings.options.all.push'),
`S`, `SS`, `SSS`,
t('settings.options.all.personal-best'),
t('settings.options.all.rival-score'),
`${t('settings.options.all.life')} 300`,
`${t('settings.options.all.life')} 100`,
`${t('settings.options.all.life')} 50`,
`${t('settings.options.all.life')} 10`,
`${t('settings.options.all.life')} 1`
][value]}
][value]}
/>
</div>
<GameSettingFields game="mai2"/>
@@ -304,7 +272,7 @@
</div>
{/if}
<StatusOverlays {error} loading={!values[0] || !!submitting || loading}/>
<StatusOverlays {error} loading={!userNameField || !!submitting || loading}/>
<style lang="sass">
.fields
@@ -1,21 +1,55 @@
<script>
<script lang="ts">
import { fade } from "svelte/transition";
import { FADE_IN, FADE_OUT } from "../../libs/config";
import GameSettingFields from "./GameSettingFields.svelte";
import { GAME, SETTING, USER } from "../../libs/sdk";
import { download } from "../../libs/ui";
import InputField from "../ui/InputField.svelte";
import Icon from "@iconify/svelte";
import { t } from "../../libs/i18n";
import StatusOverlays from "../StatusOverlays.svelte";
let userNameField: any
let submitting = "";
let error: string
let loading = true;
USER.me().then(me =>
GAME.userSummary(me.username, 'ongeki').then(async ({name}) => {
userNameField = {key: "gameUsername", value: name, type: "String"}
loading = false;
}))
function exportData() {
submitting = "export"
GAME.export('ongeki')
.then(data => download(JSON.stringify(data), `AquaDX_ongeki_export_${values[0]}.json`))
.then(data => download(JSON.stringify(data), `AquaDX_ongeki_export_${userNameField.value}.json`))
.catch(e => error = e.message)
.finally(() => submitting = "")
}
</script>
<div>
<GameSettingFields game="ongeki"/>
<button class="exportButton" on:click={exportData}>
<Icon icon="bxs:file-export"/>
{t('settings.export')}
</button>
</div>
{#if !loading}
<div>
<div class="fields">
<InputField bind:field={userNameField}
callback={() => SETTING.detailSet('ongeki', 'userName', userNameField.value)}/>
<GameSettingFields game="ongeki"/>
<button class="exportButton" on:click={exportData}>
<Icon icon="bxs:file-export"/>
{t('settings.export')}
</button>
</div>
</div>
{/if}
<StatusOverlays {error} loading={!userNameField || !!submitting || loading}/>
<style lang="sass">
.fields
display: flex
flex-direction: column
gap: 12px
</style>
+1 -2
View File
@@ -240,13 +240,12 @@ export const EN_REF_SETTINGS = {
'settings.fields.ongekiInfiniteKaika.desc': 'Set Kaika to 999',
'settings.fields.rounding.name': 'Score Rounding',
'settings.fields.rounding.desc': 'Round the score to one decimal place',
'settings.fields.gameUsername.name': 'In-Game Username',
'settings.fields.gameUsername.name': 'Player Name',
'settings.fields.gameUsername.desc': 'Your name shown in game',
'settings.fields.optOutOfLeaderboard.name': 'Opt Out of Leaderboard',
'settings.fields.optOutOfLeaderboard.desc': 'You will still be able to see yourself on the leaderboard after logging in',
'settings.fields.enableMusicRank.name': 'Enable Recommended Music Rank on Your Machine',
'settings.fields.enableMusicRank.desc': 'If you have your own ranking, you can turn this off. It only affects your own machine',
'settings.mai2.name': 'Player Name',
'settings.profile.picture': 'Profile Picture',
'settings.profile.upload-new': 'Upload New',
'settings.profile.bad-format': 'Invalid image format. Supported types are PNG, JPG, JPEG, WEBP & GIF.',
-1
View File
@@ -258,7 +258,6 @@ const zhSettings: typeof EN_REF_SETTINGS = {
'settings.fields.optOutOfLeaderboard.desc': '登录之后还是可以在排行榜上看到自己',
'settings.fields.enableMusicRank.name': '在你的机台上启用「推荐乐曲排行榜」',
'settings.fields.enableMusicRank.desc': '如果你自己设计了排行榜的话,可以关闭这个(会影响你自己的机器)。',
'settings.mai2.name': '玩家名字',
'settings.profile.picture': '头像',
'settings.profile.upload-new': '上传',
'settings.profile.bad-format': '无效的图片格式,支持的格式有 PNG、JPG、JPEG、WEBP 和 GIF。',