feat(client): make possible to switch account instantly in post form
This commit is contained in:
		
							parent
							
								
									b388b78892
								
							
						
					
					
						commit
						331afcb96a
					
				
					 8 changed files with 119 additions and 40 deletions
				
			
		|  | @ -21,6 +21,7 @@ | ||||||
| ### Improvements | ### Improvements | ||||||
| - カスタム絵文字一括編集機能 | - カスタム絵文字一括編集機能 | ||||||
| - カスタム絵文字一括インポート | - カスタム絵文字一括インポート | ||||||
|  | - 投稿フォームで一時的に投稿するアカウントを切り替えられるように | ||||||
| 
 | 
 | ||||||
| ### Bugfixes | ### Bugfixes | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -129,7 +129,12 @@ export async function login(token: Account['token'], redirect?: string) { | ||||||
| 	unisonReload(); | 	unisonReload(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function openAccountMenu(ev: MouseEvent) { | export async function openAccountMenu(opts: { | ||||||
|  | 	includeCurrentAccount?: boolean; | ||||||
|  | 	withExtraOperation: boolean; | ||||||
|  | 	active?: misskey.entities.UserDetailed['id']; | ||||||
|  | 	onChoose?: (account: misskey.entities.UserDetailed) => void; | ||||||
|  | }, ev: MouseEvent) { | ||||||
| 	function showSigninDialog() { | 	function showSigninDialog() { | ||||||
| 		popup(import('@/components/signin-dialog.vue'), {}, { | 		popup(import('@/components/signin-dialog.vue'), {}, { | ||||||
| 			done: res => { | 			done: res => { | ||||||
|  | @ -148,7 +153,7 @@ export async function openAccountMenu(ev: MouseEvent) { | ||||||
| 		}, 'closed'); | 		}, 'closed'); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	async function switchAccount(account: any) { | 	async function switchAccount(account: misskey.entities.UserDetailed) { | ||||||
| 		const storedAccounts = await getAccounts(); | 		const storedAccounts = await getAccounts(); | ||||||
| 		const token = storedAccounts.find(x => x.id === account.id).token; | 		const token = storedAccounts.find(x => x.id === account.id).token; | ||||||
| 		switchAccountWithToken(token); | 		switchAccountWithToken(token); | ||||||
|  | @ -161,41 +166,58 @@ export async function openAccountMenu(ev: MouseEvent) { | ||||||
| 	const storedAccounts = await getAccounts().then(accounts => accounts.filter(x => x.id !== $i.id)); | 	const storedAccounts = await getAccounts().then(accounts => accounts.filter(x => x.id !== $i.id)); | ||||||
| 	const accountsPromise = api('users/show', { userIds: storedAccounts.map(x => x.id) }); | 	const accountsPromise = api('users/show', { userIds: storedAccounts.map(x => x.id) }); | ||||||
| 
 | 
 | ||||||
|  | 	function createItem(account: misskey.entities.UserDetailed) { | ||||||
|  | 		return { | ||||||
|  | 			type: 'user', | ||||||
|  | 			user: account, | ||||||
|  | 			active: opts.active != null ? opts.active === account.id : false, | ||||||
|  | 			action: () => { | ||||||
|  | 				if (opts.onChoose) { | ||||||
|  | 					opts.onChoose(account); | ||||||
|  | 				} else { | ||||||
|  | 					switchAccount(account); | ||||||
|  | 				} | ||||||
|  | 			}, | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	const accountItemPromises = storedAccounts.map(a => new Promise(res => { | 	const accountItemPromises = storedAccounts.map(a => new Promise(res => { | ||||||
| 		accountsPromise.then(accounts => { | 		accountsPromise.then(accounts => { | ||||||
| 			const account = accounts.find(x => x.id === a.id); | 			const account = accounts.find(x => x.id === a.id); | ||||||
| 			if (account == null) return res(null); | 			if (account == null) return res(null); | ||||||
| 			res({ | 			res(createItem(account)); | ||||||
| 				type: 'user', |  | ||||||
| 				user: account, |  | ||||||
| 				action: () => { switchAccount(account); } |  | ||||||
| 			}); |  | ||||||
| 		}); | 		}); | ||||||
| 	})); | 	})); | ||||||
| 
 | 
 | ||||||
| 	popupMenu([...[{ | 	if (opts.withExtraOperation) { | ||||||
| 		type: 'link', | 		popupMenu([...[{ | ||||||
| 		text: i18n.locale.profile, | 			type: 'link', | ||||||
| 		to: `/@${ $i.username }`, | 			text: i18n.locale.profile, | ||||||
| 		avatar: $i, | 			to: `/@${ $i.username }`, | ||||||
| 	}, null, ...accountItemPromises, { | 			avatar: $i, | ||||||
| 		icon: 'fas fa-plus', | 		}, null, ...(opts.includeCurrentAccount ? [createItem($i)] : []), ...accountItemPromises, { | ||||||
| 		text: i18n.locale.addAccount, | 			icon: 'fas fa-plus', | ||||||
| 		action: () => { | 			text: i18n.locale.addAccount, | ||||||
| 			popupMenu([{ | 			action: () => { | ||||||
| 				text: i18n.locale.existingAccount, | 				popupMenu([{ | ||||||
| 				action: () => { showSigninDialog(); }, | 					text: i18n.locale.existingAccount, | ||||||
| 			}, { | 					action: () => { showSigninDialog(); }, | ||||||
| 				text: i18n.locale.createAccount, | 				}, { | ||||||
| 				action: () => { createAccount(); }, | 					text: i18n.locale.createAccount, | ||||||
| 			}], ev.currentTarget || ev.target); | 					action: () => { createAccount(); }, | ||||||
| 		}, | 				}], ev.currentTarget || ev.target); | ||||||
| 	}, { | 			}, | ||||||
| 		type: 'link', | 		}, { | ||||||
| 		icon: 'fas fa-users', | 			type: 'link', | ||||||
| 		text: i18n.locale.manageAccounts, | 			icon: 'fas fa-users', | ||||||
| 		to: `/settings/accounts`, | 			text: i18n.locale.manageAccounts, | ||||||
| 	}]], ev.currentTarget || ev.target, { | 			to: `/settings/accounts`, | ||||||
| 		align: 'left' | 		}]], ev.currentTarget || ev.target, { | ||||||
| 	}); | 			align: 'left' | ||||||
|  | 		}); | ||||||
|  | 	} else { | ||||||
|  | 		popupMenu([...(opts.includeCurrentAccount ? [createItem($i)] : []), ...accountItemPromises], ev.currentTarget || ev.target, { | ||||||
|  | 			align: 'left' | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -8,6 +8,9 @@ | ||||||
| > | > | ||||||
| 	<header> | 	<header> | ||||||
| 		<button v-if="!fixed" class="cancel _button" @click="cancel"><i class="fas fa-times"></i></button> | 		<button v-if="!fixed" class="cancel _button" @click="cancel"><i class="fas fa-times"></i></button> | ||||||
|  | 		<button v-click-anime class="account _button" @click="openAccountMenu"> | ||||||
|  | 			<MkAvatar :user="postAccount ?? $i" class="avatar"/> | ||||||
|  | 		</button> | ||||||
| 		<div> | 		<div> | ||||||
| 			<span class="text-count" :class="{ over: textLength > maxTextLength }">{{ maxTextLength - textLength }}</span> | 			<span class="text-count" :class="{ over: textLength > maxTextLength }">{{ maxTextLength - textLength }}</span> | ||||||
| 			<span v-if="localOnly" class="local-only"><i class="fas fa-biohazard"></i></span> | 			<span v-if="localOnly" class="local-only"><i class="fas fa-biohazard"></i></span> | ||||||
|  | @ -83,7 +86,7 @@ import { throttle } from 'throttle-debounce'; | ||||||
| import MkInfo from '@/components/ui/info.vue'; | import MkInfo from '@/components/ui/info.vue'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
| import { instance } from '@/instance'; | import { instance } from '@/instance'; | ||||||
| import { $i } from '@/account'; | import { $i, getAccounts, openAccountMenu as openAccountMenu_ } from '@/account'; | ||||||
| 
 | 
 | ||||||
| const modal = inject('modal'); | const modal = inject('modal'); | ||||||
| 
 | 
 | ||||||
|  | @ -553,8 +556,15 @@ async function post() { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	let token = undefined; | ||||||
|  | 
 | ||||||
|  | 	if (postAccount) { | ||||||
|  | 		const storedAccounts = await getAccounts(); | ||||||
|  | 		token = storedAccounts.find(x => x.id === postAccount.id)?.token; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	posting = true; | 	posting = true; | ||||||
| 	os.api('notes/create', data).then(() => { | 	os.api('notes/create', data, token).then(() => { | ||||||
| 		clear(); | 		clear(); | ||||||
| 		nextTick(() => { | 		nextTick(() => { | ||||||
| 			deleteDraft(); | 			deleteDraft(); | ||||||
|  | @ -585,7 +595,7 @@ function insertMention() { | ||||||
| 	}); | 	}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function insertEmoji(ev) { | async function insertEmoji(ev: MouseEvent) { | ||||||
| 	os.openEmojiPicker(ev.currentTarget || ev.target, {}, textareaEl); | 	os.openEmojiPicker(ev.currentTarget || ev.target, {}, textareaEl); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -602,6 +612,23 @@ function showActions(ev) { | ||||||
| 	})), ev.currentTarget || ev.target); | 	})), ev.currentTarget || ev.target); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | let postAccount = $ref<misskey.entities.UserDetailed | null>(null); | ||||||
|  | 
 | ||||||
|  | function openAccountMenu(ev: MouseEvent) { | ||||||
|  | 	openAccountMenu_({ | ||||||
|  | 		withExtraOperation: false, | ||||||
|  | 		includeCurrentAccount: true, | ||||||
|  | 		active: postAccount != null ? postAccount.id : $i.id, | ||||||
|  | 		onChoose: (account) => { | ||||||
|  | 			if (account.id === $i.id) { | ||||||
|  | 				postAccount = null; | ||||||
|  | 			} else { | ||||||
|  | 				postAccount = account; | ||||||
|  | 			} | ||||||
|  | 		}, | ||||||
|  | 	}, ev); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| onMounted(() => { | onMounted(() => { | ||||||
| 	if (props.autofocus) { | 	if (props.autofocus) { | ||||||
| 		focus(); | 		focus(); | ||||||
|  | @ -678,6 +705,19 @@ onMounted(() => { | ||||||
| 			line-height: 66px; | 			line-height: 66px; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		> .account { | ||||||
|  | 			height: 100%; | ||||||
|  | 			aspect-ratio: 1/1; | ||||||
|  | 			display: inline-flex; | ||||||
|  | 			vertical-align: bottom; | ||||||
|  | 
 | ||||||
|  | 			> .avatar { | ||||||
|  | 				width: 28px; | ||||||
|  | 				height: 28px; | ||||||
|  | 				margin: auto; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		> div { | 		> div { | ||||||
| 			position: absolute; | 			position: absolute; | ||||||
| 			top: 0; | 			top: 0; | ||||||
|  |  | ||||||
|  | @ -24,7 +24,7 @@ | ||||||
| 			<span>{{ item.text }}</span> | 			<span>{{ item.text }}</span> | ||||||
| 			<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span> | 			<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span> | ||||||
| 		</a> | 		</a> | ||||||
| 		<button v-else-if="item.type === 'user'" :tabindex="i" class="_button item" @click="clicked(item.action, $event)"> | 		<button v-else-if="item.type === 'user'" :tabindex="i" class="_button item" :class="{ active: item.active }" :disabled="item.active" @click="clicked(item.action, $event)"> | ||||||
| 			<MkAvatar :user="item.user" class="avatar"/><MkUserName :user="item.user"/> | 			<MkAvatar :user="item.user" class="avatar"/><MkUserName :user="item.user"/> | ||||||
| 			<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span> | 			<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span> | ||||||
| 		</button> | 		</button> | ||||||
|  |  | ||||||
|  | @ -61,7 +61,11 @@ export default defineComponent({ | ||||||
| 			otherMenuItemIndicated, | 			otherMenuItemIndicated, | ||||||
| 			post: os.post, | 			post: os.post, | ||||||
| 			search, | 			search, | ||||||
| 			openAccountMenu, | 			openAccountMenu:(ev) => { | ||||||
|  | 				openAccountMenu({ | ||||||
|  | 					withExtraOperation: true, | ||||||
|  | 				}, ev); | ||||||
|  | 			}, | ||||||
| 			more: () => { | 			more: () => { | ||||||
| 				os.popup(import('@/components/launch-pad.vue'), {}, { | 				os.popup(import('@/components/launch-pad.vue'), {}, { | ||||||
| 				}, 'closed'); | 				}, 'closed'); | ||||||
|  |  | ||||||
|  | @ -76,7 +76,11 @@ export default defineComponent({ | ||||||
| 			iconOnly, | 			iconOnly, | ||||||
| 			post: os.post, | 			post: os.post, | ||||||
| 			search, | 			search, | ||||||
| 			openAccountMenu, | 			openAccountMenu:(ev) => { | ||||||
|  | 				openAccountMenu({ | ||||||
|  | 					withExtraOperation: true, | ||||||
|  | 				}, ev); | ||||||
|  | 			}, | ||||||
| 			more: () => { | 			more: () => { | ||||||
| 				os.popup(import('@/components/launch-pad.vue'), {}, { | 				os.popup(import('@/components/launch-pad.vue'), {}, { | ||||||
| 				}, 'closed'); | 				}, 'closed'); | ||||||
|  |  | ||||||
|  | @ -105,7 +105,11 @@ export default defineComponent({ | ||||||
| 			}, 'closed'); | 			}, 'closed'); | ||||||
| 		}, | 		}, | ||||||
| 
 | 
 | ||||||
| 		openAccountMenu, | 		openAccountMenu:(ev) => { | ||||||
|  | 			openAccountMenu({ | ||||||
|  | 				withExtraOperation: true, | ||||||
|  | 			}, ev); | ||||||
|  | 		}, | ||||||
| 	} | 	} | ||||||
| }); | }); | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
|  | @ -125,7 +125,11 @@ export default defineComponent({ | ||||||
| 			}, 'closed'); | 			}, 'closed'); | ||||||
| 		}, | 		}, | ||||||
| 
 | 
 | ||||||
| 		openAccountMenu, | 		openAccountMenu:(ev) => { | ||||||
|  | 			openAccountMenu({ | ||||||
|  | 				withExtraOperation: true, | ||||||
|  | 			}, ev); | ||||||
|  | 		}, | ||||||
| 	} | 	} | ||||||
| }); | }); | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue