1. Finstagram
- 24.8.11 created
 
1.1. 创建项目
localhost:flutter chenchangqing$ flutter create finstagram
Creating project finstagram...
Running "flutter pub get" in finstagram...                          4.5s
Wrote 127 files.
All done!
In order to run your application, type:
  $ cd finstagram
  $ flutter run
Your application code is in finstagram/lib/main.dart.
1.2. 初始化路由
1.2.1. 新建注册页面
新建pages/register_page.dart:
import 'package:flutter/material.dart';
class RegisterPage extends StatefulWidget {
  const RegisterPage({Key? key}) : super(key: key);
  @override
  State<RegisterPage> createState() => _RegisterPageState();
}
class _RegisterPageState extends State<RegisterPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        color: Colors.red,
      ),
    );
  }
}
1.2.2. 新建登录页面
新建pages/login_page.dart:
import 'package:flutter/material.dart';
class LoginPage extends StatefulWidget {
  const LoginPage({Key? key}) : super(key: key);
  @override
  State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        color: Colors.green,
      ),
    );
  }
}
1.2.3. 初始化路由
修改main.dart:
      initialRoute: 'login',
      routes: {
        'register': (context) => RegisterPage(),
        'login': (context) => LoginPage()
      },
1.3. 登录标题/按钮
1.3.1. 新增属性
login_page.dart新增属性:
double? _deviceHeight, _deviceWidth;
修改build方法,初始化_deviceHeight, _deviceWidth:
  Widget build(BuildContext context) {
    _deviceHeight = MediaQuery.of(context).size.height;
    _deviceWidth = MediaQuery.of(context).size.width;
    ...
1.3.2. 新增标题/按钮组件
login_page.dart新增方法:
  Widget _titleWidget() {
    return const Text(
      "Finstagram",
      style: TextStyle(
          color: Colors.black, fontSize: 25, fontWeight: FontWeight.w500),
    );
  }
  Widget _loginButton() {
    return MaterialButton(
      onPressed: () {},
      minWidth: _deviceWidth! * 0.70,
      height: _deviceHeight! * 0.06,
      color: Colors.red,
      child: const Text(
        "Login",
        style: TextStyle(
            color: Colors.white, fontSize: 25, fontWeight: FontWeight.w600),
      ),
    );
  }
修改build方法:
  Container(
    padding: EdgeInsets.symmetric(horizontal: _deviceWidth! * 0.05),
    child: Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        mainAxisSize: MainAxisSize.max,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [_titleWidget(), _loginButton()],
      ),
    ),
  )
1.4. 新增Form输入
1.4.1. 增加属性
login_page.dart增加loginFormKey和_email、_password`属性:
final GlobalKey<FormState> _loginFormKey = GlobalKey<FormState>();
String? _email, _password;
1.4.2. 增加邮箱输入
login_page.dart增加方法_emailTextField:
  Widget _emailTextField() {
    return TextFormField(
      decoration: const InputDecoration(hintText: "Email..."),
      onSaved: (_value) {
        setState(() {
          _email = _value;
        });
      },
      validator: (_value) {
        bool _result = _value!.contains(RegExp(
            r"^[a-zA-Z0-9.!#$%&`*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9](?:[a-zA-Z0-9]{0,61}[a-zA-Z0-9])?)*$"));
        _result ? null : "Please enter a valid email";
      },
    );
  }
1.4.3. 增加密码输入
login_page.dart增加方法_passwordTextField:
  Widget _passwordTextField() {
    return TextFormField(
      obscureText: true,
      decoration: const InputDecoration(hintText: "Password..."),
      onSaved: (_value) {
        setState(() {
          _password = _value;
        });
      },
      validator: (_value) => _value!.length > 6
          ? null
          : "Please enter a password greater than 6 characters.",
    );
  }
1.4.4. 增加Form
login_page.dart增加方法_loginForm:
  Widget _loginForm() {
    return Container(
      height: _deviceHeight! * 0.20,
      child: Form(
        key: _loginFormKey,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          mainAxisSize: MainAxisSize.max,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [_emailTextField(), _passwordTextField()],
        ),
      ),
    );
  }
1.4.5. 修改build
children: [_titleWidget(), _loginForm(), _loginButton()],
1.4.6. 当前UI

