feat(chat): add init and dispose chat, typing info, receive a messages

This commit is contained in:
alex
2024-07-03 16:50:09 +03:00
parent 424ce3cb34
commit 4c7519ee4c
27 changed files with 553 additions and 167 deletions

View File

@@ -1,20 +1,108 @@
import 'dart:convert';
import 'package:dart_pusher_channels/dart_pusher_channels.dart';
import 'package:easy_debounce/easy_debounce.dart';
import 'package:eatvio_app/core/initialization_cubit/initialization_cubit.dart';
import 'package:eatvio_app/core/initialization_cubit/initialization_state.dart';
import 'package:eatvio_app/core/token_storage.dart';
import 'package:eatvio_app/features/chat/models/chat_message_model.dart';
import 'package:eatvio_app/features/chat/presentation/bloc/chat_room_cubit/chat_room_state.dart';
import 'package:eatvio_app/features/chat/repositories/chat_repository.dart';
import 'package:eatvio_app/locator_service.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class ChatRoomCubit extends Cubit<ChatRoomState> {
final ChatRepository chatRepository;
late final PusherChannelsClient client;
late final PrivateChannel privateChannel;
ChatRoomCubit({
required this.chatRepository,
}) : super(ChatRoomState.loading());
initChat(String chatId) async {
try {
final chatRoomModel = await chatRepository.getChatRoom(chatId);
emit(ChatRoomState.loaded(chatRoomModel: chatRoomModel));
final chatRoom = await chatRepository.getChatRoom(chatId);
final chatMessages = await chatRepository.getChatMessages(chatId);
final initCubit = sl<InitializationCubit>();
if (initCubit.state is InitializationStateSuccess) {
await subscribeToChatChannel(initCubit: initCubit, chatId: chatId);
} else {
await initCubit.runInitialization();
await subscribeToChatChannel(initCubit: initCubit, chatId: chatId);
}
emit(ChatRoomState.loaded(
chatRoom: chatRoom,
chatMessages: chatMessages,
isTyping: false,
));
} catch (e) {
emit(ChatRoomState.error(errorMessage: 'Ошибка получеия данных'));
}
}
Future<void> subscribeToChatChannel({
required InitializationCubit initCubit,
required String chatId,
}) async {
client = (initCubit.state as InitializationStateSuccess).client;
privateChannel = await client.privateChannel(
'private-direct-chat.$chatId',
authorizationDelegate: EndpointAuthorizableChannelTokenAuthorizationDelegate.forPrivateChannel(
authorizationEndpoint: Uri.parse('https://mobile-stage.eatvio.ru/broadcasting/auth'),
headers: {
'Authorization': 'Bearer ${await TokenStorage.getTokenFromStorage()}',
},
),
);
privateChannel.subscribe();
privateChannel.bind('App\\Events\\ChatMessageUpdated').listen((event) {
List<ChatMessageModel> messagesList = [
ChatMessageModel.fromJson(jsonDecode(event.data)['message']),
...(state as ChatRoomStateLoaded).chatMessages.messagesList,
];
emit(
ChatRoomState.loaded(
chatRoom: (state as ChatRoomStateLoaded).chatRoom,
chatMessages: (state as ChatRoomStateLoaded).chatMessages.copyWith(messagesList: messagesList),
isTyping: (state as ChatRoomStateLoaded).isTyping,
),
);
});
privateChannel.bind('client-typing').listen((event) {
emit(
ChatRoomState.loaded(
chatRoom: (state as ChatRoomStateLoaded).chatRoom,
chatMessages: (state as ChatRoomStateLoaded).chatMessages,
isTyping: true,
),
);
EasyDebounce.debounce(
'client-typing',
Duration(seconds: 3),
() => emit(
ChatRoomState.loaded(
chatRoom: (state as ChatRoomStateLoaded).chatRoom,
chatMessages: (state as ChatRoomStateLoaded).chatMessages,
isTyping: false,
),
),
);
});
}
@override
Future<void> close() async {
privateChannel.unsubscribe();
super.close();
}
}

View File

