FlutterFlow: Limiting photos to upload
写真の添付はモバイルアプリに付き物の機能の一つですよね。
FlutterFlowでは、アクションを1つ設定するだけで、簡単にFirestoreに写真をアップロードできます。
しかし、残念なことに、FlutterFlowから提供されているアクションには数を制限する機能が無いのです。悪意の無いユーザばかりなら良いのですが、これまで性悪説でシステムを開発してきた私にとっては見過ごせないものでした。
まず考えられる方法としては、いったん無制限でアップロードさせつつも、超過した分をスケジュールタスク等で削除する方法です。これならタスクを作成するコストはかかりますが、不要な写真によって発生するストレージ費用が帳消しします。しかし、機能を作り込むことになるため、そのためのテストや運用を考えておかないと、誤ったファイルが消されてしまうリスクが伴うため、安定した運用体制を約束出来ない限りはおすすめできません。
そこで、試行錯誤した方法をご紹介します。
結論から言いますと、アクションを2つに分割するのです。
1つはユーザから選択された写真をリスト変数に保存(その際に制限数に限定する)するアクション、もう1つはリスト変数に保存された写真をアップロードするアクションです。(別のアクションとはせず、同一のアクション内で処理ブロックを分けても良いです)
例えば、以下のような画面で考えます。
「Attach Photos」で写真を添付し、問題無ければ「Save」で保存します。
まず、「Attach Photos」のアクションを見てみましょう。
1. リスト変数に保存(Attach Photos)
関連部分だけ切り出しているので、比較的シンプルな構造です。
Store media for upload
ユーザにギャラリーから写真を選択してもらいます。Loop ~ Update Component State
1で選択された画像を、制限した回数分だけリスト型の変数に格納します。Update Component State ~ Clear Uploaded Data
後処理です。
順に見ていきましょう。
Store media for upload
「Store media for upload」でユーザにギャラリーを表示し、写真を選択してもらいます。
「Allow Multiple Images」を忘れないでください。複数選択できなくなります。
Loop ~ Update Component State
ループ中の「Update Component State」から先に説明します。
ユーザがギャラリーで選択後は、「Widget State/Uploaded Local Files」に選択された画像がリスト形式で収録されています。そのリストから、ループのインデックスを示す変数(onUploadOperationPhotoCounter)の位置にある要素を取り出し、一時的に写真を記録するページ変数(uploadedPhotos)に要素追加します。
uploadedPhotosもList<Uploaded File (Bytes)>型であることに注意してください。
その次のアクションでは、単純にループのインデックス変数をインクリメントします。先のアクションも同じ「Update Component State」のため、もしかすると同時に更新しても良いかもしれませんが、インデックスを頼りにした処理とインデックス自体の更新を同じアクションに記述するよりは、処理の意図を明確にし、今後の保守での間違いを防ぐためにも分けたほうが良いと考えます。
さて、スキップしていたループの条件は以下の2つの組み合わせです。
インデックス変数がギャラリー選択画像の数未満
写真を記録するページ変数の要素数が、指定した制限数未満(指定にはConst機能をおすすめします)
Update Component State ~ Clear Uploaded Data
あとは、後処理をするだけです。制限数に達しなかったとき、追加の画像選択を許すために、追加時に備えてインデックス変数を初期化します。
また、ギャラリーの選択状態を「Clear Upload Data」を使って消します。
これを忘れると、再度ギャラリーを開いたときに、もう一度前回分が対象になってしまいます。
これで1つ目のアクションブロックが完了しました。
次は永続化です。
2. 写真をアップロード(Save)
リスト型に写真を保存していましたので、アップロード時もループ処理になります。
アクション全体は以下のとおりです。(こちらも、必要な分だけ抜粋しています)
Loop ~ Updata Page State
こちらも、まずはループの中身から説明します。
リスト型の変数に格納されたバイト情報を、Firebaseにアップロードします。「uploadedPhotos」は、写真を記録したリスト型の変数、「onSavePhotoCounter」はループのインデックスを示す変数です。
このとき、「Multiple Images」にチェックしたくなりますが、後述するドキュメントの更新時に、アップロードされた写真のリンクを記録する必要があるため、有効にはしません。
次に、アップロードされた画像のリンクをドキュメントに記録します。
「Value Source」プルダウンから、アップロードされた写真が選択できます。
ループ最後は、インデックス変数のインクリメントです。
スキップしていたループの条件では、インデックス変数が写真を格納しているリストの要素数内であることをチェックします。
ループを抜けたら、インデックス変数を初期化して完了です。
長かったですね。「枚数を制限」オプションが提供されていないことで、こんな面倒なことになってしまいました。もし他に良い方法がありましたら、コメントしてもらえると励みになります。