Skip to content

iPhone LED Dock Layout

log5r edited this page Oct 3, 2026 · 8 revisions

iPhone の再生ドックと LED デッキ

設計の参照元は、PR #16 の docs/iphone-layout.md。実装・検証日は 2026 年 10 月 3 日、使用環境は Xcode 27・Swift 6。初回検証後に、仕様書と実装をコミット 9071417 に保存した。

画面の切り替えと既存機能の再利用

MainView は、iOS のデバイス種別が iPhone の場合に専用画面を表示する。iPad と macOS では、既存の分割ナビゲーションと下部パネルを使用する。iPhone の「ライブラリ」「プレイリスト」「ビデオ」「検索」は、それぞれにナビゲーションスタックを持つ。アルバム・アーティスト・ジャンルを選ぶと、その曲一覧へ移動する。

iOS アプリのビルド設定で UILaunchScreen を生成する。生成された Info.plist とシミュレーターのスクリーンショットで、互換モードの上下の黒帯がなく、画面全体を使用することを確認した。

player.currentItem が存在する間は、tabViewBottomAccessory に再生中の Dock を表示する。背景と形は標準アクセサリーに任せ、曲名・経過時間と再生/一時停止・次曲のボタンを配置する。曲名と時刻のボタンをタップすると、全画面の再生デッキを開く。操作領域は 44×44 pt 以上、操作部の間隔は 12 pt。2 行が収まらない文字サイズでは時刻を画面から省略するが、読み上げ値には省略前の曲名と時刻を残す。

デッキのページは「表示」「歌詞」「情報」「次に再生」の 4 つ。「次に再生」では、既存の再生キューを表示し、再生する曲を選べる。別のキューは作成せず、キューの並べ替えには対応しない。横向きでも、このスクロール可能な iPhone 用レイアウトを使用する。横向き専用のデザインは未決定。

再生、ライブラリの変更、プレイリストの保存、メタデータ・歌詞の編集、調整後の書き出し、AAC 版の作成、検索フィルターには、既存のモデルとサービスを使用する。ライブラリの画面を移動しても、再生キューは置き換えない。ライブラリから曲を削除すると、その曲を再生キューから除き、再生対象の曲だった場合は現在の項目もクリアする。

デッキ内の LED の色とガラス表示の設定は、システムの外観設定から独立している。デッキのパネルと操作ボタンの配色には BottomPanelPalette を使用し、Dock には標準アクセサリーの背景と標準の文字・アイコン色を使用する。VolumeSlotView は縦横の両方向に対応し、デスクトップ側では従来どおり縦方向を既定とする。iPhone ではインジケーターランプから調整フォームを開き、キー、速度、EQ、プリアンプ、リバーブ、プリセットを操作する。動画には既存のプレイヤーレイヤーと全画面表示を使用し、キーと速度の変更を無効にする。出力先の選択には AVRoutePickerView を使用する。

画面表示と非同期処理で得た知見

usesPhoneLayout の環境値は、ルートビューのすべてのシート修飾子の外側で設定する。下層の iPhone 用コンテンツだけに設定しても、親の修飾子から表示するシートには反映されない。回帰テストでは、書き出し名の入力画面の「書き出し」ボタンが画面外になる問題を再現した。環境値の設定をすべてのシート修飾子の後に移すことで修正した。

スペーサーを含む行を .plain スタイルのボタンにする場合は、ラベル内に contentShape(Rectangle()) を設定する。Pro Max では、行の中央が余白になり、そこをタップしても再生が始まらなかった。幅の狭い 17e では中央に文字があったため、同じテストが通過していた。ライブラリと「次に再生」は、行全体をタップ対象に変更した。

アクセシビリティ識別子は、ページ切り替えボタンごとに設定する。外側のスタックに設定すると、配下の各ボタンで公開される識別子が置き換わる場合がある。セグメント型のピッカーを 44 pt のページボタンに変更した際、UI テストでこの現象を再現した。

書き出しの準備では、要求された項目のスナップショットを取得し、準備処理の重複実行を防ぐ。iOS では、列挙型の状態に基づく単一のシートで、タイトルがないファイルの名前入力画面か、標準の共有シートを表示する。取得済みの書き出し計画と編集後の名前を保持し、名前入力のシートを閉じてからファイルのコピーを開始する。独立したシート修飾子を使っていたときは、共有シートが安定して表示されなかった。

書き出しごとに固有の一時ディレクトリを使用する。ファイルの列挙と一時ディレクトリの削除は MainActor の外で実行する。共有コントローラーの完了時と破棄時のどちらでも、その書き出しに属するディレクトリを削除する。一部のファイルで書き出しに失敗した場合は、共有シートを閉じてからエラーを表示し、アラートとシートの同時表示を避ける。

複数編集の操作ボタンは、下部のセーフエリアへの追加表示で配置する。ナビゲーションツールバーの .bottomBar に置くと、外側のタブバーに隠れていた。セーフエリアへの追加表示なら、Dock とタブバーの上にボタンを配置できる。標準共有シートの「コピー」などは、アクセシビリティ上ではボタンではなくセルとして公開され、使用できる操作も端末によって異なる。テストでは特定の共有操作の存在ではなく、標準シートの表示、終了、その後に再度書き出せることを確認する。

調整シートでの保存要求は、シートを閉じてからデッキへ渡す。AAC 版の作成結果は MainView に保持し、デッキが開いている間はデッキ内、閉じた後はライブラリ画面で表示する。情報の読み込みでは、既存の項目と要求の有効性判定を維持する。時刻付き歌詞は元の歌詞が変わったときに解析し、行のインデックスを安定した識別子として強調表示とスクロールに使用する。再生時刻の更新ごとに歌詞全体を再解析することはない。

検証方法と結果

UI テスト用データは、DEBUG && os(iOS) と明示的な起動引数 --ui-testing-phone-layout の両方で有効にする。ローカルの WAV ファイルとプレイリストを、メモリ内のモデルコンテナーに追加する。通常の利用データには影響しない。

  • iPhone の表示テスト:ライブラリ、Dock、デッキ、調整シート、歌詞、情報、「次に再生」を操作し、再生操作ボタンとランプの操作領域が 44 pt 以上で、画面内に収まることを確認する。
  • 操作のテスト:設定項目の表示、複数選択とメタデータ編集画面、プレイリストの作成・曲の追加・名前変更・曲の除去、書き出し名の入力から標準共有シートの表示までを確認する。
  • iPad の基本操作テスト:分割レイアウト、デスクトップ側と共通の操作ボタン、設定画面を確認する。
  • macOS の検証:ローカライズされた主画面・設定画面の操作、サイドバーのフォーカス、ローカライズの単体テスト、スクロール文字のクリック判定を確認する。
  • lint:変更したすべての Swift ファイルを厳格モードで検査する。ベースラインは追加しない。リポジトリ全体の通常モードの lint も実行する。変更と無関係な既存の警告は残っている。

2026 年 10 月 3 日の検証結果は次のとおり。

  • iPhone 17e(iOS 27):外観と LED スタイルの組み合わせ 4 通りのデッキテストが通過した。行全体をタップ対象にする修正と「次に再生」の選曲確認を含む最終版でも、英語・ダークの回帰テストが通過した。対象を絞ったテストで、プレイリストの作成・曲の追加・名前変更・曲の除去、設定・複数編集も通過した。
  • iPhone 17 Pro Max(iOS 27):英語・ダークと日本語・ライト・バックライトのデッキテストが通過した。行の中央のタップと「次に再生」での曲の切り替えを含む。書き出し名の入力、標準共有シートの表示と終了、その後の再書き出しも通過した。
  • iPad Pro 11 インチ M5(iOS 27):主画面と設定画面の基本操作テストが通過した。
  • macOS 27:アプリのビルド、ローカライズの単体テスト、スクロール文字のクリック判定の回帰テスト、主画面・設定・サイドバーに関する 2 件の UI テストが通過した。
  • リポジトリ全体の通常モードの lint は、変更と無関係な既存の警告を残して通過した。変更した Swift ファイル 31 件の厳格モードの lint は、新たな違反なしで通過した。git diff --check も通過した。

最終版の iPhone テストコマンドは正常終了した。テストスイートの通過後、Xcode の結果収集が子プロセスの simctl diagnose で滞留した。この診断収集プロセスだけを終了すると、両方の結果バンドルの保存が完了し、終了コードは 0 になった。テストランナーとアプリは中断していない。任意の診断アーカイブは未完成。

手動確認が残っている項目は、実機での VoiceOver の読み上げと AirPlay の出力先選択、実機での動画の全画面再生、Dock 以外の画面での非常に大きな Dynamic Type の文字サイズ、プレイリストのドラッグによる並べ替え。自動テスト用データは音声のみを含む。

PR #16 のレビューで確認した歌詞編集とミュートの不具合

修正コミットは 7748247。

歌詞エディターは、iPhone でも最小幅 420 pt を要求していた。デッキのツールバーと歌詞パネルの編集ボタンの両方から同じシートを開くため、エディター自身で usesPhoneLayout を読み、iPhone では最小寸法と推奨寸法の指定を外す。macOS と iPad では従来の寸法を使用する。歌詞エディターの指摘を確認し、ほかの編集シートでも同じ寸法制約が残っていないか調べた。

ミュートボタンは、状態に応じてアイコンを更新する一方、アクセシビリティラベルを常に Mute にしていた。IPhoneTransportButton のタイトルを isMuted に応じて Unmute/Mute に切り替え、既存の日本語訳「ミュート解除」/「ミュート」を使用する。ミュートの指摘と同じ原因は、Play/Pause ボタンや macOS のメニューにはなかった。

幅 420 pt 未満の iPhone 17e(iOS 27)の回帰テストでは、歌詞編集欄、保存・キャンセル、保存先ピッカーが画面内に収まることと、保存・キャンセルでシートを閉じられることを日英で確認する。ミュートの回帰テストでは、ボタンを2回タップし、読み上げに使うラベルが Mute → Unmute → Mute、日本語では「ミュート → ミュート解除 → ミュート」と変わることを確認する。実機の VoiceOver による音声出力は、この UI テストの確認範囲に含めない。

2026 年 10 月 3 日の iPhone 17e(iOS 27)での検証では、該当する修正を外した状態で、ミュート後のラベルが Mute のままという比較エラーと、App Only が画面外にあるという検査エラーをそれぞれ再現した。修正後は、日英のデッキテスト2件と日英の歌詞エディターテスト2件がすべて通過した。iOS アプリとテストターゲットのビルドも、この実行で完了した。

歌詞編集の回帰テストは IPhoneLibraryWorkflowUITests/testEnglishLyricsEditorFitsPhoneScreen と testJapaneseLyricsEditorFitsPhoneScreen。ミュートの確認は既存の IPhoneLayoutUITests に追加した。今回実行した対象を再検証するコマンドは次のとおり(端末 ID は実行環境に合わせる)。

xcodebuild -project SimpleMediaPlayer.xcodeproj -scheme SimpleMediaPlayer \
  -destination 'platform=iOS Simulator,id=88FD8DBD-CE09-4851-9262-B1173156FE17' \
  -derivedDataPath .build/DerivedData -clonedSourcePackagesDirPath .build/SourcePackages \
  -skipPackagePluginValidation -parallel-testing-enabled NO -collect-test-diagnostics never \
  -only-testing:SimpleMediaPlayerUITests/IPhoneLayoutUITests/testEnglishDarkDeck \
  -only-testing:SimpleMediaPlayerUITests/IPhoneLayoutUITests/testJapaneseLightBacklitDeck \
  -only-testing:SimpleMediaPlayerUITests/IPhoneLibraryWorkflowUITests/testEnglishLyricsEditorFitsPhoneScreen \
  -only-testing:SimpleMediaPlayerUITests/IPhoneLibraryWorkflowUITests/testJapaneseLyricsEditorFitsPhoneScreen \
  CODE_SIGNING_ALLOWED=NO test

最初のミュート再現テストでは、テストが失敗した後の simctl diagnose が滞留した。テスト終了をログで確認してから、この診断収集プロセスだけを終了すると、失敗結果の保存が完了し、コマンドは終了コード 65 を返した。以後の対象テストでは、Xcode 27 のヘルプに記載された -collect-test-diagnostics never で任意の詳細診断収集を無効にし、テスト結果は通常どおり保存した。

macOS のビルド、LocalizationTests の6件、PlayerViewModelTests の20件も通過した。日英のリソース検査には Mute/Unmute を追加し、再生モデルでは既存の volumeClampsAndMuteRestoresLastAudibleVolume の通過を確認した。変更した Swift ファイル5件の厳格モードの lint は違反なし、全体の通常モードの lint は既存の警告46件・重大な違反0件で通過した。ベースラインは変更していない。git diff --check も通過した。

今回の検証では、iPad の UI テストと実機での VoiceOver の音声確認は実行していない。iPad の寸法指定が変更前と同じであることは差分で確認し、iOS ターゲットのビルドでコンパイルを検証した。

PR 全体の追加検査で確認した不具合

修正コミットは f37d065。関連する呼び出し元も見直し、検査で確認した指摘はすべて解消した。

テストランナーを介さない iOS の通常起動では、同梱した wavpack.framework を dyld が発見できず、起動直後に終了した。Frameworks ディレクトリはアプリ内に存在するが、Debug・Release の検索先に macOS 用の @executable_path/../Frameworks しかなく、iOS 用の @executable_path/Frameworks がなかった。両方を検索先に加え、macOS の既存の検索先も維持する。iPhone 17e にビルドしたアプリをインストールし、simctl launch でライブラリが表示されることを確認した。これは PR 前の main にも存在する設定不備で、UI テストだけでは検出できなかった。

ライブラリから曲を削除する経路では、PlaylistEntry.item に逆関係がないため、削除した曲への参照が残っていた。保存後に新しい ModelContext で読み込むテストでは、参照が空にならず、曲名を取得すると無効化されたモデルへのアクセスでクラッシュした。LibraryService.delete で該当するプレイリスト項目を検索し、削除前に item = nil とする。同じ曲を含む複数のプレイリストについて、再読み込みで参照が解除されることを検証する。スキーマは変更しない。

曲への参照が空のプレイリスト項目は表示から除外される。そのため、画面上の移動元・移動先インデックスを全項目の配列へ適用すると、別の項目を動かしてしまう。並べ替えを Playlist.moveItems に集約し、曲が存在する項目だけを移動する。削除済みの項目は相対順序を保って後ろへ配置し、保存用の並び番号を付け直す。macOS/iPad の「上へ移動」「下へ移動」も同じ処理を使用する。

デッキ内の AAC 完了コールバックは、デッキを閉じると表示されない状態へ結果を書き込んでいた。結果のメッセージと通知の有無を MainView に保持する形へ変更した。デッキの表示フラグで通知先を選び、表示していない側の Binding setter が保留中の通知を消さないようにする。変換開始時のタイトルも固定し、途中でメタデータを編集しても結果の説明が変わらないようにした。

デッキの「その他」メニューは、AAC 項目の中央をタップする UI テストで選択されず、メニューが残る場合があった。AX の行の矩形と合成入力の座標は一致していた。通常起動したシミュレーターの操作でも、文字側へのクリックは反映されず、アイコン側へのクリックでは変換を開始できた。ラベル形式の指定だけでは繰り返し実行で失敗が残った。最終的には、メニューを開くラベルの44 ptの寸法と、各項目のラベルの幅・contentShape(Rectangle()) を分けて明示した。中央のタップから変換開始・デッキ終了・成功通知までの回帰テストが2回連続で通過した。LED のスクロール文字とガラスはヒット判定を無効にしており、メニュー文字側の入力を遮る独自の UIKit ヒット判定はなかった。SwiftUI 内部で入力領域が狭くなる具体的な原因は特定していない。

変換処理自体にも、埋め込みタグは開始時の情報を使用し、ライブラリ登録では完了後の原曲を読み直すという不整合があった。制御できる renderer を使い、開始を確認してから原曲のアーティストを編集し、描画を完了させるテストで再現した。埋め込みタグは Artist のまま、コピーのモデルは Edited Artist になった。削除・保存後に完了させるテストでも、コピーが新しく登録されていた。この経路のテストでは、SwiftData のクラッシュは発生していない。

TransformedTrackSourceSnapshot は最初の待機前に原曲の情報・歌詞・アートワークと登録 ID を保持する。空値や nil を変更せず、コピーのモデルにも開始時の値を使用する。原曲が登録済みなら、描画後のコピー開始前と、ファイルコピーの待機後の登録直前に ID の存在を確認する。削除されていれば CancellationError で中止し、描画用・ライブラリ用の一時出力を片付ける。デッキを閉じる操作は原曲の削除と区別し、変換と通知を継続する。未登録の項目からコピーを登録する既存のサービス API は維持する。変換コピーの登録とファイルコピーは LibraryService+TransformedCopy.swift にまとめ、lint のベースラインは増やさない。

音声をキー・速度変更した後に動画へ切り替えると、変更値はモデルに残る。動画には適用されないため、iPhone の KEY/SPEED は既存のデスクトップ表示と同じ 0/1・消灯表示にそろえ、動画の Dock/Strip ではキー変更の表示を隠す。「次に再生」の現在項目の読み上げも、再生中・一時停止中・停止中を区別する。停止中の日本語訳を追加した。