1.5. 登录事件
1.5.1. 修正邮箱正则
参考:https: //gist.github.com/cgkio/7268045
      validator: (_value) {
        bool _result = _value!.contains(RegExp(
            r"^[_A-Za-z0-9-+]+(.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(.[A-Za-z0-9]+)*(.[A-Za-z]{2,})$"));
        return _result ? null : "Please enter a valid email";
      }
1.5.2. Form校验
login_page.dart新增_loginUser方法:
  void _loginUser() {
    if (_loginFormKey.currentState!.validate()) {}
  }
login_page.dart修改_loginButton方法:
      onPressed: () {
        _loginUser();
      }
1.6. 注册按钮
1.6.1. 增加注册手势
login_page.dart增加_registerPageLink方法:
  Widget _registerPageLink() {
    return GestureDetector(
      onTap: () => Navigator.pushNamed(context, "register"),
      child: const Text(
        "Don`t have an account?",
        style: TextStyle(
            color: Colors.blue, fontSize: 15, fontWeight: FontWeight.w200),
      ),
    );
  }
1.6.2. 修改build方法
            children: [
              _titleWidget(),
              _loginForm(),
              _loginButton(),
              _registerPageLink()
            ]
1.7. 注册页面标题和按钮
1.7.1. 增加宽高属性
register_page.dart新增属性:
double? _deviceHeight, _deviceWidth;
1.7.2. 注册标题
register_page.dart新增方法:
  Widget _titleWidget() {
    return const Text(
      "Finstagram",
      style: TextStyle(fontSize: 25, fontWeight: FontWeight.w600),
    );
  }
1.7.3. 注册按钮
register_page.dart新增方法:
  Widget _registerButton() {
    return MaterialButton(
      onPressed: () {},
      minWidth: _deviceWidth! * 0.50,
      height: _deviceHeight! * 0.05,
      color: Colors.red,
      child: const Text(
        "Register",
        style: TextStyle(
            color: Colors.white, fontSize: 20, fontWeight: FontWeight.w400),
      ),
    );
  }
1.7.4. build
register_page.dart修改build:
  @override
  Widget build(BuildContext context) {
    _deviceHeight = MediaQuery.of(context).size.height;
    _deviceWidth = MediaQuery.of(context).size.width;
    return Scaffold(
      body: SafeArea(
        child: Container(
          padding: EdgeInsets.symmetric(horizontal: _deviceWidth! * 0.05),
          child: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              mainAxisSize: MainAxisSize.max,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [_titleWidget(), _registerButton()],
            ),
          ),
        ),
      ),
    );
  }
1.8. 注册表单
1.8.1. 新增GlobalKey
register_page.dart新增GlobalKey属性:
final GlobalKey<FormState> _registerFormKey = GlobalKey<FormState>();
1.8.2. 新增name/email/password
register_page.dart新增_name、_email、_password属性:
String? _name, _email, _password;
1.8.3. 增加form
register_page.dart新增form:
  Widget _registrationForm() {
    return Container(
      height: _deviceHeight! * 0.30,
      child: Form(
        key: _registerFormKey,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          mainAxisSize: MainAxisSize.max,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [_nameTextField(), _emailTextField(), _passwordTextField()],
        ),
      ),
    );
  }
  Widget _nameTextField() {
    return TextFormField(
      decoration: const InputDecoration(hintText: "Name..."),
      validator: (_value) => _value!.length > 0 ? null : "Please enter a name.",
      onSaved: (_value) {
        setState(() {
          _name = _value;
        });
      },
    );
  }
  Widget _emailTextField() {
    return TextFormField(
      decoration: const InputDecoration(hintText: "Email..."),
      onSaved: (_value) {
        setState(() {
          _email = _value;
        });
      },
      validator: (_value) {
        bool _result = _value!.contains(RegExp(
            r"^[_A-Za-z0-9-+]+(.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(.[A-Za-z0-9]+)*(.[A-Za-z]{2,})$"));
        return _result ? null : "Please enter a valid email";
      },
    );
  }
  Widget _passwordTextField() {
    return TextFormField(
      obscureText: true,
      decoration: const InputDecoration(hintText: "Password..."),
      onSaved: (_value) {
        setState(() {
          _password = _value;
        });
      },
      validator: (_value) => _value!.length > 6
          ? null
          : "Please enter a password greater than 6 characters.",
    );
  }
1.8.4. 修改build
register_page.dart修改build:
              children: [
                _titleWidget(),
                _registrationForm(),
                _registerButton()
              ]
