diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4aad65d83..d27979d88 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -27,6 +27,7 @@
- Enhance: ノートについているリアクションの「もっと!」から、リアクションの一覧を表示できるように
- Enhance: リプライにて引用がある場合テキストが空でもノートできるように
- 引用したいノートのURLをコピーしリプライ投稿画面にペーストして添付することで達成できます
+- Enhance: フォローするかどうかの確認ダイアログを出せるように
- Fix: 一部のページ内リンクが正しく動作しない問題を修正
- Fix: 周年の実績が閏年を考慮しない問題を修正
- Fix: ローカルURLのプレビューポップアップが左上に表示される
diff --git a/locales/index.d.ts b/locales/index.d.ts
index cbea39f1c..8e31fc8d5 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -4948,6 +4948,10 @@ export interface Locale extends ILocale {
* 説明文はありません
*/
"noDescription": string;
+ /**
+ * フォローの際常に確認する
+ */
+ "alwaysConfirmFollow": string;
"_bubbleGame": {
/**
* 遊び方
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 4ab2f5adb..f59845979 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1233,6 +1233,7 @@ useNativeUIForVideoAudioPlayer: "動画・音声の再生にブラウザのUIを
keepOriginalFilename: "オリジナルのファイル名を保持"
keepOriginalFilenameDescription: "この設定をオフにすると、アップロード時にファイル名が自動でランダム文字列に置き換えられます。"
noDescription: "説明文はありません"
+alwaysConfirmFollow: "フォローの際常に確認する"
_bubbleGame:
howToPlay: "遊び方"
diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue
index 28450e11f..636e61db8 100644
--- a/packages/frontend/src/components/MkFollowButton.vue
+++ b/packages/frontend/src/components/MkFollowButton.vue
@@ -93,6 +93,18 @@ async function onClick() {
userId: props.user.id,
});
} else {
+ if (defaultStore.state.alwaysConfirmFollow) {
+ const { canceled } = await os.confirm({
+ type: 'question',
+ text: i18n.tsx.followConfirm({ name: props.user.name || props.user.username }),
+ });
+
+ if (canceled) {
+ wait.value = false;
+ return;
+ }
+ }
+
if (hasPendingFollowRequestFromYou.value) {
await misskeyApi('following/requests/cancel', {
userId: props.user.id,
diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue
index f2f82c480..55d514ddf 100644
--- a/packages/frontend/src/pages/settings/general.vue
+++ b/packages/frontend/src/pages/settings/general.vue
@@ -165,6 +165,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.keepScreenOn }}
{{ i18n.ts.disableStreamingTimeline }}
{{ i18n.ts.enableHorizontalSwipe }}
+ {{ i18n.ts.alwaysConfirmFollow }}
{{ i18n.ts.whenServerDisconnected }}
@@ -310,6 +311,7 @@ const useGroupedNotifications = computed(defaultStore.makeGetterSetter('useGroup
const enableSeasonalScreenEffect = computed(defaultStore.makeGetterSetter('enableSeasonalScreenEffect'));
const enableHorizontalSwipe = computed(defaultStore.makeGetterSetter('enableHorizontalSwipe'));
const useNativeUIForVideoAudioPlayer = computed(defaultStore.makeGetterSetter('useNativeUIForVideoAudioPlayer'));
+const alwaysConfirmFollow = computed(defaultStore.makeGetterSetter('alwaysConfirmFollow'));
watch(lang, () => {
miLocalStorage.setItem('lang', lang.value as string);
@@ -351,6 +353,7 @@ watch([
keepScreenOn,
disableStreamingTimeline,
enableSeasonalScreenEffect,
+ alwaysConfirmFollow,
], async () => {
await reloadAsk();
});
diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts
index 9b5011739..e6a348b79 100644
--- a/packages/frontend/src/store.ts
+++ b/packages/frontend/src/store.ts
@@ -450,6 +450,10 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'device',
default: true,
},
+ alwaysConfirmFollow: {
+ where: 'device',
+ default: true,
+ },
sound_masterVolume: {
where: 'device',