一時停止と停止を再生時刻で推定すると、一時停止後に0秒へシークした場合は停止表示となり、停止後に0秒以外へシークした場合は一時停止表示となる。PlayerViewModel.isPaused で操作の状態を保持し、デッキの読み上げ、共通の操作ボタン、LED の記号を同じ値にそろえる。新しい再生、再開、停止、クリア、エラーでは一時停止状態を解除し、シークとエンジンの再設定では維持する。

読み込めない曲へ切り替える経路では、旧項目の再生中に currentItem を先に変更し、URL 解決に失敗すると旧再生が継続していた。URL 解決を項目の切り替えより前に行い、失敗時は旧項目の種類に対応するクリア処理で停止する。現在の項目を解除するため、失敗後の再開操作でも旧音声を再生しない。

再生デッキの LED は、固定高さの子要素と間隔だけで 294 pt を要求し、上下の余白を除いた内部高さ 282 pt を超えていた。行間を 14 pt から 8 pt へ変更し、同梱フォントによる先頭行を含めて収まる寸法にした。時刻付き歌詞の強調表示は、各行の装飾ごとに全行を検索していたため、描画更新につき一度だけアクティブ行を求める形へ変更した。

書き出し名入力画面では、キーボードを表示すると一覧の最小高さ 280 pt と縦フッター内の Spacer により、タイトルが欠け、書き出しボタンが候補表示に隠れていた。修正前の英語 UI テストは、入力済みで有効な「書き出す」ボタンの操作可能性検査に失敗した。録画でも重なりを確認した。iPhone では一覧の最小高さとフッターの Spacer を外し、macOS/iPad の寸法は維持する。AX のキーボード枠には候補表示の一部が含まれないため、枠の比較だけで操作可能と判断しない。

iPhone の新しい画面には既存の再生用 FocusedValue の提供元がないため、外部キーボードの再生/一時停止・前曲・次曲コマンドが無効になっていた。iPhone で提供元がない場合は現在のプレイヤーを操作する。macOS/iPad では従来の提供元と有効性判定を維持する。

2026 年 10 月 3 日の追加検査では、macOS の PlaylistOrderingTests・LocalizationTests・PlayerViewModelTests・PlayerPlaybackStateTests・TransformedExportCancellationTests・LibraryServicePersistenceTests の54件が通過した。既存の未登録項目からのコピー登録、情報の継承、キャンセル、AAC の実レンダラーによる出力、一時停止と停止の境界、読み込み失敗後の再開拒否を含む。iOS 27 の iPhone 17e では PlayerViewModelTests・PlayerPlaybackStateTests・PlaylistOrderingTests・TransformedExportCancellationTests の41件が通過した。iPad Pro 11 インチ M5 の基本画面・設定操作テストと、並べ替えの単体テスト6件も通過した。

日英のデッキ回帰テスト2件は、ミュートに加えて「次に再生」の再生中→一時停止中→停止中を確認して通過した。日英の書き出し名入力テスト2件と、共有シートへの書き出し・終了・再書き出しの確認も通過した。AAC のデッキ終了後の通知テストは、最終的なメニューの修正後に2回連続で通過し、再生状態の修正後にも再実行して通過した。日英のデッキ回帰テスト2件も最終版で再実行した。DEBUG && os(iOS) と2つのテスト用起動引数がある場合だけ renderer をバックグラウンドで10秒待機させ、変換完了前にメニューとデッキを閉じる順序を再現する。ライブラリ画面の成功通知と開始時の曲名を検査する。通常起動の renderer は変更しない。

変更した Swift ファイルのうち既存違反のない19件の厳格モードの lint は、違反なしで通過した。全体の通常モードでは135件のファイルに既存警告47件・重大な違反0件で通過した。PlayerViewModel のメソッドは同じファイルの extension に分け、クラスの長さの重大な違反を解消した。ファイルの長さの既存警告が再表示され、警告数は46件から47件となった。既存の巨大テストファイルには新規テストを追記せず、共通 fixture のアクセス範囲だけを変更し、回帰テストを別ファイルへ置いた。既存違反を持つ4ファイルは変更箇所を差分で確認した。ベースラインは変更せず、長さの違反を抑制する指定も追加していない。テスト用 renderer の必須6引数の宣言には、理由のコメントを付けて引数数のルールだけを局所的に無効化した。

未検証なのは、非同期ファイルコピーの待機中に原曲を削除する順序の直接再現、デッキ終了アニメーション中・子シート表示中の AAC 完了、実機の VoiceOver・AirPlay・外部キーボード、横画面と極端に大きい文字サイズでの書き出し入力操作。コピー待機中の削除はコピー後の ID 確認で防ぐ構造を確認したが、renderer の開始と終了を制御する今回のテストでは、そのタイミングを直接再現していない。

下部の再生パネルの配置修正

標準の下部アクセサリーへ高さ 66 pt の LED、独自のパネル背景、丸い再生ボタンを重ねると、標準のカプセル形状と寸法が一致せず、端部に背景が露出し、文字と操作が詰まっていた。iPhone 17e の UI テストでは、曲名のボタンと再生ボタンの領域が約 0.5 pt 重なり、8 pt 以上の間隔を求める検査に失敗した。ボタンが画面内にあり、44 pt 以上あることだけでは、こうした配置の問題を検出できない。

Dock は標準アクセサリーのガラス背景に、Dynamic Type 対応の曲名・経過時間と標準の SF Symbols の操作を置く形へ変更した。コンテンツは高さ 44 pt、左右の余白と操作部の間隔は 12 pt にする。長い曲名は末尾を省略し、完全な曲名と時刻はアクセシビリティ値に保持する。タブバーの縮小時に使用する .inline の配置では時刻と次曲ボタンを省略する分岐を置くが、現在の画面は .tabBarMinimizeBehavior(.never) を使用しており、この分岐は動作検証していない。

最大のアクセシビリティ文字サイズだけでは、2 行を表示する通常の大きな文字サイズの余裕を検査できない。.xxxLarge のテストは操作領域の検査を通過したが、スクリーンショットでは曲名と時刻が上下端に詰まっていた。ViewThatFits で縦方向の理想サイズを判定し、2 行が収まらない場合は曲名だけに切り替える。候補の内部に固定高さを置かず、外側に 44 pt の最小タップ領域を設定することで、文字の高さの違いに対応する。

この配置は、Apple の Layout、Buttons、Tab bars にある、主要な情報と操作のための領域を確保する方針と、タブバーの上の再生アクセサリーの例を参照した。Adopting Liquid Glass に従い、標準背景を妨げる独自の背景を重ねない。12 pt の間隔はこの画面で選んだ寸法であり、HIG に一律の値として規定されているものではない。

通常のスペクトラムを 44×16 pt に縮める実装も、Dock と歌詞・情報ページの LED 帯で共通だった。スペクトラムには中央の 38 pt の間隔、バーとセグメントの最小寸法があるため、狭い領域では描画が領域を越え、L/R などの文字が重なる。小型表示からこのビジュアライザーを外し、必要な領域を持つデッキの「ディスプレイ」ページだけで表示する。

長い日英混在の曲名を持つテストデータと、SwiftUI の Dynamic Type を .xxxLarge/.accessibility5 にする DEBUG 専用設定を使用する。どちらも明示的な UI テスト用起動引数が必要で、通常起動では適用しない。Dock の操作領域、画面内への収まり、8 pt 以上の間隔、完全な曲名のアクセシビリティ値、再生/一時停止・次曲・キュー終端での次曲ボタンの無効化・デッキを開く操作を検査する。背景と文字の表示は保存したスクリーンショットで確認する。

修正コミットは 4f8a909。2026 年 10 月 3 日に、次の範囲を検証した。

  • iPhone 17e(iOS 27):日英・外観と LED スタイルの 4 通りのデッキ回帰テスト、日英混在の長い曲名と最大文字サイズの日英テストが通過した。縦方向の理想サイズによる切り替えを加えた最終版で、通常サイズの英語・ライト、大きな文字の .xxxLarge、最大文字の日本語・ダークを再実行して通過した。保存画像で通常は 2 行、大きな文字では曲名のみになり、文字の欠けや重なりがないことを確認した。
  • iPhone 17 Pro Max(iOS 27):日本語・ライト・バックライトの Dock・デッキ・歌詞の帯と、長い曲名・最大文字の英語テストが通過した。最終版でも英語・ダークのデッキ回帰テストと長い曲名・最大文字のテストが通過した。保存画像で Dock の背景と文字、縮小した LED 帯の表示を確認した。
  • iPad Pro 11 インチ M5(iOS 27):主画面と設定の基本操作テスト 1 件が通過した。
  • macOS 27:アプリとテストターゲットのビルド、LocalizationTests の 6 件が通過した。macOS 専用の UI テストは今回再実行していない。専用 Dock は iOS に限定し、既存の .standard の LED 表示経路は差分で確認した。
  • 変更した Swift ファイル 7 件の厳格モードの lint は違反なし。全体の通常モードは 136 ファイルに既存の警告 47 件・重大な違反 0 件で通過した。ベースラインは変更していない。コードと Wiki の git diff --check も通過した。