1.9. 头像选择
1.9.1. 网络图片地址
1.9.2. 引入file_picker
因为这里使用file_picker的时候,无法正常运行iOS模拟器,所以先注释掉
  #file_picker: "6.0.0"
1.9.3. 增加import和_image属性
register_page.dart增加import和_image属性
import 'dart:io';
// import 'package:file_picker/file_picker.dart';
class _RegisterPageState extends State<RegisterPage> {
  ...
  File? _image;
  ...
1.9.4. 增加图片组件
register_page.dart增加_profileImageWidget方法:
  Widget _profileImageWidget() {
    var _imageProvider = _image != null
        ? FileImage(_image!)
        : const NetworkImage("https://i.pravatar.cc/300");
    return GestureDetector(
      onTap: () {
        // FilePicker.platform.pickFiles(type: FileType.image).then((_result) {
        //   setState(() {
        //     _image = File(_result!.files.first.path!);
        //   });
        // });
      },
      child: Container(
        height: _deviceHeight! * 0.15,
        width: _deviceHeight! * 0.15,
        decoration: BoxDecoration(
            image: DecorationImage(
                fit: BoxFit.cover, image: _imageProvider as ImageProvider)),
      ),
    );
  }
1.10. 点击注册
1.10.1. 增加注册方法
register_page.dart增加注册方法:
  void _registerUser() {
    if (_registerFormKey.currentState!.validate() && _image != null) {
      _registerFormKey.currentState!.save();
    }
  }
1.10.2. 增加点击事件
register_page.dart修改_registerButton:
      onPressed: () {
        _registerUser();
      }
1.11. 增加首页
1.11.1. 新增pages/home_page.dart
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);
  @override
  State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Finstagrams"),
        actions: [
          GestureDetector(
            onTap: () {},
            child: const Icon(Icons.add_a_photo),
          ),
          Padding(
            padding: const EdgeInsets.only(left: 8.0, right: 8.0),
            child: GestureDetector(
              onTap: () {},
              child: const Icon(Icons.logout),
            ),
          )
        ],
      ),
    );
  }
}
1.11.2. 修改main.dart
import 'package:finstagram/pages/home_page.dart';
      ...
      initialRoute: 'home',
      routes: {
        'register': (context) => RegisterPage(),
        'login': (context) => LoginPage(),
        'home': (context) => HomePage()
      },
      home: const Scaffold(),
    );
  }
}
1.12. 增加Tabbar
1.12.1. 底部Tabbar
home_page.dart增加_bottomNavigationBar方法:
  Widget _bottomNavigationBar() {
    return BottomNavigationBar(
        currentIndex: _currentPage,
        onTap: (_index) {
          setState(() {
            _currentPage = _index;
          });
        },
        items: const [
          BottomNavigationBarItem(label: 'Feed', icon: Icon(Icons.feed)),
          BottomNavigationBarItem(
              label: 'Profile', icon: Icon(Icons.account_box))
        ]);
  }
1.12.2. 增加属性
home_page.dart增加_currentPage和_pages:
  int _currentPage = 0;
  final List<Widget> _pages = [
    Container(
      color: Colors.green,
    ),
    Container(
      color: Colors.blue,
    )
  ];
1.12.3. 修改build方法
home_page.dart修改build方法:
  Widget build(BuildContext context) {
      ...
      bottomNavigationBar: _bottomNavigationBar(),
      body: _pages[_currentPage],
    );
  }
1.12.4. 当前UI

1.13. 增加FeedPage和ProfilePage
1.13.1. 增加FeedPage
新增pages/feed_page.dart:
import 'package:flutter/material.dart';
class FeedPage extends StatefulWidget {
  const FeedPage({Key? key}) : super(key: key);
  @override
  State<FeedPage> createState() => _FeedPageState();
}
class _FeedPageState extends State<FeedPage> {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.purple,
    );
  }
}
1.13.2. 增加ProfilePage
新增pages/profile_page.dart:
import 'package:flutter/material.dart';
class ProfilePage extends StatefulWidget {
  const ProfilePage({Key? key}) : super(key: key);
  @override
  State<ProfilePage> createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.orange,
    );
  }
}
1.13.3. 修改HomePage
import 'package:finstagram/pages/feed_page.dart';
import 'package:finstagram/pages/profile_page.dart';
...
final List<Widget> _pages = [FeedPage(), ProfilePage()];
...
1.14. 创建firebase项目
1.14.1. 创建firebase项目
打开 https://firebase.com,进入控制台,创建项目。
1.14.2. 依赖firebase
  firebase_core: "1.11.0"
  firebase_auth: "3.3.5"
  firebase_analytics: "9.0.5"
  cloud_firestore: "3.1.6"
  firebase_storage: "10.2.5"
  get_it: "7.2.0"
