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('送信完了')),
);
}