開啟home_page.dart,把上傳照片的功能放在Drawer。
引入以下檔案:
import '../firebase/upload_storage.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
import '../firebase/firestore_database.dart';
接著把原本的Side Drawer程式碼修改成以下:
class SideDrawer extends StatelessWidget {
  final String email;
  String imagePath;
  SideDrawer({Key key, this.email}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: MediaQuery.of(context).size.width * 0.55,
      child: Drawer(
        child: ListView(
          children: <Widget>[
            UserAccountsDrawerHeader(
              currentAccountPicture: FutureBuilder<String>(
                future: getProfilePictureUrl(email),
                builder: (context, snapshot) {
                  switch (snapshot.connectionState) {
                    case ConnectionState.none:
                    case ConnectionState.active:
                    case ConnectionState.waiting:
                      return Center(child: CircularProgressIndicator());
                      break;
                    case ConnectionState.done:
                      if(snapshot.data != null)
                        return Image.network(snapshot.data);
                      return Container();
                  }
                  return null;
                },
              ),
              accountEmail: Text(email),
              accountName: Text(''),
              decoration: BoxDecoration(color: Colors.brown),
            ),
            ListTile(
              leading: Icon(Icons.file_upload),
              title: Text('Profile picture'),
              onTap: () async {
                File image =
                    await ImagePicker.pickImage(source: ImageSource.gallery);
                if (image != null) {
                  var uploadTask = uploadImage(image, email);
                  await uploadTask.onComplete;
                  String url =
                      await uploadTask.lastSnapshot.ref.getDownloadURL();
                  updateProfilePictureUrl(email, url);
                }
              },
            ),
            ListTile(
              leading: Icon(Icons.sentiment_satisfied),
              title: Text('Rate Our App'),
              onTap: () {
                Navigator.of(context).pop();
                _asyncScoreDialog(context);
              },
            ),
            ListTile(
              leading: Icon(Icons.exit_to_app),
              title: Text("Log out"),
              onTap: () {
                BlocProvider.of<AuthenticationBloc>(context)
                    .dispatch(LoggedOut());
              },
            ),
            ListTile(
              leading: Icon(Icons.info),
              title: Text("About"),
              onTap: () {
                SnackBar snackbar = SnackBar(
                  content:
                      Text('FlutTube是第十一屆iT邦幫忙鐵人賽的實作專案\n其中使用的電影資料由TMDb所提供'),
                  duration: Duration(seconds: 5),
                );
                Scaffold.of(context).showSnackBar(snackbar);
                Navigator.of(context).pop();
              },
            )
          ],
        ),
      ),
    );
  }
}
由於getProfilePictureUrl()回傳的是Future<String>,所以currentAccountPicture這邊用FutureBuilder取得處理的狀態,當資料處理完畢後就回傳Image Widget顯示圖片。
如果沒有回傳資料(snapshot.data is null),就放一個空白的container。
當使用者點擊Upload的選項後,先用ImagePicker讓他從自己的圖片庫選取要上傳的照片。
選好照片後使用uploadImagefunction上傳到Firebase Storage,接著等圖片上傳完成後取得下載連結,最後再存到Firestore裡。
File image = await ImagePicker.pickImage(source: ImageSource.gallery);
if (image != null) {
    var uploadTask = uploadImage(image, email);
    await uploadTask.onComplete;
    String url = await uploadTask.lastSnapshot.ref.getDownloadURL();
    updateProfilePictureUrl(email, url);
}
開啟home資料夾下的「comment_widget.dart」。
處理完上傳大頭貼的功能,接下來就是在每則使用者留言顯示他的大頭貼。
import 'package:flutter/material.dart';
import 'package:timeago/timeago.dart' as timeago;
import '../firebase/firestore_database.dart';
Widget commentWidget(String email, String content, var time) {
  return Container(
      padding: EdgeInsets.symmetric(vertical: 5),
      decoration: BoxDecoration(
          border: Border(
              top: BorderSide(
        color: Colors.black,
        width: 3.0,
      ))),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Container(
            height: 40,
            width: 40,
            child: FutureBuilder<String>(
              future: getProfilePictureUrl(email),
              builder: (context, snapshot) {
                switch (snapshot.connectionState) {
                  case ConnectionState.none:
                  case ConnectionState.active:
                  case ConnectionState.waiting:
                    return Center(child: CircularProgressIndicator());
                    break;
                  case ConnectionState.done:
                    if (snapshot.data.isEmpty)
                      return Image.asset(
                        'assets/no.jpg',
                        fit: BoxFit.fill,
                      );
                    return Image.network(
                      snapshot.data,
                      fit: BoxFit.fill,
                    );
                }
                return null;
              },
            ),
          ),
          SizedBox(
            width: 5,
          ),
          Column(
            mainAxisAlignment: MainAxisAlignment.start,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Row(
                mainAxisAlignment: MainAxisAlignment.start,
                children: <Widget>[
                  Text(
                    email,
                    style: TextStyle(
                        fontSize: 16,
                        color: Colors.lightBlueAccent,
                        fontWeight: FontWeight.bold),
                  ),
                  SizedBox(
                    width: 10,
                  ),
                  Text(
                    timeago.format(time.toDate()),
                    style: TextStyle(
                      fontSize: 8,
                      color: Colors.grey,
                    ),
                  ),
                ],
              ),
              SizedBox(
                height: 5.0,
              ),
              ConstrainedBox(
                constraints: BoxConstraints(maxWidth: 300, maxHeight: 1000),
                child: Container(
                  child: Text(
                    content,
                    style: TextStyle(
                      fontSize: 14,
                    ),
                  ),
                ),
              ),
            ],
          ),
        ],
      ));
}
這裡一樣使用FutureBuilder去監聽Future處理的狀態,為了讓每個人的圖片大小都一樣,所以用Container包裹住並設定圖片採用BoxFit.fill的方式填滿。

加上大頭貼後的留言果然像樣多了,我想FlutTube這個App的功能都做得差不多了,不過既然離完賽還有3天,明天就繼續來介紹Firebase中我很喜歡的一個功能「Cloud Messaging」,之後就可以隨時傳遞通知給App的使用者。
完整程式碼在這裡-> FlutTube Github