1.15. 注册iOS应用
1.15.1. 打开iOS注册

1.15.2. 找到iOS bundleId
打开finder:

双击.workspace,等到xcode打开:

复制bundleId:

1.15.3. 填写bundleId

1.15.4. 下载配置文件

1.15.5. 点击下一步
然后,一直点击“下一步”,直到进入控制台。

1.15.6. 修改iOS系统版本
- 检查Podfile中
# platform :ios, '11.0',如果低于11,需要修改为10或11。 - 同时需要点击
.workspace进入iOS项目修改target和项目的iOS版本。 
1.15.7. 运行flutter项目
因为需要下载firebasesdk,需要长时间等待。
1.15.8. 解决问题
遇到pod install失败问题
- 检查命令行是否可以访问外网
 - 检查cocoapods版本是否最新,当前最新是1.15.2
 
注释后才可以编译:
// FIRTransactionOptions *options = [[FIRTransactionOptions alloc] init]; // options.maxAttempts = maxAttempts.integerValue; // // [firestore runTransactionWithOptions:options // block:transactionRunBlock // completion:transactionCompleteBlock];
1.16. 新增FirebaseService
1.16.1. 新建services/firebase_service.dart:
// import 'package:cloud_firestore/cloud_firestore.dart';
// import 'package:firebase_auth/firebase_auth.dart';
// import 'package:firebase_storage/firebase_storage.dart';
class FirebaseService {
  // FirebaseAuth _auth = FirebaseAuth.instance;
  // FirebaseStorage _storage = FirebaseStorage.instance;
  // FirebaseFirestore _db = FirebaseFirestore.instance;
  FirebaseService();
}
由于依赖存在问题,暂时先注释。
1.16.2. 修改main.dart:
import 'package:finstagram/services/firebase_service.dart';
...
// import 'package:firebase_core/firebase_core.dart';
import 'package:get_it/get_it.dart';
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // await Firebase.initializeApp();
  GetIt.instance.registerSingleton<FirebaseService>(FirebaseService());
  runApp(const MyApp());
}
1.17. 登录
1.17.1. 新增FirebaseService
新增services/firebase_service.dart,真实实现一注释,firebase集成有问题。
// import 'package:cloud_firestore/cloud_firestore.dart';
// import 'package:firebase_auth/firebase_auth.dart';
// import 'package:firebase_storage/firebase_storage.dart';
final String USER_COLLECTION = 'users';
class FirebaseService {
  // FirebaseAuth _auth = FirebaseAuth.instance;
  // FirebaseStorage _storage = FirebaseStorage.instance;
  // FirebaseFirestore _db = FirebaseFirestore.instance;
  Map? currentUser;
  FirebaseService();
  // Future<bool> loginUser(
  //     {required String email, required String password}) async {
  //   try {
  //     UserCredential _userCredential = await _auth.signInWithEmailAndPassword(
  //         email: email, password: password);
  //     if (_userCredential.user != null) {
  //       currentUser = await getUserData(uid: _userCredential.user!.uid);
  //       return true;
  //     } else {
  //       return false;
  //     }
  //   } catch (e) {
  //     print(e);
  //     return false;
  //   }
  // }
  // Future<Map> getUserData({required String uid}) async {
  //   DocumentSnapshot _doc =
  //       await _db.collection(USER_COLLECTION).doc(uid).get();
  //   return _doc.data() as Map;
  // }
  Future<bool> loginUser(
      {required String email, required String password}) async {
    return Future.delayed(const Duration(seconds: 1), () {
      return true;
    });
  }
  Future<Map> getUserData({required String uid}) async {
    return Future.delayed(const Duration(seconds: 1), () {
      return {"": ""};
    });
  }
}
1.17.2. 修改login_page.dart,新增import:
import 'package:finstagram/services/firebase_service.dart';
...
import 'package:get_it/get_it.dart';
1.17.3. 修改login_Page.dart,增加_firebaseService属性:
  FirebaseService? _firebaseService;
  ...
  @override
  void initState() {
    super.initState();
    _firebaseService = GetIt.instance.get<FirebaseService>();
  }
1.17.4. 修改login_Page.dart,_loginUser:
  void _loginUser() async {
    if (_loginFormKey.currentState!.validate()) {
      _loginFormKey.currentState!.save();
      bool _result = await _firebaseService!
          .loginUser(email: _email!, password: _password!);
      if (_result) Navigator.popAndPushNamed(context, "home");
    }
  }
1.17.5. 修改main.dart
      initialRoute: 'login',
1.18. 注册
1.18.1. 新增注册方法
firebase_service.dart新增registerUser方法:
// import 'package:path/path.dart' as p;
// Future<bool> registerUser(
//     {required String name,
//     required String email,
//     required String password,
//     required File image}) async {
//   try {
//     UserCredential _userCredential = await _auth
//         .createUserWithEmailAndPassword(email: email, password: password);
//     String _userId = _userCredential.user!.uid;
//     String _fileName = Timestamp.now().millisecondsSinceEpoch.toString() +
//         p.extension(image.path);
//     UploadTask _task =
//         _storage.ref('images/$_userId/$_fileName').putFile(image);
//     return _task.then((_snapshot) async {
//       String _downloadURL = await _snapshot.ref.getDownloadURL();
//       await _db
//           .collection(USER_COLLECTION)
//           .doc(_userId)
//           .set({"name": name, "email": email, "image": _downloadURL});
//     });
//   } catch (e) {
//     print(e);
//     return false;
//   }
// }
  Future<bool> registerUser(
      {required String name,
      required String email,
      required String password}) async {
    return Future.delayed(const Duration(seconds: 1), () {
      return true;
    });
  }
1.18.2. 增加FirebaseService属性
register_page.dart新增_firebaseService:
import 'package:finstagram/services/firebase_service.dart';
...
import 'package:get_it/get_it.dart';
  FirebaseService? _firebaseService;
  @override
  void initState() {
    super.initState();
    _firebaseService = GetIt.instance.get<FirebaseService>();
  }
register_page.dart修改_registerUser:
  void _registerUser() async {
    // if (_registerFormKey.currentState!.validate() && _image != null) {
    if (_registerFormKey.currentState!.validate()) {
      // 图片选择暂时忽略
      _registerFormKey.currentState!.save();
      var _result = await _firebaseService!
          .registerUser(name: _name!, email: _email!, password: _password!);
      if (_result) Navigator.pop(context);
    }
  }
1.19. 发布图片
1.19.1. 增加上传图片方法
修改firebase_service.dart,新增postImage方法:
import 'dart:io';
...
final String POSTS_COLLECTION = 'posts';
...
// Future<bool> postImage(File _image) async {
//   try {
//     String _userId = _auth.currentUser!.uid;
//     String _fileName = Timestamp.now().millisecondsSinceEpoch.toString() +
//         p.extension(_image.path);
//     UploadTask _task =
//         _storage.ref('images/$_userId/$_fileName').putFile(_image);
//     return _task.then((_snapshot) async {
//       String _downloadURL = await _snapshot.ref.getDownloadURL();
//       await _db.collection(POSTS_COLLECTION).add({
//         "useId": _userId,
//         "timestamp": Timestamp.now(),
//         "image": _downloadURL
//       });
//       return true;
//     });
//   } catch (e) {
//     print(e);
//     return false;
//   }
// }
  Future<bool> postImage(File _image) async {
    return Future.delayed(const Duration(seconds: 1), () {
      return true;
    });
  }
1.19.2. 增加FirebaseService属性
修改home_page.dart增加_firebaseService属性:
// import 'package:file_picker/file_picker.dart';
...
import 'package:finstagram/services/firebase_service.dart';
...
import 'package:get_it/get_it.dart';
  FirebaseService? _firebaseService;
  @override
  void initState() {
    super.initState();
    _firebaseService = GetIt.instance.get<FirebaseService>();
  }
1.19.3. 调用发布图片
修改home_page.dart新增_postImage:
  // void _postImage() async {
  //   FilePickerResult? _result =
  //       await FilePicker.platform.pickFiles(type: FileType.image);
  //   File _image = File(_result!.files.first.path!);
  //   await _firebaseService!.postImage(_image);
  // }
  void _postImage() async {}
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Finstagrams"),
        actions: [
          GestureDetector(
            onTap: () {
              _postImage();// add
            },
            ...
  }
1.20. 照片流
1.20.1. 查询照片流
修改firebase_service.dart,新增getLastestPosts方法:
  // Stream<QuerySnapshot> getLastestPosts() {
  //   return _db
  //       .collection(POSTS_COLLECTION)
  //       .orderBy('timestamp', descending: true)
  //       .snapshots();
  // }
  Stream<List<String>> getLastestPosts() {
    // https://blog.csdn.net/mqdxiaoxiao/article/details/102570225
    return Stream<List<String>>.fromFutures([
      Future.delayed(Duration(seconds: 1), () {
        return [
          "https://marketplace.canva.cn/EAGE6DsWb24/1/0/1600w/canva-cFjPThAyvu8.jpg"
        ];
      })
    ]);
  }
1.20.2. 显示照片流
修改feed_page.dart:
// import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:finstagram/services/firebase_service.dart';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
class FeedPage extends StatefulWidget {
  const FeedPage({Key? key}) : super(key: key);
  @override
  State<FeedPage> createState() => _FeedPageState();
}
class _FeedPageState extends State<FeedPage> {
  double? _deviceHeight, _deviceWidth;
  FirebaseService? _firebaseService;
  @override
  void initState() {
    super.initState();
    _firebaseService = GetIt.instance.get<FirebaseService>();
  }
  @override
  Widget build(BuildContext context) {
    _deviceHeight = MediaQuery.of(context).size.height;
    _deviceWidth = MediaQuery.of(context).size.width;
    return Container(
      height: _deviceHeight!,
      width: _deviceWidth!,
      child: _postsListView(),
    );
  }
  // Widget _postsListView() {
  //   return StreamBuilder<QuerySnapshot>(
  //     stream: _firebaseService!.getLastestPosts(),
  //     builder: (BuildContext _context, AsyncSnapshot _snapshot) {
  //       if (_snapshot.hasData) {
  //         List _posts = _snapshot.data!.docs.map((e) => e.data()).toList();
  //         print(_posts);
  //         return ListView.builder(
  //             itemCount: _posts.length,
  //             itemBuilder: (BuildContext context, int index) {
  //               Map _post = _posts[index];
  //               return Container(
  //                 height: _deviceHeight! * 0.30,
  //                 margin: EdgeInsets.symmetric(
  //                     vertical: _deviceHeight! * 0.01,
  //                     horizontal: _deviceWidth! * 0.05),
  //                 decoration: BoxDecoration(
  //                     image: DecorationImage(
  //                         fit: BoxFit.cover,
  //                         image: NetworkImage(_post["image"]))),
  //               );
  //             });
  //       } else {
  //         return const Center(
  //           child: CircularProgressIndicator(),
  //         );
  //       }
  //     },
  //   );
  // }
  Widget _postsListView() {
    return StreamBuilder<List<String>>(
      stream: _firebaseService!.getLastestPosts(),
      builder: (BuildContext _context, AsyncSnapshot _snapshot) {
        if (_snapshot.hasData) {
          print(_snapshot.data);
          List<String> _posts = _snapshot.data!;
          print(_posts);
          return ListView.builder(
              itemCount: _posts.length,
              itemBuilder: (BuildContext context, int index) {
                return Container(
                  height: _deviceHeight! * 0.30,
                  margin: EdgeInsets.symmetric(
                      vertical: _deviceHeight! * 0.01,
                      horizontal: _deviceWidth! * 0.05),
                  decoration: BoxDecoration(
                      image: DecorationImage(
                          fit: BoxFit.cover,
                          image: NetworkImage(_posts[index]))),
                );
              });
        } else {
          return const Center(
            child: CircularProgressIndicator(),
          );
        }
      },
    );
  }
}
1.21. 显示头像
1.21.1. 修改firebase_service.dart,头像写死下
  // Map? currentUser
  Map? currentUser = {
    "image":
        "https://marketplace.canva.cn/EAGE6DsWb24/1/0/1600w/canva-cFjPThAyvu8.jpg"
  };
1.21.2. 修改profile_page.dart:
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import '../services/firebase_service.dart';
class ProfilePage extends StatefulWidget {
  const ProfilePage({Key? key}) : super(key: key);
  @override
  State<ProfilePage> createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
  double? _deviceHeight, _deviceWidth;
  FirebaseService? _firebaseService;
  @override
  void initState() {
    super.initState();
    _firebaseService = GetIt.instance.get<FirebaseService>();
  }
  @override
  Widget build(BuildContext context) {
    _deviceHeight = MediaQuery.of(context).size.height;
    _deviceWidth = MediaQuery.of(context).size.width;
    return Container(
      padding: EdgeInsets.symmetric(
          horizontal: _deviceWidth! * 0.05, vertical: _deviceHeight! * 0.02),
      child: Column(
        mainAxisSize: MainAxisSize.max,
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [_profileImage()],
      ),
    );
  }
  Widget _profileImage() {
    return Container(
      margin: EdgeInsets.only(bottom: _deviceHeight! * 0.02),
      height: _deviceHeight! * 0.15,
      width: _deviceHeight! * 0.15,
      decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(100),
          image: DecorationImage(
              fit: BoxFit.cover,
              image: NetworkImage(_firebaseService!.currentUser!["image"]))),
    );
  }
}
1.22. 自己发布的照片
1.22.1. 查询用户发布的照片
修改firebase_service.dart
  // Stream<QuerySnapshot> getPostsForUser() {
  //   String _userID = _auth.currentUser!.uid;
  //   return _db
  //       .collection(POSTS_COLLECTION)
  //       .where('userId', isEqualTo: _userID)
  //       .snapshots();
  // }
  Stream<List<String>> getPostsForUser() {
    return Stream<List<String>>.fromFutures([
      Future.delayed(Duration(seconds: 1), () {
        return [
          "https://marketplace.canva.cn/EAGE6DsWb24/1/0/1600w/canva-cFjPThAyvu8.jpg",
          "https://marketplace.canva.cn/EAGE6DsWb24/1/0/1600w/canva-cFjPThAyvu8.jpg",
          "https://marketplace.canva.cn/EAGE6DsWb24/1/0/1600w/canva-cFjPThAyvu8.jpg",
          "https://marketplace.canva.cn/EAGE6DsWb24/1/0/1600w/canva-cFjPThAyvu8.jpg",
          "https://marketplace.canva.cn/EAGE6DsWb24/1/0/1600w/canva-cFjPThAyvu8.jpg"
        ];
      })
    ]);
  }
