Недавно я создал приложение в стиле чата, похожее на WhatsApp, чтобы понять, как я могу использовать Google Firebase, для которого я использовал Android Studio. Для этого я сначала объявил довольно много вещей в своем файле pubspe c .yaml как зависимости, например:
dependencies:
firebase_core: ^0.4.2+1
firebase_auth: ^0.15.1
cloud_firestore: ^0.12.11
В самом приложении я сделал несколько вещей, включая создание файл registration_screen.dart, позволяющий пользователю зарегистрировать учетную запись. Код для него выглядел примерно так:
import 'package:flash_chat/constants.dart';
import 'package:flutter/material.dart';
import 'package:flash_chat/components/rounded_button.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'chat_screen.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
class RegistrationScreen extends StatefulWidget {
static String id = 'registration_screen';
@override
_RegistrationScreenState createState() => _RegistrationScreenState();
}
class _RegistrationScreenState extends State<RegistrationScreen> {
final _auth = FirebaseAuth.instance;
bool showSpinner = false;
String email;
String password;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: ModalProgressHUD(
inAsyncCall: showSpinner,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Flexible(
child: Hero(
tag: 'logo',
child: Container(
height: 200.0,
child: Image.asset('images/logo.png'),
),
),
),
SizedBox(
height: 48.0,
),
TextField(
keyboardType: TextInputType.emailAddress,
textAlign: TextAlign.center,
onChanged: (value) {
email = value;
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Enter your email',
),
),
SizedBox(
height: 8.0,
),
TextField(
obscureText: true,
textAlign: TextAlign.center,
onChanged: (value) {
password = value;
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Enter your password',
),
),
SizedBox(
height: 24.0,
),
RoundedButton(
title: 'Register',
color: Colors.blueAccent,
onPressed: () async {
setState(() {
showSpinner = true;
});
try {
final newUser = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
if (newUser != null) {
Navigator.pushNamed(context, ChatScreen.id);
}
setState(() {
showSpinner = false;
});
} catch (e) {
print(e);
}
},
),
],
),
),
),
);
}
}
Экран входа в систему был очень похож на это. Для реального экрана чата я построил код, который будет выглядеть следующим образом:
import 'package:flutter/material.dart';
import 'package:flash_chat/constants.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
final _firestore = Firestore.instance;
FirebaseUser loggedInUser;
class ChatScreen extends StatefulWidget {
static String id = 'chat_screen';
@override
_ChatScreenState createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
final messageTextController = TextEditingController();
final _auth = FirebaseAuth.instance;
String messageText;
@override
void initState() {
super.initState();
getCurrentUser();
}
void getCurrentUser() async {
try {
final user = await _auth.currentUser();
if (user != null) {
loggedInUser = user;
}
} catch (e) {
print(e);
}
}
void messagesStream() async {
await for (var snapshot in _firestore.collection('messages').snapshots()) {
for (var message in snapshot.documents) {
print(message.data);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: null,
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () {
_auth.signOut();
Navigator.pop(context);
}),
],
title: Text('⚡️Chat'),
backgroundColor: Colors.lightBlueAccent,
),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
MessagesStream(),
Container(
decoration: kMessageContainerDecoration,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextField(
controller: messageTextController,
onChanged: (value) {
messageText = value;
},
decoration: kMessageTextFieldDecoration,
),
),
FlatButton(
onPressed: () {
messageTextController.clear();
//messageText + loggedInUser.email
_firestore.collection('messages').add({
'text': messageText,
'sender': loggedInUser.email,
});
},
child: Text(
'Send',
style: kSendButtonTextStyle,
),
),
],
),
),
],
),
),
);
}
}
class MessagesStream extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('messages').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent,
),
);
}
final messages = snapshot.data.documents.reversed;
List<MessageBubble> messageBubbles = [];
for (var message in messages) {
final messageText = message.data['text'];
final messageSender = message.data['sender'];
final currentUser = loggedInUser.email;
if (currentUser == messageSender) {
//The message from the logged in user
}
final messageBubble = MessageBubble(
sender: messageSender,
text: messageText,
isMe: currentUser == messageSender,
);
messageBubbles.add(messageBubble);
}
return Expanded(
child: ListView(
reverse: true,
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
children: messageBubbles,
),
);
},
);
}
}
class MessageBubble extends StatelessWidget {
MessageBubble({this.sender, this.text, this.isMe});
final String sender;
final String text;
final bool isMe;
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment:
isMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: <Widget>[
Text(
sender,
style: TextStyle(fontSize: 12.0, color: Colors.black54),
),
Material(
borderRadius: isMe
? BorderRadius.only(
topLeft: Radius.circular(30.0),
bottomLeft: Radius.circular(30.0),
bottomRight: Radius.circular(30.0),
)
: BorderRadius.only(
bottomLeft: Radius.circular(30.0),
bottomRight: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
elevation: 5.0,
color: isMe ? Colors.lightBlueAccent : Colors.white,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
child: Text(
'$text',
style: TextStyle(
color: isMe ? Colors.white : Colors.black54,
fontSize: 15.0,
),
),
),
),
],
),
);
}
}
Я попытался как можно реорганизовать свой код, чтобы убедиться, что он не будет слишком запутанным - то есть повторяющиеся виджеты или функции были сохранены в отдельном файле, чтобы уменьшить общий объем кода.
Мне очень хотелось бы помочь, как продвинуться дальше, включить пользовательский контент c, а не просто чат. Сообщения. Приложения Spotify и YouTube были бы хорошим примером, но кое-что еще лучше было бы приложением Anytime Fitness (Великобритания):
https://play.google.com/store/apps/details?id=com.anytimefitness.app&hl=en_GB
По сути, я хочу быть в состоянии расширить функциональность этого приложения, чтобы позволить мне показывать пользовательский контент c, такой как видео, статьи / текст и сообщения / уведомления и т. д. c. В конечном счете, владелец приложения должен иметь возможность добавлять контент, назначенный каждой указанной c учетной записи пользователя, чтобы при входе пользователя в систему (через Firebase) он видел весь свой уникальный контент, а никто другой.
Как бы я go о добавлении этой функции? Будет ли это случай, когда владелец загружает контент в Firebase и пользователь получает доступ к нему через свои учетные записи, или владелец может получить доступ к «основной» версии приложения на своем телефоне и загружать видео таким образом. Некоторые функции загрузки и хранения также были бы идеальными.
Я бы очень признателен за ваши мысли. Как вы можете видеть, у меня есть базовое c понимание того, как использовать Firebase и как привязать каждую отдельную учетную запись пользователя к своим собственным сообщениям в базе данных. Однако я не уверен, как расширить эту функциональность для доступа к видео / аудио и уведомлению / текстовому контенту. Спасибо!