実機での VoiceOver の音声、透明度を下げる設定とコントラストを上げる設定での表示は今回確認していない。VoiceOver に公開するボタンの種類・日英のラベル・完全な曲名の値は、コードと UI テストで確認した。

LED 色設定の文字拡大対応(PR #16)

追加レビューでは、iPhone の設定画面にある色プリセットの横並びが指摘された。iPhone 17e のシミュレーターで、修正前の通常文字サイズでも Green などの色名が数文字ずつに分断されることを確認した。LEDColorEditor は、通常の表示色、バックライト時の表示色、バックライト色、VU メーターの盤面色・ランプ色の計 5 か所で共用されている。

プリセットは ViewThatFits(in: .horizontal) で配置を選ぶ。横並び候補の幅は fixedSize(horizontal: true, vertical: false) で自然な幅に保ち、収まらないときは縦並びにする。選択チェックマークと日英の色名を含めて判定するため、端末種別だけによる切り替えは不要である。

最大アクセシビリティ文字サイズでは、隣の色コード入力欄と Apply も横並びでは収まらなかった。修正前の入力欄は約 134 pt で、7 文字分の約 229 pt より狭く、#FF9F2E が #F… と省略された。この行はアクセシビリティ文字サイズで縦並びに変更した。AnyLayout を使い、レイアウトを切り替えても同じ入力欄を保持する。

LEDSettingsLayoutUITests は、設定メニューから画面を開き、各プリセットの到達性・表示範囲・文字寸法、Orange 選択後のチェックマークを含む表示範囲、色コードへの反映、入力欄の幅、Apply の操作を検証する。既存の --ui-testing-phone-large-text によるルートの環境値変更だけでは、この設定シートは通常文字サイズのままだった。新しいテストではアプリの起動設定 UIPreferredContentSizeCategoryName を使い、実際の文字寸法と保存画像でも拡大を確認する。

2026 年 10 月 3 日に Xcode 27 で次の検証を実施した。

  • iPhone 17e・iOS 27:通常サイズの英語と、最大アクセシビリティサイズの英語・日本語の UI テスト計 3 件が通過した。保存画像で色名・選択チェック・色コード全体・Apply/適用の表示を確認した。
  • iPad Pro 11 インチ M5・iOS 27:主画面から設定を開いて閉じる既存 UI テスト 1 件が通過した。
  • macOS 27:ビルドと BottomPanelSettingsTests、LEDColorValueTests、VUMeterPaletteTests、LocalizationTests の計 24 件が通過した。
  • 変更した Swift ファイル 2 件の厳格 lint は違反なし。全体の通常 lint は既存警告 47 件・重大違反 0 件で通過した。ベースラインは変更していない。

バックライト用の 2 つの色エディターと VU メーター用の 2 つは、共通部品の呼び出し元として差分とコードで確認したが、今回の UI テストでは個別に操作していない。macOS の設定画面の描画、実機、VoiceOver の音声は今回未検証である。

残る選択項目と情報表示の文字拡大対応(PR #16)

追加レビューでは、LED 設定のセグメント型ピッカーも iPhone の最大文字サイズでは収まらないと指摘された。修正前の英語 UI テストは、選択肢の文字枠の高さが 16 pt にとどまった状態で失敗した。色プリセットだけでなく、表示スタイル・時刻・メディア情報・ガラス効果・スペクトラム応答の各選択肢を検査する必要がある。

AdaptiveSettingsPicker は、iPhone またはアクセシビリティ文字サイズで、折り返し可能な本文サイズの選択ボタンを縦に並べる。選択状態はチェックマークと AX の selected trait に公開し、元の Binding と選択肢ごとの無効化条件を使用する。通常文字サイズの iPad/macOS では従来のセグメント表示を維持する。iPad/macOS 専用のパネル配置・LED 位置・角の選択も、この部品を使用する。

同じ原因が残っていた歌詞の保存先と検索条件の Match も、この部品へ変更した。歌詞エディターはアクセシビリティ文字サイズで保存先の領域をスクロール可能にし、本文の編集領域を確保する。検索の見出しと操作ボタンは同じ文字サイズで縦に並べ、iPhone に固定の推奨寸法を要求しない。

デッキの 4 つのページ名は、最大文字サイズの保存画像で省略されていた。アクセシビリティ文字サイズでは、現在のページ名を表示する標準メニューへ切り替える。情報ページの値とアートワークなしの表示は、iPhone では固定の 13 pt から本文サイズへ変更し、複数行の高さを確保する。曲一覧の現在項目も、装飾アイコンに常に「再生中」と付ける方法をやめ、行の値で再生中・一時停止中・停止中を区別する。

設定を変更する UI テストの初期値を起動引数で指定すると、UserDefaults の argument domain が変更後の永続値より優先され、選択が反映されない。明示的な DEBUG 用引数 --ui-testing-reset-led-settings を使用し、テストデータの作成時に永続値を初期化する。通常起動では初期化しない。テストは選択肢の到達性・完全な日英ラベル・文字寸法・画面内への収まりに加え、別の値への変更と元の値への復帰、双方の selected trait を確認する。

歌詞エディターと情報画面のスクロール検証では、画面全体ではなく、対象の ScrollView の表示領域への収まりを確認する。画面外の AX 要素は存在していても高さ 0 の枠を返すため、それを可視状態と判断しない。小さな領域で大きくドラッグすると、慣性で可視範囲を行き過ぎて往復する。表示領域に応じた短いドラッグと低速・終了前の保持を使い、選択後に最初の項目へ戻す方向も明示する。

日本語だけの短い文字列では、AX の Text の枠がフォントの行間を含まず、文字の輪郭に近い高さとなる場合がある。最大本文サイズの「低速」は、フォントの行高が約 63 pt に対して AX の高さは 44 pt だった。文字縮小と誤判定しないよう、LED 選択肢の高さは、指定言語・本文フォント・実際の幅で CoreText に組版させた文字輪郭と比較する。折り返した行の基準位置を含め、全字数を組版できたことも確認する。修正前の 16 pt の表示は、この判定でも必要な文字の高さに届かない。

情報画面のテストでは、選んだ曲を一時停止してから検査する。60 秒の音源を再生したまま長い UI 検査を行うと、キューが次の曲へ進み、情報画面も新しい曲へ更新される。枠やスクロールの不具合と誤認しないよう、行の AX 値が一時停止中になったことを確認してから、選んだ曲の値を検査する。

修正コミットは f10b6ae。2026 年 10 月 3 日に Xcode 27 で次の範囲を検証した。

  • iPhone 17e・iOS 27:UI テスト計 16 件が通過した。LEDSettingsLayoutUITests の 6 件は、通常サイズの英語と最大文字サイズの日英で、5 グループ・13 選択肢と色プリセットを検査する。IPhoneEditorPickerUITests の 4 件は、最大文字サイズの日英の保存先・検索条件を変更して戻し、歌詞編集領域と終了操作も確認する。IPhoneInformationAccessibilityUITests の 2 件は、最大文字サイズの日英のアートワークなし・曲名・アーティスト・アルバム・ファイル名の本文サイズと表示領域への収まりを検査する。通常サイズの日英のデッキと歌詞編集の既存 4 件も通過し、曲一覧の読み上げ値の停止中→再生中→一時停止中を確認した。
  • iPad Pro 11 インチ M5・iOS 27:IPadLayoutUITests の 2 件が通過した。通常サイズではパネル配置のセグメント表示を維持し、最大文字サイズではガラス効果の 4 選択肢の寸法・選択変更・選択状態を確認した。
  • macOS 27:ビルドと BottomPanelSettingsTests、LEDColorValueTests、VUMeterPaletteTests、LocalizationTests、PlayerPlaybackStateTests、MediaInfoDetailsTests の計 34 件が通過した。
  • 変更した Swift ファイル 13 件の厳格 lint は違反なし。全体の通常 lint は 140 ファイルに既存警告 47 件・重大違反 0 件で通過した。ベースラインは変更していない。コードと Wiki の差分検査も通過した。

保存画像では、日英の選択肢の折り返し、チェックマークとの間隔、歌詞の編集領域、検索の終了ボタン、情報の複数行表示を確認した。実機の VoiceOver の音声、横向き iPhone、macOS の設定画面の描画は今回未検証である。iPad/macOS の歌詞編集と検索は呼び出し元と差分で確認したが、最大文字サイズの画面操作は個別には検証していない。

Clone this wiki locally