Merge pull request #656 from GetStream/release/2.2.1

chore(llc,core,ui): update changelog and pubspecs
This commit is contained in:
Salvatore Giordano
2021-09-01 12:20:58 +02:00
committed by GitHub
25 changed files with 708 additions and 16 deletions
+1 -1
View File
@@ -37,7 +37,7 @@ jobs:
"llc": "packages/stream_chat",
"ui": "packages/stream_chat_flutter",
"core": "packages/stream_chat_flutter_core",
"localization": "packages/stream_chat_flutter_localizations",
"localization": "packages/stream_chat_localizations",
"persistence": "packages/stream_chat_persistence"
}
env:
Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

@@ -187,8 +187,33 @@ StreamChat(
As you can see we generate a local notification whenever a message.new or notification.message_new event is received.
### Foreground notifications
Sometimes you may want to show a notification when the app is in the foreground.
For example, when you're in a channel and you receive a new message from someone in another channel.
For this scenario, you can also use the `flutter_local_notifications` package to show a notification.
You need to listen for new events using `StreamChatClient.on` and handle them accordingly.
Here we're checking if the event is a `message.new` or `notification.message_new` event, and if the message is from a different user than the current user. In that case we'll show a notification.
```dart
client.on(
EventType.messageNew,
EventType.notificationMessageNew,
).listen((event) {
if (event.message?.user?.id == client.state.currentUser?.id) {
return;
}
showLocalNotification(event, client.state.currentUser!.id, context);
});
```
:::note
Using `flutter_local_notifications` is a great way to implement notifications while the is in foreground too! You can generate a local notification listening to events using the method `streamChatClient.on()` and react to the events you want.
You should also check that the channel of the message is different than the channel in the foreground.
How you do this depends on your app infrastructure and how you handle navigation.
Take a look at the [Stream Chat v1 sample app](https://github.com/GetStream/flutter-samples/blob/main/packages/stream_chat_v1/lib/home_page.dart#L11) to see how we're doing it over there.
:::
### Saving notification messages to the offline storage
@@ -0,0 +1,182 @@
---
id: customize_message_widget
sidebar_position: 11
title: Customizing The MessageWidget
---
Customizing Text Messages
### Introduction
Every application provides a unique look and feel to their own messaging interface including and not
limited to fonts, colors, and shapes.
This guide details how to customize the `MessageWidget` in the Stream Chat Flutter UI SDK.
### Building Custom Messages
This guide goes into detail about the ability to customize the `MessageWidget`. However, if you want
to customize the default `MessageWidget` in the `MessageListView` provided, you can use the `.copyWith()` method
provided inside the `messageBuilder` parameter of the `MessageListView` like this:
```dart
MessageListView(
messageBuilder: (context, details, messageList, defaultImpl) {
// Your implementation of the message here
// E.g: return Text(details.message.text ?? '');
},
),
```
### Theming
You can customize the `MessageWidget` using the `StreamChatTheme` class, so that you can change the
message theme at the top instead of creating your own `MessageWidget` at the lower implementation level.
There are several things you can change in the theme including text styles and colors of various elements.
You can also set a different theme for the user's own messages and messages received by them.
:::note
Theming allows you to change minor factors like style while using the widget directly allows you much
more customization such as replacing a certain widget with another. Some things can only be customized
through the widget and not the theme.
:::
Here is an example:
```dart
StreamChatThemeData(
/// Sets theme for user's messages
ownMessageTheme: MessageThemeData(
messageBackgroundColor: colorTheme.textHighEmphasis,
),
/// Sets theme for received messages
otherMessageTheme: MessageThemeData(
avatarTheme: AvatarThemeData(
borderRadius: BorderRadius.circular(8),
),
),
)
```
![](../assets/message_theming.png)
#### Change message text style
The `MessageWidget` has multiple `Text` widgets that you can manipulate the styles of. The three main
are the actual message text, user name, message links, and the message timestamp.
```dart
MessageThemeData(
messageTextStyle: TextStyle(...),
createdAtStyle: TextStyle(...),
messageAuthorStyle: TextStyle(...),
messageLinksStyle: TextStyle(...),
)
```
![](../assets/message_styles.png)
#### Change avatar theme
You can change the attributes of the avatar (if displayed) using the `avatarTheme` property.
```dart
MessageThemeData(
avatarTheme: AvatarThemeData(
borderRadius: BorderRadius.circular(8),
),
)
```
![](../assets/message_rounded_avatar.png)
#### Changing Reaction theme
You also customize the reactions attached to every message using the theme.
```dart
MessageThemeData(
reactionsBackgroundColor: Colors.red,
reactionsBorderColor: Colors.redAccent,
reactionsMaskColor: Colors.pink,
),
```
![](../assets/message_reaction_theming.png)
### Changing Message Actions
When a message is long pressed, the `MessageActionsModal` is shown.
The `MessageWidget` allows showing or hiding some options if you so choose.
```dart
MessageWidget(
...
showUsername = true,
showTimestamp = true,
showReactions = true,
showDeleteMessage = true,
showEditMessage = true,
showReplyMessage = true,
showThreadReplyMessage = true,
showResendMessage = true,
showCopyMessage = true,
showFlagButton = true,
showPinButton = true,
showPinHighlight = true,
),
```
![](../assets/message_widget_actions.png)
### Building attachments
The `customAttachmentBuilder` property allows you to build any kind of attachment (inbuilt or custom)
in your own way. While a separate guide is written for this, it is included here because of relevance.
```dart
MessageListView(
messageBuilder: (context, details, messages, defaultMessage) {
return defaultMessage.copyWith(
customAttachmentBuilders: {
'location': (context, message, attachments) {
final attachmentWidget = Image.network(
_buildMapAttachment(
attachments[0].extraData['latitude'],
attachments[0].extraData['longitude'],
),
);
return wrapAttachmentWidget(context, attachmentWidget, null, true, BorderRadius.circular(8.0));
}
},
);
},
),
```
### Widget Builders
Some parameters allow you to construct your own widget in place of some elements in the `MessageWidget`.
These are:
* `userAvatarBuilder` : Allows user to substitute their own widget in place of the user avatar.
* `editMessageInputBuilder` : Allows user to substitute their own widget in place of the input in edit mode.
* `textBuilder` : Allows user to substitute their own widget in place of the text.
* `bottomRowBuilder` : Allows user to substitute their own widget in the bottom of the message when not deleted.
* `deletedBottomRowBuilder` : Allows user to substitute their own widget in the bottom of the message when deleted.
```dart
MessageWidget(
...
textBuilder: (context, message) {
// Add your own text implementation here.
},
),
```
@@ -0,0 +1,448 @@
---
id: token_generation_with_firebase
sidebar_position: 5
title: User Token Generation With Firebase Auth and Cloud Functions
---
Securely generate Stream Chat user tokens using Firebase Authentication and Cloud Functions.
:::note
This guide assumes that you are familiar with Firebase Authentication and Cloud Functions for Flutter and using the Flutter Stream Chat SDK.
:::
### Introduction
In this guide, you'll explore how you can use Firebase Auth as an authentication provider and create Firebase Cloud functions to securely
generate Stream Chat user tokens.
You will use Stream's [NodeJS client](https://getstream.io/chat/docs/node/?language=javascript) for Stream account creation and
token generation, and [Flutter Cloud Functions for Firebase](https://firebase.flutter.dev/docs/functions/overview) to invoke the cloud functions
from your Flutter app.
Stream supports several different [backend clients](https://getstream.io/chat/sdk/#backend-clients) to integrate with your server. This guide only shows an easy way to integrate Stream Chat authentication using Firebase and Flutter.
### Flutter Firebase
See the [Flutter Firebase getting started](https://firebase.flutter.dev/docs/overview) docs for setup and installation instructions.
You will also need to add the [Flutter Firebase Authentication](https://firebase.flutter.dev/docs/auth/overview), and [Flutter Firebase Cloud Functions](https://firebase.flutter.dev/docs/functions/overview) packages to your app. Depending on the platform that you target, there may be specific configurations that you need to do.
#### Starting Code
The following code shows a basic application with **FirebaseAuth** and **FirebaseFunctions**.
You will extend this later to execute cloud functions.
```dart
import 'package:cloud_functions/cloud_functions.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'dart:async';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Auth(),
),
);
}
}
class Auth extends StatefulWidget {
Auth({Key? key}) : super(key: key);
@override
_AuthState createState() => _AuthState();
}
class _AuthState extends State<Auth> {
late FirebaseAuth auth;
late FirebaseFunctions functions;
@override
void initState() {
super.initState();
auth = FirebaseAuth.instance;
functions = FirebaseFunctions.instance;
}
final email = '[email protected]';
final password = 'password';
Future<void> createAccount() async {
// Create Firebase account
await auth.createUserWithEmailAndPassword(email: email, password: password);
print('Firebase account created');
}
Future<void> signIn() async {
// Sign in with Firebase
await auth.signInWithEmailAndPassword(email: email, password: password);
print('Firebase signed in');
}
Future<void> signOut() async {
// Revoke Stream chat token.
final callable = functions.httpsCallable('revokeStreamUserToken');
await callable();
print('Stream user token revoked');
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AuthenticationState(
streamUser: auth.authStateChanges(),
),
ElevatedButton(
onPressed: createAccount,
child: Text('Create account'),
),
ElevatedButton(
onPressed: signIn,
child: Text('Sign in'),
),
ElevatedButton(
onPressed: signOut,
child: Text('Sign out'),
),
],
),
);
}
}
class AuthenticationState extends StatelessWidget {
const AuthenticationState({
Key? key,
required this.streamUser,
}) : super(key: key);
final Stream<User?> streamUser;
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: streamUser,
builder: (context, snapshot) {
if (snapshot.hasData) {
return (snapshot.data != null)
? Text('Authenticated')
: Text('Not Authenticated');
}
return Text('Not Authenticated');
},
);
}
}
```
Running the above will give this:
![](../assets/authentication_demo_app.jpg)
The `Auth` widget handles all of the authentication logic. It initializes a `FirebaseAuth.instance` and uses that
in the `createAccount`, `signIn` and `signOut` methods. There is a button to envoke each of these methods.
The `FirebaseFunctions.instance` will be used later in this guide.
The `AuthenticationState` widget listens to `auth.authStateChanges()` to display a message
indicating if a user is authenticated.
### Firebase Cloud Functions
Firebase Cloud Functions allows you to extend Firebase with custom operations that an event can trigger:
- **Internal event**: For example, when creating a new Firebase account this is automatically triggered.
- **External event**: For example, directly calling a cloud function from your Flutter application.
To set up your local environment to deploy cloud functions, please see the
[Cloud Functions getting started](https://firebase.flutter.dev/docs/overview) docs.
After initializing your project with cloud functions, you should have a **functions** folder in your project, including a `package.json` file.
There should be two dependencies already added, **firebase-admin** and **firebase-functions**. You will also need to add the **stream-chat** dependency.
Navigate to the **functions** folder and run `npm install stream-chat --save-prod`.
This will install the node module and add it as a dependency to `package.json`.
Now open `index.js` and add the following (this is the complete example):
```js
const StreamChat = require('stream-chat').StreamChat;
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
const serverClient = StreamChat.getInstance(functions.config().stream.key, functions.config().stream.secret);
// When a user is deleted from Firebase their associated Stream account is also deleted.
exports.deleteStreamUser = functions.auth.user().onDelete((user, context) => {
return serverClient.deleteUser(user.uid);
});
// Create a Stream user and return auth token.
exports.createStreamUserAndGetToken = functions.https.onCall(async (data, context) => {
// Checking that the user is authenticated.
if (!context.auth) {
// Throwing an HttpsError so that the client gets the error details.
throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
'while authenticated.');
} else {
try {
// Create user using the serverClient.
await serverClient.upsertUser({
id: context.auth.uid,
name: context.auth.token.name,
email: context.auth.token.email,
image: context.auth.token.image,
});
/// Create and return user auth token.
return serverClient.createToken(context.auth.uid);
} catch (err) {
console.error(`Unable to create user with ID ${context.auth.uid} on Stream. Error ${err}`);
// Throwing an HttpsError so that the client gets the error details.
throw new functions.https.HttpsError('aborted', "Could not create Stream user");
}
}
});
// Get Stream user token.
exports.getStreamUserToken = functions.https.onCall((data, context) => {
// Checking that the user is authenticated.
if (!context.auth) {
// Throwing an HttpsError so that the client gets the error details.
throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
'while authenticated.');
} else {
try {
return serverClient.createToken(context.auth.uid);
} catch (err) {
console.error(`Unable to get user token with ID ${context.auth.uid} on Stream. Error ${err}`);
// Throwing an HttpsError so that the client gets the error details.
throw new functions.https.HttpsError('aborted', "Could not get Stream user");
}
}
});
// Revoke the authenticated user's Stream chat token.
exports.revokeStreamUserToken = functions.https.onCall((data, context) => {
// Checking that the user is authenticated.
if (!context.auth) {
// Throwing an HttpsError so that the client gets the error details.
throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
'while authenticated.');
} else {
try {
return serverClient.revokeUserToken(context.auth.uid);
} catch (err) {
console.error(`Unable to revoke user token with ID ${context.auth.uid} on Stream. Error ${err}`);
// Throwing an HttpsError so that the client gets the error details.
throw new functions.https.HttpsError('aborted', "Could not get Stream user");
}
}
});
```
First, you import the necessary packages and call `admin.initializeApp();` to set up Firebase cloud functions.
Next, you initialize the **StreamChat** server client by calling `StreamChat.getInstance`. This function requires your Stream app's
**token** and **secret**. You can get this from the Stream Dashboard for your app.
Set these values as environment data on Firebase Functions.
```bash
firebase functions:config:set stream.key="app-key" stream.secret="app-secret"
```
*Replace **app-key** and **app-secret** with the values for your Stream app.*
This creates an object of **stream** with properties **key** and **secret**. To access this environment
data use `functions.config().stream.key` and `functions.config().stream.secret`.
See the [Firebase environment configuration](https://firebase.google.com/docs/functions/config-env)
documentation for additional information.
To deploy these functions to Firebase, run:
```bash
firebase deploy --only functions
```
### Create a Stream User and Get the User's Token
In the `createStreamUserAndGetToken` cloud function you create an `onCall` HTTPS handler, which exposes
a cloud function that can be envoked from your Flutter app.
```js
// Create a Stream user and return auth token.
exports.createStreamUserAndGetToken = functions.https.onCall(async (data, context) => {
// Checking that the user is authenticated.
if (!context.auth) {
// Throwing an HttpsError so that the client gets the error details.
throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
'while authenticated.');
} else {
try {
// Create user using the serverClient.
await serverClient.upsertUser({
id: context.auth.uid,
name: context.auth.token.name,
email: context.auth.token.email,
image: context.auth.token.image,
});
/// Create and return user auth token.
return serverClient.createToken(context.auth.uid);
} catch (err) {
console.error(`Unable to create user with ID ${context.auth.uid} on Stream. Error ${err}`);
// Throwing an HttpsError so that the client gets the error details.
throw new functions.https.HttpsError('aborted', "Could not create Stream user");
}
}
});
```
This function first does a check to see that the client that calls it is authenticated,
by ensuring that `context.auth` is not null. If it is null, then it throws an `HttpsError` with a descriptive
message. This error can be caught in your Flutter application.
If the caller is authenticated the function proceeds to use the `serverClient` to create a new Stream Chat
user by calling the `upsertUser` method and passing in some user data. It uses the authenticated caller's **uid** as an **id**.
After the user is created it generates a token for that user. This token is then returned to the caller.
To call this from Flutter, you will need to use the `cloud_functions` package.
Update the **createAccount** method in your Flutter code to the following:
```dart
Future<void> createAccount() async {
// Create Firebase account
await auth.createUserWithEmailAndPassword(email: email, password: password);
print('Firebase account created');
// Create Stream user and get token
final callable = functions.httpsCallable('createStreamUserAndGetToken');
final results = await callable();
print('Stream account created, token: ${results.data}');
}
```
Calling this method will do the following:
1. Create a new Firebase User and authenticate that user.
2. Call the `createStreamUserAndGetToken` cloud function and get the Stream user token for the authenticated user.
As you can see, calling a cloud function is easy and will also send all the necessary user authentication information (such as the UID)
in the request.
Once you have the Stream user token, you can authenticate your Stream Chat user as you normally would.
Please see our [initialization documention](https://getstream.io/chat/docs/flutter-dart/init_and_users/?language=dart) for more information.
As you can see below, the User ID matches on both Firebase's and Stream's user database.
##### Firebase Authentication Database
![Firebase Auth Database with new user created](../assets/firebase_authentication_dashboard.jpg)
##### Stream Chat User Database
![Stream chat user database new account created](../assets/stream_chat_user_database.jpg)
### Get the Stream User Token
The `getStreamUserToken` cloud function is very similar to the `createStreamUserAndGetToken` function. The only difference is
that it only creates a user token and does not create a new user account on Stream.
Update the **signIn** method in your Flutter code to the following:
```dart
Future<void> signIn() async {
// Sign in with Firebase
await auth.signInWithEmailAndPassword(email: email, password: password);
print('Firebase signed in');
// Get Stream user token
final callable = functions.httpsCallable('getStreamUserToken');
final results = await callable();
print('Stream user token retrieved: ${results.data}');
}
```
Calling this method will do the following:
1. Sign in using Firebase Auth.
2. Call the `getStreamUserToken` cloud function to get a Stream user token.
:::note
The user needs to be authenticated to call this cloud function. Otherwise, the function will throw
the **failed-precondition** error that you specified.
:::
### Revoke Stream User Token
You may also want to revoke the Stream user token if you sign out from Firebase.
Update the `signOut` method in your Flutter code to the following:
```dart
Future<void> signOut() async {
// Revoke Stream user token.
final callable = functions.httpsCallable('revokeStreamUserToken');
await callable();
print('Stream user token revoked');
// Sign out Firebase.
await auth.signOut();
print('Firebase signed out');
}
```
:::note
Call the cloud function before signing out from Firebase.
:::
### Delete Stream User
When deleting a Firebase user account, it would make sense also to delete the
associated Stream user account.
The cloud function looks like this:
```js
// When a user is deleted from Firebase their associated Stream account is also deleted.
exports.deleteStreamUser = functions.auth.user().onDelete((user, context) => {
return serverClient.deleteUser(user.uid);
});
```
In this function, you are listening to delete events on Firebase auth. When an account is deleted, this function will be triggered, and you can get the
user's **uid** and call the `deleteUser` method on the `serverClient`.
This is not an external cloud function; it can only be triggered when an
account is deleted.
### Conclusion
In this guide, you have seen how to securely create Stream Chat tokens using
Firebase Authentication and Cloud Functions.
The principles shown in this guide can be applied to your preferred authentication
provider and cloud architecture of choice.
+6
View File
@@ -69,6 +69,12 @@ scripts:
select-package:
dir-exists: coverage
docs:
run: |
npm install -g https://github.com/GetStream/stream-chat-docusaurus-cli &&
npx stream-chat-docusaurus -i -s
description: Runs the docusaurus documentation locally.
environment:
sdk: '>=2.12.0 <3.0.0'
flutter: '>=1.22.4 <2.0.0'
+7
View File
@@ -1,3 +1,10 @@
## 2.2.1
🐞 Fixed
- Fixed unread indicator not updating correctly
- Fix `channel.show` not working because of null body
## 2.2.0
🐞 Fixed
@@ -1488,7 +1488,7 @@ class ChannelClientState {
_listenMemberRemoved();
_computeInitialUnread();
_computeUnread();
_startCleaning();
@@ -1512,11 +1512,11 @@ class ChannelClientState {
final _subscriptions = <StreamSubscription>[];
void _computeInitialUnread() {
void _computeUnread() {
final userRead = channelState.read.firstWhereOrNull(
(r) => r.user.id == _channel._client.state.currentUser?.id,
);
if (userRead != null) {
if (userRead != null && userRead.unreadMessages > 0) {
unreadCount = userRead.unreadMessages;
}
}
@@ -1934,6 +1934,8 @@ class ChannelClientState {
read: newReads,
pinnedMessages: updatedState.pinnedMessages,
);
_computeUnread();
}
int _sortByCreatedAt(Message a, Message b) =>
@@ -292,6 +292,7 @@ class ChannelApi {
) async {
final response = await _client.post(
'${_getChannelUrl(channelId, channelType)}/show',
data: {},
);
return EmptyResponse.fromJson(response.data);
}
+1 -1
View File
@@ -3,4 +3,4 @@ import 'package:stream_chat/src/client/client.dart';
/// Current package version
/// Used in [StreamChatClient] to build the `x-stream-client` header
// ignore: constant_identifier_names
const PACKAGE_VERSION = '2.2.0';
const PACKAGE_VERSION = '2.2.1';
+1 -1
View File
@@ -1,7 +1,7 @@
name: stream_chat
homepage: https://getstream.io/
description: The official Dart client for Stream Chat, a service for building chat applications.
version: 2.2.0
version: 2.2.1
repository: https://github.com/GetStream/stream-chat-flutter
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
@@ -550,14 +550,21 @@ void main() {
final path = '${_getChannelUrl(channelId, channelType)}/show';
when(() => client.post(path)).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
when(() => client.post(
path,
data: {},
))
.thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await channelApi.showChannel(channelId, channelType);
expect(res, isNotNull);
verify(() => client.post(path)).called(1);
verify(() => client.post(
path,
data: {},
)).called(1);
verifyNoMoreInteractions(client);
});
@@ -1,3 +1,7 @@
## 2.2.1
- Updated `stream_chat_flutter_core` dependency to 2.2.1
## 2.2.0
✅ Added
+2 -2
View File
@@ -1,7 +1,7 @@
name: stream_chat_flutter
homepage: https://github.com/GetStream/stream-chat-flutter
description: Stream Chat official Flutter SDK. Build your own chat experience using Dart and Flutter.
version: 2.2.0
version: 2.2.1
repository: https://github.com/GetStream/stream-chat-flutter
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
@@ -37,7 +37,7 @@ dependencies:
scrollable_positioned_list: ^0.2.0-nullsafety.0
share_plus: ^2.0.3
shimmer: ^2.0.0
stream_chat_flutter_core: ^2.2.0
stream_chat_flutter_core: ^2.2.1
substring_highlight: ^1.0.26
synchronized: ^3.0.0
url_launcher: ^6.0.3
@@ -1,3 +1,7 @@
## 2.2.1
- Updated `stream_chat` dependency to 2.2.1
## 2.2.0
🛑️ Breaking Changes from `2.1.1`
@@ -1,7 +1,7 @@
name: stream_chat_flutter_core
homepage: https://github.com/GetStream/stream-chat-flutter
description: Stream Chat official Flutter SDK Core. Build your own chat experience using Dart and Flutter.
version: 2.2.0
version: 2.2.1
repository: https://github.com/GetStream/stream-chat-flutter
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
@@ -16,7 +16,7 @@ dependencies:
sdk: flutter
meta: ^1.3.0
rxdart: ^0.27.0
stream_chat: ^2.2.0
stream_chat: ^2.2.1
dev_dependencies:
fake_async: ^1.2.0
@@ -1,3 +1,9 @@
## Upcoming
🐞 Fixed
* Fixed typos in `Italian` translations.
## 1.1.0
✅ Added
@@ -255,7 +255,7 @@ Il file è troppo grande per essere caricato. Il limite è di $limitInMB MB.''';
String get yesterdayLabel => 'Ieri';
@override
String get channelIsMutedText => 'Il canale è mutato';
String get channelIsMutedText => 'Il canale è silenziato';
@override
String get noTitleText => 'Nessun titolo';
@@ -274,7 +274,7 @@ Il file è troppo grande per essere caricato. Il limite è di $limitInMB MB.''';
String get loadingChannelsError => 'Errore durante il caricamento dei canali';
@override
String get deleteConversationLabel => 'Elemina conversazione';
String get deleteConversationLabel => 'Elimina conversazione';
@override
String get deleteConversationQuestion =>