1

初心者向けに説明してください;-)。

目標: WhatsApp 経由で画像を送信すると、チャットに直接表示されます (WhatsApp はアップロードを「待機」しません)。同じ効果が欲しい。

私の問題は、イメージがイメージピッカーを介して選択され、チャットに表示されるまで遅延があることです。これは、Streambuilder -> ListView.builder がデータベースに書き込まれている場合にのみ表示されるためです)。

現在、次の手順があります。

  1. イメージピッカー
  2. 画像ファイルは圧縮されてアップロードされます (非同期、待機…)
  3. 画像は Firebase に保存されます
  4. ファイルの URL が受信され、_handleSubmitted を介してメッセージのフィールドとして Firestore データベースに書き込まれます。
  5. Streambuilder -> Listview.builder は、 (document["imageUrl"])経由でスナップショットとして受信したすべてのメッセージ (CachedNetworkImage 経由の画像) を表示します

私の考え:まず、Listview.builder 内の imagepicker からローカル イメージを表示し、それをネットワーク イメージに置き換えます (スムーズな移行)。

しかし、ちょうど 3 週間前にプログラミングを始めたばかりなので、それを行う方法も、Listview.Builder 内でリスト項目を操作する方法もわかりません。

//Chat screen which lists all the chat messages, including _handleSubmitted and the _buildTextComposer

import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:intl/intl.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter_native_image/flutter_native_image.dart';
import 'package:first_app/image_large.dart';

final database = Firestore.instance
    .collection('nachrichten')
    .document('G5xlQHvb56ZqpWs7ojUV');
final reference = FirebaseDatabase.instance.reference().child('messages');

class ChatScreen extends StatefulWidget {
  @override
  State createState() => new ChatScreenState();
}

class ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
  final TextEditingController _textController = new TextEditingController();
  final ScrollController _scrollController = new ScrollController();

  bool _isComposing = false;
  bool isLoading;
  String imageUrl;
  File imageFile;

  //optional from other code
  @override
  void initState() {
    super.initState();
    imageUrl = '';
  }

  Future getImage() async {
    imageFile = await ImagePicker.pickImage(source: ImageSource.camera);

    if (imageFile != null) {
      setState(() {
        isLoading = true;
      });
      uploadFile();
    }
  }

  Future uploadFile() async {
    //file compression
    File compressedFile = await FlutterNativeImage.compressImage(imageFile.path,
        quality: 50, percentage: 50);
    String fileName = DateTime.now().millisecondsSinceEpoch.toString();
    StorageReference reference = FirebaseStorage.instance.ref().child(fileName);
    StorageUploadTask uploadTask = reference.putFile(compressedFile);
    StorageTaskSnapshot storageTaskSnapshot = await uploadTask.onComplete;
    storageTaskSnapshot.ref.getDownloadURL().then((downloadUrl) {
      imageUrl = downloadUrl;
      setState(() {
        isLoading = false;
        _handleSubmitted(imageUrl: imageUrl);
      });
    }, onError: (err) {
      setState(() {
        isLoading = false;
      });
      Fluttertoast.showToast(msg: 'This file is not an image');
    });
  }

  //Builds the button text composer, including camera icon, text input and send button
  Widget _buildTextComposer() {
    return new IconTheme(
      data: new IconThemeData(color: Theme.of(context).accentColor),
      child: new Container(
          margin: const EdgeInsets.symmetric(horizontal: 0.80),
          child: new Row(children: <Widget>[
            new Container(
              margin: new EdgeInsets.symmetric(horizontal: 0.4),
              child: new IconButton(
                icon: new Icon(Icons.photo_camera),
                onPressed: getImage,
              ),
            ),
            new Flexible(
              child: Container(
                margin: const EdgeInsets.symmetric(vertical: 10.0),
                padding: EdgeInsets.all(10.0),
                decoration: new BoxDecoration(
                  border: Border.all(color: Colors.grey.shade200),
                  borderRadius: new BorderRadius.circular(20.0),
                ),

                //container with constraint limits the maximum height of the text input field
                child: new Container(
                  constraints: BoxConstraints.loose(Size.fromHeight(100.0)),
                  child: new TextField(
                    maxLines: null,
                    keyboardType: TextInputType.multiline,
                    controller: _textController,
                    onChanged: (String text) {
                      setState(() {
                        _isComposing = text.length > 0;
                      });
                    },
//                    onSubmitted: _handleSubmitted,
                    decoration: new InputDecoration.collapsed(
                        hintText: "Nachricht schreiben..."),
                  ),
                ),
              ),
            ),
            new Container(
                margin: new EdgeInsets.symmetric(horizontal: 0.4),
                child: Theme.of(context).platform == TargetPlatform.iOS
                    ? new CupertinoButton(
                        child: new Text("Send"),
                        onPressed: _isComposing
                            ? () => _handleSubmitted(text: _textController.text)
                            : null,
                      )
                    : new IconButton(
                        icon: new Icon(Icons.send),
                        onPressed: _isComposing
                            ? () => _handleSubmitted(text: _textController.text)
                            : null,
                      )),
          ]),
          decoration: Theme.of(context).platform == TargetPlatform.iOS
              ? new BoxDecoration(
                  border:
                      new Border(top: new BorderSide(color: Colors.grey[200])))
              : null),
    );
  }

  //Builds the actual chat screen with Scaffold
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
          title: new Text("Chat.here Gruppenchat"),
          centerTitle: true,
          elevation:
              Theme.of(context).platform == TargetPlatform.iOS ? 0.0 : 4.0),
      body: StreamBuilder<QuerySnapshot>(
          stream: Firestore.instance
              .collection('nachrichten')
              .orderBy('timestamp', descending: true)
              //  .limit(20)
              .snapshots(),
          builder:
              (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
            if (!snapshot.hasData) return Text('Loading data');
            final int documentsLength = snapshot.data.documents.length;
            return Container(
                child: Column(
                  children: <Widget>[
                    new Flexible(
                        child: ListView.builder(
                      controller: _scrollController,
                      reverse: true,
                      itemCount: documentsLength,
                      itemBuilder: (context, int index) {
                        final DocumentSnapshot document =
                            snapshot.data.documents[index];
                        return new Container(
                          margin: const EdgeInsets.symmetric(
                              horizontal: 10.0, vertical: 10.0),
                          child: new Row(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: <Widget>[
                              new Container(
                                margin: const EdgeInsets.only(right: 16.0),
                                child: new CircleAvatar(
                                    child: new Text(
                                        document['author'].substring(0, 1))),
                              ),
                              new Expanded(
                                child: new Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: <Widget>[
                                    new Row(
                                      children: <Widget>[
                                        new Text(document['author'],
                                            style: TextStyle(
                                                fontSize: 12.0,
                                                color: Colors.black45,
                                                fontWeight: FontWeight.bold)),
                                        new Text(
                                            ' ' +
                                                DateFormat("MMM. d. '|' HH:mm")
                                                    .format(
                                                        document['timestamp']),
                                            style: TextStyle(
                                                fontSize: 12.0,
                                                color: Colors.black45))
                                      ],
                                    ),

                                    (document['text'] == null)
                                        ? new GestureDetector(
                                            onTap: () {
                                              Navigator.push(
                                                context,
                                                MaterialPageRoute(
                                                    builder: (context) =>
                                                        SecondScreen(
                                                            imageUrl: document[
                                                                'imageUrl'])),
                                              );
                                            },
                                            child: new Container(
                                              child: new ClipRRect(
                                                borderRadius:
                                                    new BorderRadius.circular(
                                                        7.0),
                                                child: new CachedNetworkImage(
                                                  imageUrl:
                                                      document['imageUrl'],
                                                  placeholder: Container(
                                                    child:
                                                        CircularProgressIndicator(
                                                      valueColor:
                                                          AlwaysStoppedAnimation<
                                                                  Color>(
                                                              Colors.orange),
                                                    ),
                                                    width: 200.0,
                                                    height: 200.0,
                                                    padding:
                                                        EdgeInsets.all(70.0),
                                                    decoration: BoxDecoration(
                                                      borderRadius:
                                                          BorderRadius.all(
                                                        Radius.circular(8.0),
                                                      ),
                                                    ),
                                                  ),
                                                ),
                                              ),
                                              margin:
                                                  EdgeInsets.only(right: 50.0),
                                            ))
                                        : new Card(
                                            margin:
                                                EdgeInsets.only(right: 50.0),
                                            //green color for messages of yourself
                                            color:
                                                document['author'] == "Matthias"
                                                    ? Color.fromRGBO(
                                                        220, 255, 202, 1.0)
                                                    : null,
                                            child: new Container(
                                                padding: EdgeInsets.all(6.0),
                                                child: new Text(
                                                  document['text'],
                                                  style:
                                                      TextStyle(fontSize: 15.0),
                                                )),
                                            shape: RoundedRectangleBorder(
                                                borderRadius:
                                                    BorderRadius.circular(7.0)),
                                          ),

                                    //Container( child: image != null ? new Image.file(image, width: 250.0) : new Text("Kein Bild"))
                                  ],
                                ),
                              ),
                            ],
                          ),
                        );
                      },
                    )),
                    new Divider(height: 1.0),
                    new Container(
                      decoration:
                          new BoxDecoration(color: Theme.of(context).cardColor),
                      child: _buildTextComposer(),
                    ),
                  ],
                ),
                decoration: Theme.of(context).platform == TargetPlatform.iOS
                    ? new BoxDecoration(
                        border: new Border(
                            top: new BorderSide(color: Colors.grey[200])))
                    : null);
          }),
    );
  }

  void _handleSubmitted({String text, String imageUrl}) {
    _textController.clear();
    setState(() {
      _isComposing = false;
    });

    //creation of an own document in Firestore
    Firestore.instance.runTransaction((Transaction transaction) async {
      CollectionReference reference =
          Firestore.instance.collection('nachrichten');

      await reference.add({
        "text": text,
        "author": "Matthias",
        "imageUrl": imageUrl,
        "timestamp": DateTime.now(),
      });
    });

    _scrollController.animateTo(
      0.0,
      curve: Curves.easeOut,
      duration: const Duration(milliseconds: 300),
    );
  }
}
4

1 に答える 1