refactor(frontend): アカウント情報はstore管理に

This commit is contained in:
syuilo 2025-04-16 09:25:13 +09:00
parent de19d9a4d4
commit 75267f87d5
5 changed files with 61 additions and 44 deletions

View File

@ -21,14 +21,19 @@ type AccountWithToken = Misskey.entities.MeDetailed & { token: string };
export async function getAccounts(): Promise<{ export async function getAccounts(): Promise<{
host: string; host: string;
user: Misskey.entities.User; id: Misskey.entities.User['id'];
username: Misskey.entities.User['username'];
user?: Misskey.entities.User | null;
token: string | null; token: string | null;
}[]> { }[]> {
const tokens = store.s.accountTokens; const tokens = store.s.accountTokens;
const accountInfos = store.s.accountInfos;
const accounts = prefer.s.accounts; const accounts = prefer.s.accounts;
return accounts.map(([host, user]) => ({ return accounts.map(([host, user]) => ({
host, host,
user, id: user.id,
username: user.username,
user: accountInfos[host + '/' + user.id],
token: tokens[host + '/' + user.id] ?? null, token: tokens[host + '/' + user.id] ?? null,
})); }));
} }
@ -36,7 +41,8 @@ export async function getAccounts(): Promise<{
async function addAccount(host: string, user: Misskey.entities.User, token: AccountWithToken['token']) { async function addAccount(host: string, user: Misskey.entities.User, token: AccountWithToken['token']) {
if (!prefer.s.accounts.some(x => x[0] === host && x[1].id === user.id)) { if (!prefer.s.accounts.some(x => x[0] === host && x[1].id === user.id)) {
store.set('accountTokens', { ...store.s.accountTokens, [host + '/' + user.id]: token }); store.set('accountTokens', { ...store.s.accountTokens, [host + '/' + user.id]: token });
prefer.commit('accounts', [...prefer.s.accounts, [host, user]]); store.set('accountInfos', { ...store.s.accountInfos, [host + '/' + user.id]: user });
prefer.commit('accounts', [...prefer.s.accounts, [host, { id: user.id, username: user.username }]]);
} }
} }
@ -44,6 +50,10 @@ export async function removeAccount(host: string, id: AccountWithToken['id']) {
const tokens = JSON.parse(JSON.stringify(store.s.accountTokens)); const tokens = JSON.parse(JSON.stringify(store.s.accountTokens));
delete tokens[host + '/' + id]; delete tokens[host + '/' + id];
store.set('accountTokens', tokens); store.set('accountTokens', tokens);
const accountInfos = JSON.parse(JSON.stringify(store.s.accountInfos));
delete accountInfos[host + '/' + id];
store.set('accountInfos', accountInfos);
prefer.commit('accounts', prefer.s.accounts.filter(x => x[0] !== host || x[1].id !== id)); prefer.commit('accounts', prefer.s.accounts.filter(x => x[0] !== host || x[1].id !== id));
} }
@ -121,14 +131,7 @@ export function updateCurrentAccount(accountData: Misskey.entities.MeDetailed) {
for (const [key, value] of Object.entries(accountData)) { for (const [key, value] of Object.entries(accountData)) {
$i[key] = value; $i[key] = value;
} }
prefer.commit('accounts', prefer.s.accounts.map(([host, user]) => { store.set('accountInfos', { ...store.s.accountInfos, [host + '/' + $i.id]: $i });
// TODO: $iのホストも比較したいけど通常null
if (user.id === $i.id) {
return [host, $i];
} else {
return [host, user];
}
}));
$i.token = token; $i.token = token;
miLocalStorage.setItem('account', JSON.stringify($i)); miLocalStorage.setItem('account', JSON.stringify($i));
} }
@ -138,17 +141,9 @@ export function updateCurrentAccountPartial(accountData: Partial<Misskey.entitie
for (const [key, value] of Object.entries(accountData)) { for (const [key, value] of Object.entries(accountData)) {
$i[key] = value; $i[key] = value;
} }
prefer.commit('accounts', prefer.s.accounts.map(([host, user]) => {
// TODO: $iのホストも比較したいけど通常null store.set('accountInfos', { ...store.s.accountInfos, [host + '/' + $i.id]: $i });
if (user.id === $i.id) {
const newUser = JSON.parse(JSON.stringify($i));
for (const [key, value] of Object.entries(accountData)) {
newUser[key] = value;
}
return [host, newUser];
}
return [host, user];
}));
miLocalStorage.setItem('account', JSON.stringify($i)); miLocalStorage.setItem('account', JSON.stringify($i));
} }
@ -223,25 +218,42 @@ export async function openAccountMenu(opts: {
}, ev: MouseEvent) { }, ev: MouseEvent) {
if (!$i) return; if (!$i) return;
function createItem(host: string, account: Misskey.entities.User): MenuItem { function createItem(host: string, id: Misskey.entities.User['id'], username: Misskey.entities.User['username'], account: Misskey.entities.User | null | undefined, token: string): MenuItem {
return { if (account) {
type: 'user' as const, return {
user: account, type: 'user' as const,
active: opts.active != null ? opts.active === account.id : false, user: account,
action: async () => { active: opts.active != null ? opts.active === id : false,
if (opts.onChoose) { action: async () => {
opts.onChoose(account); if (opts.onChoose) {
} else { opts.onChoose(account);
switchAccount(host, account.id); } else {
} switchAccount(host, id);
}, }
}; },
};
} else {
return {
type: 'button' as const,
text: username,
active: opts.active != null ? opts.active === id : false,
action: async () => {
if (opts.onChoose) {
fetchAccount(token, id).then(account => {
opts.onChoose(account);
});
} else {
switchAccount(host, id);
}
},
};
}
} }
const menuItems: MenuItem[] = []; const menuItems: MenuItem[] = [];
// TODO: $iのホストも比較したいけど通常null // TODO: $iのホストも比較したいけど通常null
const accountItems = (await getAccounts().then(accounts => accounts.filter(x => x.user.id !== $i.id))).map(a => createItem(a.host, a.user)); const accountItems = (await getAccounts().then(accounts => accounts.filter(x => x.id !== $i.id))).map(a => createItem(a.host, a.id, a.username, a.user, a.token));
if (opts.withExtraOperation) { if (opts.withExtraOperation) {
menuItems.push({ menuItems.push({
@ -254,7 +266,7 @@ export async function openAccountMenu(opts: {
}); });
if (opts.includeCurrentAccount) { if (opts.includeCurrentAccount) {
menuItems.push(createItem(host, $i)); menuItems.push(createItem(host, $i.id, $i.username, $i, $i.token));
} }
menuItems.push(...accountItems); menuItems.push(...accountItems);
@ -290,7 +302,7 @@ export async function openAccountMenu(opts: {
}); });
} else { } else {
if (opts.includeCurrentAccount) { if (opts.includeCurrentAccount) {
menuItems.push(createItem(host, $i)); menuItems.push(createItem(host, $i.id, $i.username, $i, $i.token));
} }
menuItems.push(...accountItems); menuItems.push(...accountItems);

View File

@ -157,7 +157,7 @@ async function init() {
const accounts = await getAccounts(); const accounts = await getAccounts();
const accountIdsToFetch = accounts.map(a => a.user.id).filter(id => !users.value.has(id)); const accountIdsToFetch = accounts.map(a => a.id).filter(id => !users.value.has(id));
if (accountIdsToFetch.length > 0) { if (accountIdsToFetch.length > 0) {
const usersRes = await misskeyApi('users/show', { const usersRes = await misskeyApi('users/show', {
@ -169,7 +169,7 @@ async function init() {
users.value.set(user.id, { users.value.set(user.id, {
...user, ...user,
token: accounts.find(a => a.user.id === user.id)!.token, token: accounts.find(a => a.id === user.id)!.token,
}); });
} }
} }

View File

@ -879,7 +879,7 @@ async function post(ev?: MouseEvent) {
if (postAccount.value) { if (postAccount.value) {
const storedAccounts = await getAccounts(); const storedAccounts = await getAccounts();
token = storedAccounts.find(x => x.user.id === postAccount.value?.id)?.token; token = storedAccounts.find(x => x.id === postAccount.value?.id)?.token;
} }
posting.value = true; posting.value = true;

View File

@ -32,10 +32,11 @@ export type SoundStore = {
// NOTE: デフォルト値は他の設定の状態に依存してはならない(依存していた場合、ユーザーがその設定項目単体で「初期値にリセット」した場合不具合の原因になる) // NOTE: デフォルト値は他の設定の状態に依存してはならない(依存していた場合、ユーザーがその設定項目単体で「初期値にリセット」した場合不具合の原因になる)
export const PREF_DEF = { export const PREF_DEF = {
// TODO: 持つのはホストやユーザーID、ユーザー名など最低限にしといて、その他のプロフィール情報はpreferences外で管理した方が綺麗そう
// 現状だと、updateCurrentAccount/updateCurrentAccountPartialが呼ばれるたびに「設定」へのcommitが行われて不自然(明らかに設定の更新とは捉えにくい)だし
accounts: { accounts: {
default: [] as [host: string, user: Misskey.entities.User][], default: [] as [host: string, user: {
id: string;
username: string;
}][],
}, },
pinnedUserLists: { pinnedUserLists: {

View File

@ -108,6 +108,10 @@ export const store = markRaw(new Pizzax('base', {
where: 'device', where: 'device',
default: {} as Record<string, string>, // host/userId, token default: {} as Record<string, string>, // host/userId, token
}, },
accountInfos: {
where: 'device',
default: {} as Record<string, Misskey.entities.User>, // host/userId, user
},
enablePreferencesAutoCloudBackup: { enablePreferencesAutoCloudBackup: {
where: 'device', where: 'device',