iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 27
1
Mobile Development

Flutter---Google推出的跨平台框架,Android、iOS一起搞定系列 第 27

【Flutter基礎概念與實作】 Day27–在留言取得並顯示使用者的照片

今天就把上傳大頭貼到Firebase Storage和在留言顯示使用者照片的功能完成吧。

Home Page

開啟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);
}

Comment Widget

開啟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


上一篇
【Flutter基礎概念與實作】 Day26–上傳圖片到Firebase Storage
下一篇
【Flutter基礎概念與實作】 Day28–使用FCM發送通知給使用者
系列文
Flutter---Google推出的跨平台框架,Android、iOS一起搞定30

尚未有邦友留言

立即登入留言