@@ -1,3 +1,4 @@
import 'package:eatvio_app/features/chat/models/chat_messages_model.dart';
import 'package:eatvio_app/features/chat/models/chat_room_model.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@@ -10,7 +11,9 @@ abstract class ChatRoomState with _$ChatRoomState {
const factory ChatRoomState.loading() = ChatRoomStateLoading;
const factory ChatRoomState.loaded({
required ChatRoomModel chatRoomModel,
required ChatRoomModel chatRoom,
required ChatMessagesModel chatMessages,
required bool isTyping,
}) = ChatRoomStateLoaded;
const factory ChatRoomState.error({

View File

@@ -20,7 +20,9 @@ mixin _$ChatRoomState {
TResult when<TResult extends Object?>(
TResult Function() $default, {
required TResult Function() loading,
required TResult Function(ChatRoomModel chatRoomModel) loaded,
required TResult Function(ChatRoomModel chatRoom,
ChatMessagesModel chatMessages, bool isTyping)
loaded,
required TResult Function(String errorMessage) error,
}) =>
throw _privateConstructorUsedError;
@@ -28,7 +30,9 @@ mixin _$ChatRoomState {
TResult? whenOrNull<TResult extends Object?>(
TResult? Function()? $default, {
TResult? Function()? loading,
TResult? Function(ChatRoomModel chatRoomModel)? loaded,
TResult? Function(ChatRoomModel chatRoom, ChatMessagesModel chatMessages,
bool isTyping)?
loaded,
TResult? Function(String errorMessage)? error,
}) =>
throw _privateConstructorUsedError;
@@ -36,7 +40,9 @@ mixin _$ChatRoomState {
TResult maybeWhen<TResult extends Object?>(
TResult Function()? $default, {
TResult Function()? loading,
TResult Function(ChatRoomModel chatRoomModel)? loaded,
TResult Function(ChatRoomModel chatRoom, ChatMessagesModel chatMessages,
bool isTyping)?
loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
}) =>
@@ -126,7 +132,9 @@ class _$ChatRoomStateImpl implements _ChatRoomState {
TResult when<TResult extends Object?>(
TResult Function() $default, {
required TResult Function() loading,
required TResult Function(ChatRoomModel chatRoomModel) loaded,
required TResult Function(ChatRoomModel chatRoom,
ChatMessagesModel chatMessages, bool isTyping)
loaded,
required TResult Function(String errorMessage) error,
}) {
return $default();
@@ -137,7 +145,9 @@ class _$ChatRoomStateImpl implements _ChatRoomState {
TResult? whenOrNull<TResult extends Object?>(
TResult? Function()? $default, {
TResult? Function()? loading,
TResult? Function(ChatRoomModel chatRoomModel)? loaded,
TResult? Function(ChatRoomModel chatRoom, ChatMessagesModel chatMessages,
bool isTyping)?
loaded,
TResult? Function(String errorMessage)? error,
}) {
return $default?.call();
@@ -148,7 +158,9 @@ class _$ChatRoomStateImpl implements _ChatRoomState {
TResult maybeWhen<TResult extends Object?>(
TResult Function()? $default, {
TResult Function()? loading,
TResult Function(ChatRoomModel chatRoomModel)? loaded,
TResult Function(ChatRoomModel chatRoom, ChatMessagesModel chatMessages,
bool isTyping)?
loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
}) {
@@ -241,7 +253,9 @@ class _$ChatRoomStateLoadingImpl implements ChatRoomStateLoading {
TResult when<TResult extends Object?>(
TResult Function() $default, {
required TResult Function() loading,
required TResult Function(ChatRoomModel chatRoomModel) loaded,
required TResult Function(ChatRoomModel chatRoom,
ChatMessagesModel chatMessages, bool isTyping)
loaded,
required TResult Function(String errorMessage) error,
}) {
return loading();
@@ -252,7 +266,9 @@ class _$ChatRoomStateLoadingImpl implements ChatRoomStateLoading {
TResult? whenOrNull<TResult extends Object?>(
TResult? Function()? $default, {
TResult? Function()? loading,
TResult? Function(ChatRoomModel chatRoomModel)? loaded,
TResult? Function(ChatRoomModel chatRoom, ChatMessagesModel chatMessages,
bool isTyping)?
loaded,
TResult? Function(String errorMessage)? error,
}) {
return loading?.call();
@@ -263,7 +279,9 @@ class _$ChatRoomStateLoadingImpl implements ChatRoomStateLoading {
TResult maybeWhen<TResult extends Object?>(
TResult Function()? $default, {
TResult Function()? loading,
TResult Function(ChatRoomModel chatRoomModel)? loaded,
TResult Function(ChatRoomModel chatRoom, ChatMessagesModel chatMessages,
bool isTyping)?
loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
}) {
@@ -321,9 +339,11 @@ abstract class _$$ChatRoomStateLoadedImplCopyWith<$Res> {
$Res Function(_$ChatRoomStateLoadedImpl) then) =
__$$ChatRoomStateLoadedImplCopyWithImpl<$Res>;
@useResult
$Res call({ChatRoomModel chatRoomModel});
$Res call(
{ChatRoomModel chatRoom, ChatMessagesModel chatMessages, bool isTyping});
$ChatRoomModelCopyWith<$Res> get chatRoomModel;
$ChatRoomModelCopyWith<$Res> get chatRoom;
$ChatMessagesModelCopyWith<$Res> get chatMessages;
}
/// @nodoc
@@ -337,21 +357,39 @@ class __$$ChatRoomStateLoadedImplCopyWithImpl<$Res>
@pragma('vm:prefer-inline')
@override
$Res call({
Object? chatRoomModel = null,
Object? chatRoom = null,
Object? chatMessages = null,
Object? isTyping = null,
}) {
return _then(_$ChatRoomStateLoadedImpl(
chatRoomModel: null == chatRoomModel
? _value.chatRoomModel
: chatRoomModel // ignore: cast_nullable_to_non_nullable
chatRoom: null == chatRoom
? _value.chatRoom
: chatRoom // ignore: cast_nullable_to_non_nullable
as ChatRoomModel,
chatMessages: null == chatMessages
? _value.chatMessages
: chatMessages // ignore: cast_nullable_to_non_nullable
as ChatMessagesModel,
isTyping: null == isTyping
? _value.isTyping
: isTyping // ignore: cast_nullable_to_non_nullable
as bool,
));
}
@override
@pragma('vm:prefer-inline')
$ChatRoomModelCopyWith<$Res> get chatRoomModel {
return $ChatRoomModelCopyWith<$Res>(_value.chatRoomModel, (value) {
return _then(_value.copyWith(chatRoomModel: value));
$ChatRoomModelCopyWith<$Res> get chatRoom {
return $ChatRoomModelCopyWith<$Res>(_value.chatRoom, (value) {
return _then(_value.copyWith(chatRoom: value));
});
}
@override
@pragma('vm:prefer-inline')
$ChatMessagesModelCopyWith<$Res> get chatMessages {
return $ChatMessagesModelCopyWith<$Res>(_value.chatMessages, (value) {
return _then(_value.copyWith(chatMessages: value));
});
}
}
@@ -359,14 +397,21 @@ class __$$ChatRoomStateLoadedImplCopyWithImpl<$Res>
/// @nodoc
class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded {
const _$ChatRoomStateLoadedImpl({required this.chatRoomModel});
const _$ChatRoomStateLoadedImpl(
{required this.chatRoom,
required this.chatMessages,
required this.isTyping});
@override
final ChatRoomModel chatRoomModel;
final ChatRoomModel chatRoom;
@override
final ChatMessagesModel chatMessages;
@override
final bool isTyping;
@override
String toString() {
return 'ChatRoomState.loaded(chatRoomModel: $chatRoomModel)';
return 'ChatRoomState.loaded(chatRoom: $chatRoom, chatMessages: $chatMessages, isTyping: $isTyping)';
}
@override
@@ -374,12 +419,17 @@ class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ChatRoomStateLoadedImpl &&
(identical(other.chatRoomModel, chatRoomModel) ||
other.chatRoomModel == chatRoomModel));
(identical(other.chatRoom, chatRoom) ||
other.chatRoom == chatRoom) &&
(identical(other.chatMessages, chatMessages) ||
other.chatMessages == chatMessages) &&
(identical(other.isTyping, isTyping) ||
other.isTyping == isTyping));
}
@override
int get hashCode => Object.hash(runtimeType, chatRoomModel);
int get hashCode =>
Object.hash(runtimeType, chatRoom, chatMessages, isTyping);
@JsonKey(ignore: true)
@override
@@ -393,10 +443,12 @@ class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded {
TResult when<TResult extends Object?>(
TResult Function() $default, {
required TResult Function() loading,
required TResult Function(ChatRoomModel chatRoomModel) loaded,
required TResult Function(ChatRoomModel chatRoom,
ChatMessagesModel chatMessages, bool isTyping)
loaded,
required TResult Function(String errorMessage) error,
}) {
return loaded(chatRoomModel);
return loaded(chatRoom, chatMessages, isTyping);
}
@override
@@ -404,10 +456,12 @@ class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded {
TResult? whenOrNull<TResult extends Object?>(
TResult? Function()? $default, {
TResult? Function()? loading,
TResult? Function(ChatRoomModel chatRoomModel)? loaded,
TResult? Function(ChatRoomModel chatRoom, ChatMessagesModel chatMessages,
bool isTyping)?
loaded,
TResult? Function(String errorMessage)? error,
}) {
return loaded?.call(chatRoomModel);
return loaded?.call(chatRoom, chatMessages, isTyping);
}
@override
@@ -415,12 +469,14 @@ class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded {
TResult maybeWhen<TResult extends Object?>(
TResult Function()? $default, {
TResult Function()? loading,
TResult Function(ChatRoomModel chatRoomModel)? loaded,
TResult Function(ChatRoomModel chatRoom, ChatMessagesModel chatMessages,
bool isTyping)?
loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
}) {
if (loaded != null) {
return loaded(chatRoomModel);
return loaded(chatRoom, chatMessages, isTyping);
}
return orElse();
}
@@ -465,9 +521,13 @@ class _$ChatRoomStateLoadedImpl implements ChatRoomStateLoaded {
abstract class ChatRoomStateLoaded implements ChatRoomState {
const factory ChatRoomStateLoaded(
{required final ChatRoomModel chatRoomModel}) = _$ChatRoomStateLoadedImpl;
{required final ChatRoomModel chatRoom,
required final ChatMessagesModel chatMessages,
required final bool isTyping}) = _$ChatRoomStateLoadedImpl;
ChatRoomModel get chatRoomModel;
ChatRoomModel get chatRoom;
ChatMessagesModel get chatMessages;
bool get isTyping;
@JsonKey(ignore: true)
_$$ChatRoomStateLoadedImplCopyWith<_$ChatRoomStateLoadedImpl> get copyWith =>
throw _privateConstructorUsedError;
@@ -541,7 +601,9 @@ class _$ChatRoomStateErrorImpl implements ChatRoomStateError {
TResult when<TResult extends Object?>(
TResult Function() $default, {
required TResult Function() loading,
required TResult Function(ChatRoomModel chatRoomModel) loaded,
required TResult Function(ChatRoomModel chatRoom,
ChatMessagesModel chatMessages, bool isTyping)
loaded,
required TResult Function(String errorMessage) error,
}) {
return error(errorMessage);
@@ -552,7 +614,9 @@ class _$ChatRoomStateErrorImpl implements ChatRoomStateError {
TResult? whenOrNull<TResult extends Object?>(
TResult? Function()? $default, {
TResult? Function()? loading,
TResult? Function(ChatRoomModel chatRoomModel)? loaded,
TResult? Function(ChatRoomModel chatRoom, ChatMessagesModel chatMessages,
bool isTyping)?
loaded,
TResult? Function(String errorMessage)? error,
}) {
return error?.call(errorMessage);
@@ -563,7 +627,9 @@ class _$ChatRoomStateErrorImpl implements ChatRoomStateError {
TResult maybeWhen<TResult extends Object?>(
TResult Function()? $default, {
TResult Function()? loading,
TResult Function(ChatRoomModel chatRoomModel)? loaded,
TResult Function(ChatRoomModel chatRoom, ChatMessagesModel chatMessages,
bool isTyping)?
loaded,
TResult Function(String errorMessage)? error,
required TResult orElse(),
}) {