Flutter Webで「このサイトを離れますか?」を表示する(beforeunloadイベント)
はじめに
Flutter Webでスプラトゥーン2のプレイヤー向けの動画プレイヤーアプリを作成しました。プレイの録画ファイルをブラウザにドラッグアンドドロップすると、動画を開き、やられたシーンなど重要シーンを頭出しします。
頭出しは画像認識で行っているので時間がかかります。そして、うっかりタブを閉じてしまった場合は、残念なことに、また最初からの頭出しになってしまいます。よって、動画を開いているときにタブを閉じたときはブラウザ標準の「このサイトを離れますか?」ダイアログを表示します。
前提
Flutterと状態管理に使用しているライブラリのバージョン
- Flutter 2.2.3-stable
-
hooks_riverpod 1.0.0-dev.7
-
freezed 0.14.2
すこし古いのでバージョンアップしようとしたのですが、Chromeによるデバッグ実行ができなくなる問題を回避できなかったため、現状動くバージョンでの解説になります。
動画ファイルの開閉状態
動画を開いている等のUIの状態はfreezedで作成したクラスとStateNotiferで管理しています。
@freezed
abstract class MainUiModel with _$MainUiModel {
const factory MainUiModel(
bool isOpen /* trueの時は動画ファイルを開いている */,
String fileName /* 開いた動画ファイルの名前 */
/* 略 */
) = _MainUiModel;
}
class MainUiModelStateNotifier extends StateNotifier<MainUiModel> {
/// 動画ファイルがドラッグアンドドロップ領域に落とされた
/// [fileName] ファイル名
void onDrop(String fileName) {
state = state.copyWith(fileName: fileName, isOpen: true);
}
/// 動画ファイルを閉じる
void onCloseFile() {
state = state.copyWith(fileName: "", isOpen: false);
}
}
final mainUiModelStateNotifierProvider =
StateNotifierProvider<MainUiModelStateNotifier, MainUiModel>((ref) {
return MainUiModelStateNotifier();
});
isOpenフラグがtrueの時のみ、タブを閉じたときに「このサイトを離れますか?」を表示したいです。
JavaScriptでの実装方法
JavaScriptではbeforeunloadイベントを使って実装することができます。
参考 Window: beforeunload イベント - Web API | MDM
window.addEventListener('beforeunload', (event) => {
event.preventDefault();
event.returnValue = '';
});
Flutter Webでの実装方法
Flutter Webではbeforeunloadイベントはdart:htmlライブラリWindowクラスのonBeforeUnloadプロパティに実装されています。こちらは Stream<Event>
クラスのインスタンスが取得できます。よって、StreamProvider.autoDisposeを使ってこのように実装しました。
final confirmTabCloseStreamProvider = StreamProvider.autoDispose<bool>(
(ref) => window.onBeforeUnload.map((event) {
// BeforeUnloadEventにキャスト
final beforeUnloadEvent = event as BeforeUnloadEvent;
// UIの状態を取得
final mainUiModel = ref.read(mainUiModelStateNotifierProvider);
// 動画を開いているときのみ「このサイトを離れますか?」を表示する。
if (mainUiModel.isOpen) {
beforeUnloadEvent.preventDefault();
beforeUnloadEvent.returnValue = '';
}
// 流すインスタンスは何でも良い。
return true;
}));
こちらのStreamProviderをタイトル部分など常に表示されているHookConsumerWidgetで監視します。
/// タイトル部分
class TitleWidget extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
// 表示のための状態を監視
final mainUiModel = ref.watch(mainUiModelStateNotifierProvider);
// タブを閉じるときの確認担当。
final futureConfirmTabClose = ref.watch(confirmTabCloseStreamProvider.last);
// 長いアプリ名
var title = Strings.titleLong;
// 動画ファイルを開いている時は「短いアプリ名 - 動画ファイル名」にする
if (mainUiModel.fileName.isNotEmpty) {
title = sprintf("%s - %s", [Strings.title, mainUiModel.fileName]);
}
double fontSize = 19;
final titleStyle = TextStyle(fontSize: fontSize, color: Colors.white);
return Text(title, style: titleStyle);
}
}
Author And Source
この問題について(Flutter Webで「このサイトを離れますか?」を表示する(beforeunloadイベント)), 我々は、より多くの情報をここで見つけました https://qiita.com/tfandkusu/items/d107bcb6da3e04c4b9aa著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .