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. 网络图片地址

https://pravatar.cc/

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系统版本

  1. 检查Podfile中# platform :ios, '11.0',如果低于11,需要修改为10或11。
  2. 同时需要点击.workspace进入iOS项目修改target和项目的iOS版本。

1.15.7. 运行flutter项目

因为需要下载firebasesdk,需要长时间等待。

1.15.8. 解决问题

遇到pod install失败问题

  1. 检查命令行是否可以访问外网
  2. 检查cocoapods版本是否最新,当前最新是1.15.2

Cocoapods的版本升级和降级

(Xcode): Undefined symbol: leveldb::WriteBatch::Put(leveldb::Slice const&, leveldb::Slice const&) errors

注释后才可以编译:

// 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

results matching ""

    No results matching ""