forked from eatvio/eatvio_app
feat(chat): add init and dispose chat, typing info, receive a messages
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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(),
|
||||
}) {
|
||||
|
||||
Reference in New Issue
Block a user