nginxのドキュメントルート
/usr/share/nginx/html
almalinux8.8を使って、var/www/htmlがなかったので焦りました…
$ ls
adm crash empty games kerberos local log nis preserve spool yp
cache db ftp gopher lib lock mail opt run tmp
随机应变 ABCD: Always Be Coding and … : хороший
nginxのドキュメントルート
/usr/share/nginx/html
almalinux8.8を使って、var/www/htmlがなかったので焦りました…
$ ls
adm crash empty games kerberos local log nis preserve spool yp
cache db ftp gopher lib lock mail opt run tmp
### build
firebaseへデプロイする前に、ファイルをcompileします
$ flutter build web
Fireforceのhosting機能を有効化
プロジェクトのcurrent directoryで
$ sudo npm install -g firebase-tools –force
$ firebase login
プロジェクトの初期化
$ firebase init
=> publicのdirectoryを ./build/web/ で設定する
firebase
$ firebase deploy
webアプリをbuildする
$ flutter build web
$ firebase deploy
firebase hostingを無効化する
$ firebase hosting:disable
OKKKKKKKKKKKKKKKK
Flutterでsession_storageのパッケージを利用します。
https://pub.dev/packages/session_storage
pubspec.yaml
dependencies: session_storage: form_field_validator: flutter: sdk: flutter
main.dart
import 'package:session_storage/session_storage.dart'; // 省略 onTap: (int value) { if (value == 1) SessionStorage()..addAll({'language': 'english'}); Navigator.push( context, MaterialPageRoute(builder: (context)=> SecondScreen()), ); } // 省略 body: Center( child: Container ( child: Text( 'Here: ${session['language']}', style: const TextStyle(fontSize:32.0)), ), ),
セッションとDBが使えるとかなり幅が広がる
firestoreにフィールドの値が挿入されているか確認し、値の有無によってflutter側でリダイレクト処理を行う
=> 単純にif nullで処理できる
final snapshot = await firestore.collection('mydata').doc('12345678').get(); final Map<String, dynamic>? mydata = snapshot.data(); if (mydata?['hoge'] != null) { msg = '値があります'; } else { msg = '値がありません'; }
これにアラートメッセージを追加する
if (mydata?['hoge'] != null) { msg = '値があります'; } else { showDialog( context: context, builder: (BuildContext context) => AlertDialog( title: Text("値がありません"), content: Text("値がありません"), ) );
エリアを指定してアラート文を表示が一般的かもしれないが、アラートダイアログなどを一発で実装できるのもFlutterの良いところですね。
docでuidを指定した後に、mapで取得する。その際に、Map
String? msg = ''; FirebaseFirestore firestore = FirebaseFirestore.instance; final snapshot = await firestore.collection('mydata').doc('12345678').get(); final Map<String, dynamic>? mydata = snapshot.data(); msg = mydata?['name']; _controller.text = msg!;
firestoreではなく、flutterの中でmap型を指定する場合は以下のように書いてOK
final Map<String, String> frameworks = { 'Flutter' : 'Dart', 'Rails' : 'Ruby', };
コレクションを複数指定する場合とは書き方が大分異なる
var msg = ''; FirebaseFirestore firestore = FirebaseFirestore.instance; final snapshot = await firestore.collection('mydata').orderBy('name', descending: false).get(); snapshot.docChanges.forEach((element) { final name = element.doc.get('name'); final mail = element.doc.get('mail'); final age = element.doc.get('age'); msg += "${name} (${age}) <${mail}>\n"; }); _controller.text = msg;
uidを指定して、setを実行するとcollection自体の値が全て更新されてしまう。
var msg = _controller.text; final data = { 'address': msg, }; FirebaseFirestore firestore = FirebaseFirestore.instance; final snapshot = await firestore.collection('mydata').doc('12345678').set(data);
コレクション自体を残す場合はsetではなく、updateを使用する
var msg = _controller.text; final data = { 'address': msg, }; FirebaseFirestore firestore = FirebaseFirestore.instance; final snapshot = await firestore.collection('mydata').doc('12345678').update(data);
引数に値を入れる
static var _prev = 'ページ1'; void buttonPressed() { setState(() { // Navigator.pushNamed(context, '/complete'); Navigator.push(context, MaterialPageRoute(builder: (context)=>CompleteScreen(_prev)),); }); }
複数画面の入力フォームなどはどのような設計にするかは要検討か
https://pub.dev/packages/form_field_validator
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Form ( key: _formKey,
Widget build(BuildContext context)は複数記述できないので、body: Formと書く
そうすると、TextFormFieldが使えるようになる
Padding( padding: EdgeInsets.all(10.0), child: TextFormField( controller: _id_controller, style: TextStyle( fontSize: 28.0, color: const Color(0xffFF0000), fontWeight: FontWeight.w400, fontFamily:"Roboto"), validator: idValidator, ), ),
class MyCustomFormState extends State<MyCustomForm>{ final _formKey = GlobalKey<FormState>(); final textValidator = MultiValidator([ RequiredValidator(errorText: '入力必須の項目です。'), MinLengthValidator(8, errorText: '8文字以上で入力してください。'), ]); @override Widget build(BuildContext context){ return Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ TextFormField( validator: textValidator, ), Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), child: ElevatedButton( onPressed:() { if(_formKey.currentState!.validate()){ ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('送信完了')), ); } }, child: const Text('送信'), ) ) ] ) ); } }
class MyCustomFormState extends State<MyCustomForm>{ final _formKey = GlobalKey<FormState>(); @override Widget build(BuildContext context){ return Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ TextFormField( validator: (value){ if(value == null || value.isEmpty){ return 'テキストを入力してください'; } }, ), Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), child: ElevatedButton( onPressed:() { if(_formKey.currentState!.validate()){ ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('送信完了')), ); } }, child: const Text('送信'), ) ) ] ) ); } }
フォームを一意に認識するためのキー
final _formKey = GlobalKey<FormState>();
Form( key: _formKey, )
入力がない場合テキストを返す
if (_formKey.currentState!.validate()) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('送信完了')), ); }