公開日

本家の制約を UI で再現する:公開範囲と引用範囲の組み合わせ

Mastodon の投稿欄では、公開範囲と引用範囲の組み合わせに制約がある。ワンクリックで切り替えるボタン列を作るにあたり、本家が何を禁じているかをソースから読み解き、再現できないものは「選ばせない」で安全側に倒した。

はじめに

前回は、Mastodon の Web UI から Redux ストアを拾い、本家と同じアクションを dispatch する話を書いた。今回はその上に載る制約の話。

公開範囲と引用範囲は独立に選べるわけではない。本家のダイアログは組み合わせによって選択肢を出さなかったり固定したりする。こちらのボタン列はダイアログの置き換えなので、同じ制約を再現しないと本家では作れない状態をストアに書き込んでしまう。

本家が持つ制約

Mastodon v4.5.0 のソースとダイアログの挙動を見て、再現すべき制約を 3 つに整理した。

  • フォロワーのみ、または指定された相手のみの投稿では、引用範囲は「自分のみ」に固定される
  • 投稿を編集している間は、公開範囲を変更できない
  • 非公開(フォロワーのみ)の投稿を自分で引用するときは、公開・ひかえめな公開を選べない

スクリプトでは、ストアから読んだ状態をもとにボタンごとに disabled を立てる形にした。

quoteLocked: privacy === 'private' || privacy === 'direct',
isEditing: compose.get('id') != null,
quotedVis: quotedId ? state.statuses.getIn([quotedId, 'visibility']) : null,

引用範囲の固定は、グループ全体を無効にしたうえで「自分のみ」を選択中として表示する。ストアの quote_policy は書き換えず、表示だけ固定。編集中は公開範囲のグループ全体を無効にし、ツールチップに「投稿後は公開範囲を変更できません」と出す。自己引用の制約は、引用先の visibility を statuses から引いて判定している。

再現しないものは選ばせない

もう 1 つ、本家にはあるのにあえて再現しなかった挙動がある。引用中に公開範囲を「指定された相手のみ」に変えると、本家は引用をリンクに変換する処理を走らせる。この変換を自前で再現するのは流石に手間に見合わない。中途半端に真似ると、本家と違う状態を作りかねないし。

そこで、引用中は「指定された相手のみ」のボタンを無効にした。

(!!s.quotedId && v === 'direct'), // 引用中のDM化は Mastodon 本体の変換処理を再現しないので不可

できないことを「できない」と見せるだけなら、ストアに変な状態を書く心配はない。どうしてもその操作をしたいなら、本家のダイアログを使えばいい。README にも「本家の引用→リンク変換処理を再現しないため」と理由を書いた。

AI と壁打ちして決めたこと

制約の洗い出しは AI(Claude Code)に手伝ってもらった。ソースのどこを読めば判定条件が分かるかを聞き、挙げてもらった候補を自分でソースと照らして確かめた。AI が「こう動くはず」と言った説明のうち、ソースで裏が取れなかったものは採っていない。

決めたのは次の 2 点。

  • 本家の制約は、ストアの状態から同じ条件で判定して再現する
  • 再現すると本家と食い違うおそれのある挙動は、再現せず「選ばせない」

後者は機能を削る判断なので、やっぱ AI に任せず自分で決めた。本家のダイアログが残っている以上、こちらで全部できなくていいんだよな。安全側に倒しておけば、本家が更新されたときの壊れ方も「選べないだけ」で済む。

次回は、小さな OSS のライセンス表記について書く。