1.22.2. 显示用户发布的照片
修改profile_page.dart:
  Widget build(BuildContext context) {
    ...
        children: [_profileImage(), _postsGridView()],
  // Widget _postsGridView() {
  //   return Expanded(
  //       child: StreamBuilder<QuerySnapshot>(
  //     stream: _firebaseService!.getPostsForUser(),
  //     builder: (context, snapshot) {
  //       if (snapshot.hasData) {
  //         List _posts = snapshot.data!.docs.map((e) => e.data()).toList();
  //         return GridView.builder(
  //             gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
  //                 crossAxisCount: 2, mainAxisSpacing: 2, crossAxisSpacing: 2),
  //             itemCount: _posts.length,
  //             itemBuilder: (context, index) {
  //               Map _post = _posts[index];
  //               return Container(
  //                 decoration: BoxDecoration(
  //                     image: DecorationImage(
  //                         fit: BoxFit.cover,
  //                         image: NetworkImage(_post["image"]))),
  //               );
  //             });
  //       } else {
  //         return const Center(
  //           child: CircularProgressIndicator(),
  //         );
  //       }
  //     },
  //   ));
  // }
  Widget _postsGridView() {
    return Expanded(
        child: StreamBuilder<List<String>>(
      stream: _firebaseService!.getPostsForUser(),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          List _posts = snapshot.data!;
          return GridView.builder(
              gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: 2, mainAxisSpacing: 2, crossAxisSpacing: 2),
              itemCount: _posts.length,
              itemBuilder: (context, index) {
                return Container(
                  decoration: BoxDecoration(
                      image: DecorationImage(
                          fit: BoxFit.cover,
                          image: NetworkImage(_posts[index]))),
                );
              });
        } else {
          return const Center(
            child: CircularProgressIndicator(),
          );
        }
      },
    ));
  }
1.23. 登出
1.23.1. 增加登出方法
修改firebase_service.dart,增加logout:
  // Future<void> logout() async {
  //   await _auth.signOut();
  // }
  Future<void> logout() async {
    return Future.delayed(const Duration(seconds: 1), () {});
  }
1.23.2. 调用登出方法
修改home_page.dart:
  Widget build(BuildContext context) {
    ...
              onTap: () async {
                await _firebaseService!.logout();
                Navigator.popAndPushNamed(context, 'login');
              }
  }
1.24. 源码
https://gitee.com/learnany/flutter/blob/master/finstagram.zip