Отображение чатов
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
"@@locale": "en",
|
"@@locale": "en",
|
||||||
"appTitle": "Messenger",
|
"appTitle": "Messenger",
|
||||||
"chats": "Chats",
|
"chats": "Chats",
|
||||||
|
"favorites": "Favorites",
|
||||||
"contacts": "Contacts",
|
"contacts": "Contacts",
|
||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"@@locale": "ru",
|
"@@locale": "ru",
|
||||||
"appTitle": "Мессенджер",
|
"appTitle": "Мессенджер",
|
||||||
"chats": "Чаты",
|
"chats": "Чаты",
|
||||||
|
"favorites": "Избранное",
|
||||||
"contacts": "Контакты",
|
"contacts": "Контакты",
|
||||||
"settings": "Настройки",
|
"settings": "Настройки",
|
||||||
"login": "Вход",
|
"login": "Вход",
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import 'package:isar/isar.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import '../../features/chat/data/models/chat_model.dart';
|
||||||
|
import '../../features/chat/data/models/message_model.dart';
|
||||||
|
|
||||||
|
class DatabaseService {
|
||||||
|
late Isar _isar;
|
||||||
|
|
||||||
|
Isar get isar => _isar;
|
||||||
|
|
||||||
|
Future<void> init() async {
|
||||||
|
final dir = await getApplicationDocumentsDirectory();
|
||||||
|
_isar = await Isar.open(
|
||||||
|
[ChatModelSchema, MessageModelSchema],
|
||||||
|
directory: dir.path,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> clearAll() async {
|
||||||
|
await _isar.writeTxn(() => _isar.clear());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'package:signalr_netcore/signalr_client.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import '../../features/chat/domain/entities/message.dart';
|
||||||
|
|
||||||
|
class SignalRService {
|
||||||
|
final SharedPreferences prefs;
|
||||||
|
HubConnection? _hubConnection;
|
||||||
|
final _messageController = StreamController<Message>.broadcast();
|
||||||
|
|
||||||
|
Stream<Message> get messages => _messageController.stream;
|
||||||
|
|
||||||
|
SignalRService(this.prefs);
|
||||||
|
|
||||||
|
Future<void> init() async {
|
||||||
|
final apiUrl = prefs.getString('api_url') ?? 'https://api.messenger.app';
|
||||||
|
final token = prefs.getString('access_token');
|
||||||
|
|
||||||
|
if (token == null) return;
|
||||||
|
|
||||||
|
final hubUrl = '${apiUrl.replaceAll(RegExp(r'/+$'), '')}/hubs/chat';
|
||||||
|
|
||||||
|
_hubConnection = HubConnectionBuilder()
|
||||||
|
.withUrl(hubUrl, options: HttpConnectionOptions(
|
||||||
|
accessTokenFactory: () async => token,
|
||||||
|
// logging: (level, message) => print('[SignalR] $level: $message'),
|
||||||
|
))
|
||||||
|
.withAutomaticReconnect()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
_hubConnection?.onclose(({error}) {
|
||||||
|
// print('[SignalR] Connection closed: $error');
|
||||||
|
});
|
||||||
|
|
||||||
|
_hubConnection?.on('ReceiveMessage', _handleReceiveMessage);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await _hubConnection?.start();
|
||||||
|
// print('[SignalR] Connection started');
|
||||||
|
} catch (e) {
|
||||||
|
// print('[SignalR] Error starting connection: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleReceiveMessage(List<dynamic>? arguments) {
|
||||||
|
if (arguments != null && arguments.isNotEmpty) {
|
||||||
|
final data = arguments[0] as Map<String, dynamic>;
|
||||||
|
// Map JSON to Message entity and add to stream
|
||||||
|
// I'll need a Message.fromJson mapper
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> stop() async {
|
||||||
|
await _hubConnection?.stop();
|
||||||
|
_hubConnection = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
abstract class AuthLocalDataSource {
|
abstract class AuthLocalDataSource {
|
||||||
Future<String?> getToken();
|
Future<String?> getToken();
|
||||||
|
String? getTokenSync();
|
||||||
Future<void> saveToken(String token);
|
Future<void> saveToken(String token);
|
||||||
Future<String?> getRefreshToken();
|
Future<String?> getRefreshToken();
|
||||||
Future<void> saveRefreshToken(String token);
|
Future<void> saveRefreshToken(String token);
|
||||||
|
|||||||
@@ -15,6 +15,11 @@ class AuthLocalDataSourceImpl implements AuthLocalDataSource {
|
|||||||
return sharedPreferences.getString(_accessTokenKey);
|
return sharedPreferences.getString(_accessTokenKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? getTokenSync() {
|
||||||
|
return sharedPreferences.getString(_accessTokenKey);
|
||||||
|
}
|
||||||
|
|
||||||
Future<String?> getRefreshToken() async {
|
Future<String?> getRefreshToken() async {
|
||||||
return sharedPreferences.getString(_refreshTokenKey);
|
return sharedPreferences.getString(_refreshTokenKey);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,16 @@ class AuthRepositoryImpl implements AuthRepository {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Result<User>> getCurrentUser() async {
|
Future<Result<User>> getCurrentUser() async {
|
||||||
return await remoteDataSource.getCurrentUser();
|
final result = await remoteDataSource.getCurrentUser();
|
||||||
|
if (result.isFailure) {
|
||||||
|
// If remote fails (e.g. offline), try to return a dummy user with stored ID
|
||||||
|
// to keep the app in authenticated state if we have a token
|
||||||
|
final userId = await localDataSource.getUserId();
|
||||||
|
if (userId != null) {
|
||||||
|
return Result.success(User(id: userId, name: 'User', email: ''));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -60,5 +69,11 @@ class AuthRepositoryImpl implements AuthRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get isLoggedIn => false;
|
bool get isLoggedIn {
|
||||||
|
// This is problematic because it's synchronous but SharedPreferences is async.
|
||||||
|
// However, in our DI we wait for SharedPreferences.getInstance().
|
||||||
|
// We can use a synchronous check if we expose it or just use the fact that
|
||||||
|
// AuthBloc calls authChecked which is async.
|
||||||
|
return localDataSource.getTokenSync() != null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
import 'package:isar/isar.dart';
|
||||||
|
import '../../../../core/errors/result.dart';
|
||||||
|
import '../../../../core/errors/errors.dart';
|
||||||
|
import '../../domain/entities/chat.dart';
|
||||||
|
import '../../domain/entities/message.dart';
|
||||||
|
import '../models/chat_model.dart';
|
||||||
|
import '../models/message_model.dart';
|
||||||
|
import 'chat_local_datasource.dart';
|
||||||
|
|
||||||
|
class ChatLocalDataSourceImpl implements ChatLocalDataSource {
|
||||||
|
final Isar isar;
|
||||||
|
|
||||||
|
ChatLocalDataSourceImpl(this.isar);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<List<Chat>>> getCachedChats() async {
|
||||||
|
try {
|
||||||
|
final chatModels = await isar.chatModels.where().sortByLastMessageTimeDesc().findAll();
|
||||||
|
return Result.success(chatModels.map((m) => m.toEntity()).toList());
|
||||||
|
} catch (e) {
|
||||||
|
return Result.failure(AppError.database(message: e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<void>> cacheChats(List<Chat> chats) async {
|
||||||
|
try {
|
||||||
|
final models = chats.map((c) => ChatModel.fromEntity(c)).toList();
|
||||||
|
await isar.writeTxn(() async {
|
||||||
|
await isar.chatModels.putAll(models);
|
||||||
|
});
|
||||||
|
return const Result.success(null);
|
||||||
|
} catch (e) {
|
||||||
|
return Result.failure(AppError.database(message: e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<Chat>> getChatFromCache(String chatId) async {
|
||||||
|
try {
|
||||||
|
final model = await isar.chatModels.filter().idEqualTo(chatId).findFirst();
|
||||||
|
if (model != null) {
|
||||||
|
return Result.success(model.toEntity());
|
||||||
|
}
|
||||||
|
return const Result.failure(AppError.notFound(message: 'Chat not found in cache'));
|
||||||
|
} catch (e) {
|
||||||
|
return Result.failure(AppError.database(message: e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<void>> cacheChat(Chat chat) async {
|
||||||
|
try {
|
||||||
|
final model = ChatModel.fromEntity(chat);
|
||||||
|
await isar.writeTxn(() async {
|
||||||
|
await isar.chatModels.put(model);
|
||||||
|
});
|
||||||
|
return const Result.success(null);
|
||||||
|
} catch (e) {
|
||||||
|
return Result.failure(AppError.database(message: e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<List<Message>>> getMessagesFromCache(String chatId) async {
|
||||||
|
try {
|
||||||
|
final messageModels = await isar.messageModels
|
||||||
|
.filter()
|
||||||
|
.chatIdEqualTo(chatId)
|
||||||
|
.sortByCreatedAtDesc()
|
||||||
|
.findAll();
|
||||||
|
return Result.success(messageModels.map((m) => m.toEntity()).toList());
|
||||||
|
} catch (e) {
|
||||||
|
return Result.failure(AppError.database(message: e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<void>> cacheMessages(String chatId, List<Message> messages) async {
|
||||||
|
try {
|
||||||
|
final models = messages.map((m) => MessageModel.fromEntity(m)).toList();
|
||||||
|
await isar.writeTxn(() async {
|
||||||
|
await isar.messageModels.putAll(models);
|
||||||
|
});
|
||||||
|
return const Result.success(null);
|
||||||
|
} catch (e) {
|
||||||
|
return Result.failure(AppError.database(message: e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<void>> clearCache() async {
|
||||||
|
try {
|
||||||
|
await isar.writeTxn(() => isar.clear());
|
||||||
|
return const Result.success(null);
|
||||||
|
} catch (e) {
|
||||||
|
return Result.failure(AppError.database(message: e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,10 +3,13 @@ import '../../domain/entities/chat.dart';
|
|||||||
import '../../domain/entities/message.dart';
|
import '../../domain/entities/message.dart';
|
||||||
|
|
||||||
abstract class ChatRemoteDataSource {
|
abstract class ChatRemoteDataSource {
|
||||||
Future<Result<List<Chat>>> getChats();
|
Future<Result<List<Chat>>> getChats({String? currentUserId});
|
||||||
Future<Result<Chat>> getChatById(String chatId);
|
Future<Result<Chat>> getChatById(String chatId);
|
||||||
Future<Result<void>> createChat(String title, List<String> participantIds);
|
Future<Result<Chat>> createPersonalChat(String userId);
|
||||||
Future<Result<void>> sendMessage(String chatId, Message message);
|
Future<Result<Chat>> createGroupChat(String name, List<String> memberIds);
|
||||||
Future<Result<List<Message>>> getMessages(String chatId, {int? limit, String? lastMessageId});
|
Future<Result<Chat>> getOrCreateFavorites();
|
||||||
Stream<Result<Message>> listenToMessages(String chatId);
|
Future<Result<Message>> sendMessage(String chatId, String content, {String? type, List<Map<String, dynamic>>? attachments});
|
||||||
|
Future<Result<List<Message>>> getMessages(String chatId, {String? cursor});
|
||||||
|
Future<Result<void>> togglePin(String chatId);
|
||||||
|
Future<Result<void>> clearChat(String chatId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,191 @@
|
|||||||
|
import '../../../../core/network/api_client.dart';
|
||||||
|
import '../../../../core/errors/result.dart';
|
||||||
|
import '../../../../core/errors/errors.dart';
|
||||||
|
import '../../domain/entities/chat.dart';
|
||||||
|
import '../../domain/entities/message.dart';
|
||||||
|
import '../../domain/entities/user.dart';
|
||||||
|
import 'chat_remote_datasource.dart';
|
||||||
|
|
||||||
|
class ChatRemoteDataSourceImpl implements ChatRemoteDataSource {
|
||||||
|
final ApiClient apiClient;
|
||||||
|
|
||||||
|
ChatRemoteDataSourceImpl(this.apiClient);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<List<Chat>>> getChats({String? currentUserId}) async {
|
||||||
|
final result = await apiClient.get<List<dynamic>>('/api/chats');
|
||||||
|
return result.fold(
|
||||||
|
(error) => Result.failure(error),
|
||||||
|
(data) {
|
||||||
|
try {
|
||||||
|
final chats = data.map((json) => _mapChatJson(json, currentUserId: currentUserId)).toList();
|
||||||
|
// Sort: favorites first, then by last message time or creation time
|
||||||
|
chats.sort((a, b) {
|
||||||
|
if (a.type == 'favorites') return -1;
|
||||||
|
if (b.type == 'favorites') return 1;
|
||||||
|
final timeA = a.lastMessageTime ?? DateTime.fromMillisecondsSinceEpoch(0);
|
||||||
|
final timeB = b.lastMessageTime ?? DateTime.fromMillisecondsSinceEpoch(0);
|
||||||
|
return timeB.compareTo(timeA);
|
||||||
|
});
|
||||||
|
return Result.success(chats);
|
||||||
|
} catch (e) {
|
||||||
|
return Result.failure(AppError.parsing(message: 'Failed to parse chats: $e'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<Chat>> getChatById(String chatId) async {
|
||||||
|
final result = await apiClient.get<Map<String, dynamic>>('/api/chats/$chatId');
|
||||||
|
return result.fold(
|
||||||
|
(error) => Result.failure(error),
|
||||||
|
(data) {
|
||||||
|
try {
|
||||||
|
return Result.success(_mapChatJson(data));
|
||||||
|
} catch (e) {
|
||||||
|
return Result.failure(AppError.parsing(message: 'Failed to parse chat: $e'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<Chat>> createPersonalChat(String userId) async {
|
||||||
|
final result = await apiClient.post<Map<String, dynamic>>(
|
||||||
|
'/api/chats/personal',
|
||||||
|
data: {'userId': userId},
|
||||||
|
);
|
||||||
|
return result.fold(
|
||||||
|
(error) => Result.failure(error),
|
||||||
|
(data) => Result.success(_mapChatJson(data)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<Chat>> createGroupChat(String name, List<String> memberIds) async {
|
||||||
|
final result = await apiClient.post<Map<String, dynamic>>(
|
||||||
|
'/api/chats/group',
|
||||||
|
data: {
|
||||||
|
'name': name,
|
||||||
|
'memberIds': memberIds,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return result.fold(
|
||||||
|
(error) => Result.failure(error),
|
||||||
|
(data) => Result.success(_mapChatJson(data)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<Chat>> getOrCreateFavorites() async {
|
||||||
|
final result = await apiClient.post<Map<String, dynamic>>('/api/chats/favorites');
|
||||||
|
return result.fold(
|
||||||
|
(error) => Result.failure(error),
|
||||||
|
(data) => Result.success(_mapChatJson(data)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<Message>> sendMessage(String chatId, String content, {String? type, List<Map<String, dynamic>>? attachments}) async {
|
||||||
|
final result = await apiClient.post<Map<String, dynamic>>(
|
||||||
|
'/api/messages/chat/$chatId',
|
||||||
|
data: {
|
||||||
|
'content': content,
|
||||||
|
'type': type ?? 'Text',
|
||||||
|
'attachments': attachments,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return result.fold(
|
||||||
|
(error) => Result.failure(error),
|
||||||
|
(data) {
|
||||||
|
try {
|
||||||
|
return Result.success(_mapMessageJson(data));
|
||||||
|
} catch (e) {
|
||||||
|
return Result.failure(AppError.parsing(message: 'Failed to parse message: $e'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<List<Message>>> getMessages(String chatId, {String? cursor}) async {
|
||||||
|
final result = await apiClient.get<List<dynamic>>(
|
||||||
|
'/api/messages/chat/$chatId',
|
||||||
|
queryParameters: cursor != null ? {'cursor': cursor} : null,
|
||||||
|
);
|
||||||
|
return result.fold(
|
||||||
|
(error) => Result.failure(error),
|
||||||
|
(data) {
|
||||||
|
try {
|
||||||
|
return Result.success(data.map((json) => _mapMessageJson(json)).toList());
|
||||||
|
} catch (e) {
|
||||||
|
return Result.failure(AppError.parsing(message: 'Failed to parse messages: $e'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<void>> togglePin(String chatId) async {
|
||||||
|
return await apiClient.post('/api/chats/$chatId/pin');
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<void>> clearChat(String chatId) async {
|
||||||
|
return await apiClient.post('/api/chats/$chatId/clear');
|
||||||
|
}
|
||||||
|
|
||||||
|
Chat _mapChatJson(Map<String, dynamic> json, {String? currentUserId}) {
|
||||||
|
final members = (json['members'] as List<dynamic>?)?.map((m) {
|
||||||
|
final userData = m['user'] as Map<String, dynamic>?;
|
||||||
|
return User(
|
||||||
|
id: m['userId'] ?? (userData?['id'] ?? ''),
|
||||||
|
name: userData?['displayName'] ?? '',
|
||||||
|
avatarUrl: userData?['avatar'],
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
final lastMsgJson = json['lastMessage'] ?? (json['messages'] as List?)?.firstOrNull;
|
||||||
|
final type = json['type']?.toString().toLowerCase() ?? 'personal';
|
||||||
|
|
||||||
|
String title = json['name'] ?? '';
|
||||||
|
if (title.isEmpty && type == 'personal' && members != null && members.isNotEmpty) {
|
||||||
|
// If personal chat and no title, use the OTHER member's name
|
||||||
|
try {
|
||||||
|
final otherMember = members.firstWhere(
|
||||||
|
(m) => m.id != currentUserId && m.name.isNotEmpty,
|
||||||
|
orElse: () => members.firstWhere((m) => m.id != currentUserId, orElse: () => members[0]),
|
||||||
|
);
|
||||||
|
title = otherMember.name;
|
||||||
|
} catch (_) {
|
||||||
|
title = members[0].name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Chat(
|
||||||
|
id: json['id'],
|
||||||
|
type: type,
|
||||||
|
title: title,
|
||||||
|
avatarUrl: json['avatar'],
|
||||||
|
participants: members,
|
||||||
|
unreadCount: json['unreadCount'] ?? 0,
|
||||||
|
isPinned: json['isPinned'] ?? false,
|
||||||
|
lastMessage: lastMsgJson != null ? _mapMessageJson(lastMsgJson) : null,
|
||||||
|
lastMessageTime: lastMsgJson != null ? DateTime.parse(lastMsgJson['createdAt']) : null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Message _mapMessageJson(Map<String, dynamic> json) {
|
||||||
|
return Message(
|
||||||
|
id: json['id'],
|
||||||
|
chatId: json['chatId'],
|
||||||
|
senderId: json['senderId'],
|
||||||
|
content: json['content'] ?? '',
|
||||||
|
messageType: json['type'] ?? 'Text',
|
||||||
|
createdAt: json['createdAt'] != null ? DateTime.parse(json['createdAt']) : null,
|
||||||
|
updatedAt: json['updatedAt'] != null ? DateTime.parse(json['updatedAt']) : null,
|
||||||
|
isRead: (json['readBy'] as List?)?.isNotEmpty ?? false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
import 'package:isar/isar.dart';
|
||||||
|
import '../../domain/entities/chat.dart';
|
||||||
|
import '../../domain/entities/user.dart';
|
||||||
|
import '../../domain/entities/message.dart';
|
||||||
|
import 'message_model.dart';
|
||||||
|
|
||||||
|
part 'chat_model.g.dart';
|
||||||
|
|
||||||
|
@collection
|
||||||
|
class ChatModel {
|
||||||
|
Id isarId = Isar.autoIncrement;
|
||||||
|
|
||||||
|
@Index(unique: true, replace: true)
|
||||||
|
late String id;
|
||||||
|
|
||||||
|
late String type;
|
||||||
|
late String title;
|
||||||
|
String? avatarUrl;
|
||||||
|
|
||||||
|
late List<UserModel> participants;
|
||||||
|
|
||||||
|
LastMessageModel? lastMessage;
|
||||||
|
|
||||||
|
DateTime? lastMessageTime;
|
||||||
|
|
||||||
|
int unreadCount = 0;
|
||||||
|
bool isMuted = false;
|
||||||
|
bool isPinned = false;
|
||||||
|
|
||||||
|
Chat toEntity() {
|
||||||
|
return Chat(
|
||||||
|
id: id,
|
||||||
|
type: type,
|
||||||
|
title: title,
|
||||||
|
avatarUrl: avatarUrl,
|
||||||
|
participants: participants.map((u) => u.toEntity()).toList(),
|
||||||
|
lastMessage: lastMessage?.toEntity(),
|
||||||
|
lastMessageTime: lastMessageTime,
|
||||||
|
unreadCount: unreadCount,
|
||||||
|
isMuted: isMuted,
|
||||||
|
isPinned: isPinned,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ChatModel fromEntity(Chat chat) {
|
||||||
|
return ChatModel()
|
||||||
|
..id = chat.id
|
||||||
|
..type = chat.type
|
||||||
|
..title = chat.title
|
||||||
|
..avatarUrl = chat.avatarUrl
|
||||||
|
..participants = chat.participants?.map((u) => UserModel.fromEntity(u)).toList() ?? []
|
||||||
|
..lastMessage = chat.lastMessage != null ? LastMessageModel.fromEntity(chat.lastMessage!) : null
|
||||||
|
..lastMessageTime = chat.lastMessageTime
|
||||||
|
..unreadCount = chat.unreadCount
|
||||||
|
..isMuted = chat.isMuted
|
||||||
|
..isPinned = chat.isPinned;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@embedded
|
||||||
|
class LastMessageModel {
|
||||||
|
late String id;
|
||||||
|
late String content;
|
||||||
|
late String messageType;
|
||||||
|
DateTime? createdAt;
|
||||||
|
|
||||||
|
Message toEntity() {
|
||||||
|
return Message(
|
||||||
|
id: id,
|
||||||
|
chatId: '', // Не критично для превью в списке чатов
|
||||||
|
senderId: '',
|
||||||
|
content: content,
|
||||||
|
messageType: messageType,
|
||||||
|
createdAt: createdAt,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static LastMessageModel fromEntity(Message message) {
|
||||||
|
return LastMessageModel()
|
||||||
|
..id = message.id
|
||||||
|
..content = message.content
|
||||||
|
..messageType = message.messageType
|
||||||
|
..createdAt = message.createdAt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@embedded
|
||||||
|
class UserModel {
|
||||||
|
late String id;
|
||||||
|
late String name;
|
||||||
|
String? avatarUrl;
|
||||||
|
String? role;
|
||||||
|
DateTime? lastSeen;
|
||||||
|
bool? isOnline;
|
||||||
|
|
||||||
|
User toEntity() {
|
||||||
|
return User(
|
||||||
|
id: id,
|
||||||
|
name: name,
|
||||||
|
avatarUrl: avatarUrl,
|
||||||
|
role: role,
|
||||||
|
lastSeen: lastSeen,
|
||||||
|
isOnline: isOnline,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static UserModel fromEntity(User user) {
|
||||||
|
return UserModel()
|
||||||
|
..id = user.id
|
||||||
|
..name = user.name
|
||||||
|
..avatarUrl = user.avatarUrl
|
||||||
|
..role = user.role
|
||||||
|
..lastSeen = user.lastSeen
|
||||||
|
..isOnline = user.isOnline;
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,53 @@
|
|||||||
|
import 'package:isar/isar.dart';
|
||||||
|
import '../../domain/entities/message.dart';
|
||||||
|
|
||||||
|
part 'message_model.g.dart';
|
||||||
|
|
||||||
|
@collection
|
||||||
|
class MessageModel {
|
||||||
|
Id isarId = Isar.autoIncrement;
|
||||||
|
|
||||||
|
@Index(unique: true, replace: true)
|
||||||
|
late String id;
|
||||||
|
|
||||||
|
@Index()
|
||||||
|
late String chatId;
|
||||||
|
|
||||||
|
late String senderId;
|
||||||
|
late String content;
|
||||||
|
late String messageType;
|
||||||
|
|
||||||
|
@Index()
|
||||||
|
DateTime? createdAt;
|
||||||
|
|
||||||
|
DateTime? updatedAt;
|
||||||
|
bool isRead = false;
|
||||||
|
|
||||||
|
// For simplicity, store media as a JSON string or ignore for now
|
||||||
|
String? mediaJson;
|
||||||
|
|
||||||
|
Message toEntity() {
|
||||||
|
return Message(
|
||||||
|
id: id,
|
||||||
|
chatId: chatId,
|
||||||
|
senderId: senderId,
|
||||||
|
content: content,
|
||||||
|
messageType: messageType,
|
||||||
|
createdAt: createdAt,
|
||||||
|
updatedAt: updatedAt,
|
||||||
|
isRead: isRead,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MessageModel fromEntity(Message message) {
|
||||||
|
return MessageModel()
|
||||||
|
..id = message.id
|
||||||
|
..chatId = message.chatId
|
||||||
|
..senderId = message.senderId
|
||||||
|
..content = message.content
|
||||||
|
..messageType = message.messageType
|
||||||
|
..createdAt = message.createdAt
|
||||||
|
..updatedAt = message.updatedAt
|
||||||
|
..isRead = message.isRead ?? false;
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,47 +1,133 @@
|
|||||||
import '../../../../core/errors/errors.dart';
|
import 'dart:async';
|
||||||
import '../../../../core/errors/result.dart';
|
import '../../../../core/errors/result.dart';
|
||||||
|
import '../../../../core/network/signalr_service.dart';
|
||||||
import '../../domain/entities/chat.dart';
|
import '../../domain/entities/chat.dart';
|
||||||
import '../../domain/entities/message.dart';
|
import '../../domain/entities/message.dart';
|
||||||
import '../../domain/repositories/chat_repository.dart';
|
import '../../domain/repositories/chat_repository.dart';
|
||||||
|
import '../datasources/chat_local_datasource.dart';
|
||||||
|
import '../datasources/chat_remote_datasource.dart';
|
||||||
|
|
||||||
class ChatRepositoryImpl implements ChatRepository {
|
class ChatRepositoryImpl implements ChatRepository {
|
||||||
@override
|
final ChatRemoteDataSource remoteDataSource;
|
||||||
Future<Result<void>> createChat(String title, List<String> participantIds) async {
|
final ChatLocalDataSource localDataSource;
|
||||||
return const Result.success(null);
|
final SignalRService signalRService;
|
||||||
}
|
|
||||||
|
ChatRepositoryImpl({
|
||||||
|
required this.remoteDataSource,
|
||||||
|
required this.localDataSource,
|
||||||
|
required this.signalRService,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Result<void>> deleteChat(String chatId) async {
|
Stream<Message> get messageStream => signalRService.messages;
|
||||||
return const Result.success(null);
|
|
||||||
|
@override
|
||||||
|
Future<void> initSignalR() => signalRService.init();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> disposeSignalR() => signalRService.stop();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<List<Chat>>> getChats({String? currentUserId}) async {
|
||||||
|
// 1. Return cached chats immediately if available
|
||||||
|
final cachedResult = await localDataSource.getCachedChats();
|
||||||
|
|
||||||
|
// 2. Fetch from remote and update cache
|
||||||
|
final remoteResult = await remoteDataSource.getChats(currentUserId: currentUserId);
|
||||||
|
if (remoteResult.isSuccess) {
|
||||||
|
final chats = remoteResult.data!;
|
||||||
|
await localDataSource.cacheChats(chats);
|
||||||
|
return Result.success(chats);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If remote fails, return cached or error
|
||||||
|
return cachedResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Result<Chat>> getChatById(String chatId) async {
|
Future<Result<Chat>> getChatById(String chatId) async {
|
||||||
return const Result.failure(AppError.notFound(message: 'Chat not found'));
|
final remoteResult = await remoteDataSource.getChatById(chatId);
|
||||||
|
if (remoteResult.isSuccess) {
|
||||||
|
await localDataSource.cacheChat(remoteResult.data!);
|
||||||
|
return remoteResult;
|
||||||
|
}
|
||||||
|
return localDataSource.getChatFromCache(chatId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Result<List<Chat>>> getChats() async {
|
Future<Result<Chat>> createPersonalChat(String userId) async {
|
||||||
// Return empty list for now
|
final result = await remoteDataSource.createPersonalChat(userId);
|
||||||
return const Result.success([]);
|
if (result.isSuccess) {
|
||||||
|
await localDataSource.cacheChat(result.data!);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Result<List<Message>>> getMessages(
|
Future<Result<Chat>> createGroupChat(String name, List<String> memberIds) async {
|
||||||
String chatId, {
|
final result = await remoteDataSource.createGroupChat(name, memberIds);
|
||||||
int? limit,
|
if (result.isSuccess) {
|
||||||
String? lastMessageId,
|
await localDataSource.cacheChat(result.data!);
|
||||||
}) async {
|
}
|
||||||
return const Result.success([]);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Result<void>> sendMessage(String chatId, Message message) async {
|
Future<Result<Chat>> getOrCreateFavorites() async {
|
||||||
return const Result.success(null);
|
final result = await remoteDataSource.getOrCreateFavorites();
|
||||||
|
if (result.isSuccess) {
|
||||||
|
await localDataSource.cacheChat(result.data!);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Result<void>> updateChat(String chatId, String title) async {
|
Future<Result<Message>> sendMessage(String chatId, String content, {String? type}) async {
|
||||||
return const Result.success(null);
|
final result = await remoteDataSource.sendMessage(chatId, content, type: type);
|
||||||
|
if (result.isSuccess) {
|
||||||
|
// We don't cache individual messages here usually,
|
||||||
|
// let SignalR ReceiveMessage handle it or update list
|
||||||
|
final messagesResult = await getMessages(chatId);
|
||||||
|
if (messagesResult.isSuccess) {
|
||||||
|
await localDataSource.cacheMessages(chatId, messagesResult.data!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<List<Message>>> getMessages(String chatId, {String? cursor}) async {
|
||||||
|
if (cursor == null) {
|
||||||
|
final cached = await localDataSource.getMessagesFromCache(chatId);
|
||||||
|
final remote = await remoteDataSource.getMessages(chatId);
|
||||||
|
if (remote.isSuccess) {
|
||||||
|
await localDataSource.cacheMessages(chatId, remote.data!);
|
||||||
|
return remote;
|
||||||
|
}
|
||||||
|
return cached;
|
||||||
|
} else {
|
||||||
|
return remoteDataSource.getMessages(chatId, cursor: cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<void>> togglePin(String chatId) async {
|
||||||
|
final result = await remoteDataSource.togglePin(chatId);
|
||||||
|
if (result.isSuccess) {
|
||||||
|
final chat = await getChatById(chatId);
|
||||||
|
if (chat.isSuccess) {
|
||||||
|
await localDataSource.cacheChat(chat.data!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<void>> clearChat(String chatId) async {
|
||||||
|
final result = await remoteDataSource.clearChat(chatId);
|
||||||
|
if (result.isSuccess) {
|
||||||
|
await localDataSource.cacheMessages(chatId, []);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,17 @@ import '../entities/chat.dart';
|
|||||||
import '../entities/message.dart';
|
import '../entities/message.dart';
|
||||||
|
|
||||||
abstract class ChatRepository {
|
abstract class ChatRepository {
|
||||||
Future<Result<List<Chat>>> getChats();
|
Future<Result<List<Chat>>> getChats({String? currentUserId});
|
||||||
Future<Result<Chat>> getChatById(String chatId);
|
Future<Result<Chat>> getChatById(String chatId);
|
||||||
Future<Result<void>> createChat(String title, List<String> participantIds);
|
Future<Result<Chat>> createPersonalChat(String userId);
|
||||||
Future<Result<void>> sendMessage(String chatId, Message message);
|
Future<Result<Chat>> createGroupChat(String name, List<String> memberIds);
|
||||||
Future<Result<List<Message>>> getMessages(String chatId, {int? limit, String? lastMessageId});
|
Future<Result<Chat>> getOrCreateFavorites();
|
||||||
Future<Result<void>> deleteChat(String chatId);
|
Future<Result<Message>> sendMessage(String chatId, String content, {String? type});
|
||||||
Future<Result<void>> updateChat(String chatId, String title);
|
Future<Result<List<Message>>> getMessages(String chatId, {String? cursor});
|
||||||
|
Future<Result<void>> togglePin(String chatId);
|
||||||
|
Future<Result<void>> clearChat(String chatId);
|
||||||
|
|
||||||
|
Stream<Message> get messageStream;
|
||||||
|
Future<void> initSignalR();
|
||||||
|
Future<void> disposeSignalR();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,92 @@
|
|||||||
|
import 'dart:async';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import '../../domain/entities/chat.dart';
|
||||||
|
import '../../domain/entities/message.dart';
|
||||||
|
import '../../domain/repositories/chat_repository.dart';
|
||||||
import 'chat_event.dart';
|
import 'chat_event.dart';
|
||||||
import 'chat_state.dart';
|
import 'chat_state.dart';
|
||||||
|
|
||||||
class ChatBloc extends Bloc<ChatEvent, ChatState> {
|
class ChatBloc extends Bloc<ChatEvent, ChatState> {
|
||||||
ChatBloc() : super(const ChatState.initial()) {
|
final ChatRepository chatRepository;
|
||||||
|
StreamSubscription? _messageSubscription;
|
||||||
|
|
||||||
|
ChatBloc({required this.chatRepository}) : super(const ChatState.initial()) {
|
||||||
on<ChatEventStarted>(_onStarted);
|
on<ChatEventStarted>(_onStarted);
|
||||||
on<ChatEventChatsLoaded>(_onChatsLoaded);
|
on<ChatEventChatsLoaded>(_onChatsLoaded);
|
||||||
on<ChatEventChatSelected>(_onChatSelected);
|
on<ChatEventChatSelected>(_onChatSelected);
|
||||||
on<ChatEventMessagesRequested>(_onMessagesRequested);
|
on<ChatEventMessagesRequested>(_onMessagesRequested);
|
||||||
on<ChatEventMessageSent>(_onMessageSent);
|
on<ChatEventMessageSent>(_onMessageSent);
|
||||||
|
on<ChatEventFavoritesRequested>(_onFavoritesRequested);
|
||||||
|
|
||||||
|
_messageSubscription = chatRepository.messageStream.listen((message) {
|
||||||
|
// Handle real-time messages
|
||||||
|
add(ChatEvent.messagesRequested(message.chatId));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onStarted(ChatEventStarted event, emit) async {
|
Future<void> _onStarted(ChatEventStarted event, Emitter<ChatState> emit) async {
|
||||||
|
// Start SignalR in background
|
||||||
|
chatRepository.initSignalR().catchError((e) {
|
||||||
|
// Log or handle SignalR init error
|
||||||
|
});
|
||||||
|
// Immediately trigger chats loading
|
||||||
|
add(const ChatEvent.chatsLoaded());
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onChatsLoaded(ChatEventChatsLoaded event, Emitter<ChatState> emit) async {
|
||||||
emit(const ChatState.loading());
|
emit(const ChatState.loading());
|
||||||
emit(const ChatState.chatsLoaded([]));
|
final result = await chatRepository.getChats(currentUserId: event.currentUserId);
|
||||||
|
result.fold(
|
||||||
|
(error) => emit(ChatState.error(error.message ?? 'Failed to load chats')),
|
||||||
|
(chats) => emit(ChatState.chatsLoaded(chats)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onChatsLoaded(ChatEventChatsLoaded event, emit) async {}
|
Future<void> _onChatSelected(ChatEventChatSelected event, Emitter<ChatState> emit) async {
|
||||||
Future<void> _onChatSelected(ChatEventChatSelected event, emit) async {}
|
emit(const ChatState.loading());
|
||||||
Future<void> _onMessagesRequested(ChatEventMessagesRequested event, emit) async {}
|
final chatResult = await chatRepository.getChatById(event.chatId);
|
||||||
Future<void> _onMessageSent(ChatEventMessageSent event, emit) async {}
|
final messagesResult = await chatRepository.getMessages(event.chatId);
|
||||||
|
|
||||||
|
chatResult.fold(
|
||||||
|
(error) => emit(ChatState.error(error.message ?? 'Failed to load chat')),
|
||||||
|
(chat) {
|
||||||
|
messagesResult.fold(
|
||||||
|
(error) => emit(ChatState.chatSelected(chat, [])),
|
||||||
|
(messages) => emit(ChatState.chatSelected(chat, messages)),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onMessagesRequested(ChatEventMessagesRequested event, Emitter<ChatState> emit) async {
|
||||||
|
final result = await chatRepository.getMessages(event.chatId);
|
||||||
|
result.fold(
|
||||||
|
(error) => emit(ChatState.error(error.message ?? 'Failed to load messages')),
|
||||||
|
(messages) => emit(ChatState.messagesLoaded(messages)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onMessageSent(ChatEventMessageSent event, Emitter<ChatState> emit) async {
|
||||||
|
final result = await chatRepository.sendMessage(event.chatId, event.content);
|
||||||
|
result.fold(
|
||||||
|
(error) => emit(ChatState.error(error.message ?? 'Failed to send message')),
|
||||||
|
(_) => add(ChatEvent.messagesRequested(event.chatId)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onFavoritesRequested(ChatEventFavoritesRequested event, Emitter<ChatState> emit) async {
|
||||||
|
emit(const ChatState.loading());
|
||||||
|
final result = await chatRepository.getOrCreateFavorites();
|
||||||
|
result.fold(
|
||||||
|
(error) => emit(ChatState.error(error.message ?? 'Failed to open Favorites')),
|
||||||
|
(chat) => add(ChatEvent.chatSelected(chat.id)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() {
|
||||||
|
_messageSubscription?.cancel();
|
||||||
|
chatRepository.disposeSignalR();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,9 @@ part 'chat_event.freezed.dart';
|
|||||||
@freezed
|
@freezed
|
||||||
class ChatEvent with _$ChatEvent {
|
class ChatEvent with _$ChatEvent {
|
||||||
const factory ChatEvent.started() = ChatEventStarted;
|
const factory ChatEvent.started() = ChatEventStarted;
|
||||||
const factory ChatEvent.chatsLoaded() = ChatEventChatsLoaded;
|
const factory ChatEvent.chatsLoaded({String? currentUserId}) = ChatEventChatsLoaded;
|
||||||
const factory ChatEvent.chatSelected(String chatId) = ChatEventChatSelected;
|
const factory ChatEvent.chatSelected(String chatId) = ChatEventChatSelected;
|
||||||
const factory ChatEvent.messagesRequested(String chatId, {String? lastMessageId}) = ChatEventMessagesRequested;
|
const factory ChatEvent.messagesRequested(String chatId, {String? cursor}) = ChatEventMessagesRequested;
|
||||||
const factory ChatEvent.messageSent(String chatId, String content) = ChatEventMessageSent;
|
const factory ChatEvent.messageSent(String chatId, String content) = ChatEventMessageSent;
|
||||||
const factory ChatEvent.messageRead(String chatId, String messageId) = ChatEventMessageRead;
|
const factory ChatEvent.favoritesRequested() = ChatEventFavoritesRequested;
|
||||||
const factory ChatEvent.chatCreated(String title, List<String> participantIds) = ChatEventChatCreated;
|
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,6 @@
|
|||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import '../../domain/entities/chat.dart';
|
||||||
|
import '../../domain/entities/message.dart';
|
||||||
|
|
||||||
part 'chat_state.freezed.dart';
|
part 'chat_state.freezed.dart';
|
||||||
|
|
||||||
@@ -6,9 +8,8 @@ part 'chat_state.freezed.dart';
|
|||||||
class ChatState with _$ChatState {
|
class ChatState with _$ChatState {
|
||||||
const factory ChatState.initial() = ChatInitial;
|
const factory ChatState.initial() = ChatInitial;
|
||||||
const factory ChatState.loading() = ChatLoading;
|
const factory ChatState.loading() = ChatLoading;
|
||||||
const factory ChatState.chatsLoaded(List<dynamic> chats) = _ChatsLoaded;
|
const factory ChatState.chatsLoaded(List<Chat> chats) = _ChatsLoaded;
|
||||||
const factory ChatState.chatSelected(String chat, List<dynamic> messages) = _ChatSelected;
|
const factory ChatState.chatSelected(Chat chat, List<Message> messages) = _ChatSelected;
|
||||||
const factory ChatState.messagesLoaded(List<dynamic> messages) = _MessagesLoaded;
|
const factory ChatState.messagesLoaded(List<Message> messages) = _MessagesLoaded;
|
||||||
const factory ChatState.messageSent() = _MessageSent;
|
|
||||||
const factory ChatState.error(String message) = ChatError;
|
const factory ChatState.error(String message) = ChatError;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,10 +20,9 @@ mixin _$ChatState {
|
|||||||
TResult when<TResult extends Object?>({
|
TResult when<TResult extends Object?>({
|
||||||
required TResult Function() initial,
|
required TResult Function() initial,
|
||||||
required TResult Function() loading,
|
required TResult Function() loading,
|
||||||
required TResult Function(List<dynamic> chats) chatsLoaded,
|
required TResult Function(List<Chat> chats) chatsLoaded,
|
||||||
required TResult Function(String chat, List<dynamic> messages) chatSelected,
|
required TResult Function(Chat chat, List<Message> messages) chatSelected,
|
||||||
required TResult Function(List<dynamic> messages) messagesLoaded,
|
required TResult Function(List<Message> messages) messagesLoaded,
|
||||||
required TResult Function() messageSent,
|
|
||||||
required TResult Function(String message) error,
|
required TResult Function(String message) error,
|
||||||
}) =>
|
}) =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
@@ -31,10 +30,9 @@ mixin _$ChatState {
|
|||||||
TResult? whenOrNull<TResult extends Object?>({
|
TResult? whenOrNull<TResult extends Object?>({
|
||||||
TResult? Function()? initial,
|
TResult? Function()? initial,
|
||||||
TResult? Function()? loading,
|
TResult? Function()? loading,
|
||||||
TResult? Function(List<dynamic> chats)? chatsLoaded,
|
TResult? Function(List<Chat> chats)? chatsLoaded,
|
||||||
TResult? Function(String chat, List<dynamic> messages)? chatSelected,
|
TResult? Function(Chat chat, List<Message> messages)? chatSelected,
|
||||||
TResult? Function(List<dynamic> messages)? messagesLoaded,
|
TResult? Function(List<Message> messages)? messagesLoaded,
|
||||||
TResult? Function()? messageSent,
|
|
||||||
TResult? Function(String message)? error,
|
TResult? Function(String message)? error,
|
||||||
}) =>
|
}) =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
@@ -42,10 +40,9 @@ mixin _$ChatState {
|
|||||||
TResult maybeWhen<TResult extends Object?>({
|
TResult maybeWhen<TResult extends Object?>({
|
||||||
TResult Function()? initial,
|
TResult Function()? initial,
|
||||||
TResult Function()? loading,
|
TResult Function()? loading,
|
||||||
TResult Function(List<dynamic> chats)? chatsLoaded,
|
TResult Function(List<Chat> chats)? chatsLoaded,
|
||||||
TResult Function(String chat, List<dynamic> messages)? chatSelected,
|
TResult Function(Chat chat, List<Message> messages)? chatSelected,
|
||||||
TResult Function(List<dynamic> messages)? messagesLoaded,
|
TResult Function(List<Message> messages)? messagesLoaded,
|
||||||
TResult Function()? messageSent,
|
|
||||||
TResult Function(String message)? error,
|
TResult Function(String message)? error,
|
||||||
required TResult orElse(),
|
required TResult orElse(),
|
||||||
}) =>
|
}) =>
|
||||||
@@ -57,7 +54,6 @@ mixin _$ChatState {
|
|||||||
required TResult Function(_ChatsLoaded value) chatsLoaded,
|
required TResult Function(_ChatsLoaded value) chatsLoaded,
|
||||||
required TResult Function(_ChatSelected value) chatSelected,
|
required TResult Function(_ChatSelected value) chatSelected,
|
||||||
required TResult Function(_MessagesLoaded value) messagesLoaded,
|
required TResult Function(_MessagesLoaded value) messagesLoaded,
|
||||||
required TResult Function(_MessageSent value) messageSent,
|
|
||||||
required TResult Function(ChatError value) error,
|
required TResult Function(ChatError value) error,
|
||||||
}) =>
|
}) =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
@@ -68,7 +64,6 @@ mixin _$ChatState {
|
|||||||
TResult? Function(_ChatsLoaded value)? chatsLoaded,
|
TResult? Function(_ChatsLoaded value)? chatsLoaded,
|
||||||
TResult? Function(_ChatSelected value)? chatSelected,
|
TResult? Function(_ChatSelected value)? chatSelected,
|
||||||
TResult? Function(_MessagesLoaded value)? messagesLoaded,
|
TResult? Function(_MessagesLoaded value)? messagesLoaded,
|
||||||
TResult? Function(_MessageSent value)? messageSent,
|
|
||||||
TResult? Function(ChatError value)? error,
|
TResult? Function(ChatError value)? error,
|
||||||
}) =>
|
}) =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
@@ -79,7 +74,6 @@ mixin _$ChatState {
|
|||||||
TResult Function(_ChatsLoaded value)? chatsLoaded,
|
TResult Function(_ChatsLoaded value)? chatsLoaded,
|
||||||
TResult Function(_ChatSelected value)? chatSelected,
|
TResult Function(_ChatSelected value)? chatSelected,
|
||||||
TResult Function(_MessagesLoaded value)? messagesLoaded,
|
TResult Function(_MessagesLoaded value)? messagesLoaded,
|
||||||
TResult Function(_MessageSent value)? messageSent,
|
|
||||||
TResult Function(ChatError value)? error,
|
TResult Function(ChatError value)? error,
|
||||||
required TResult orElse(),
|
required TResult orElse(),
|
||||||
}) =>
|
}) =>
|
||||||
@@ -143,10 +137,9 @@ class _$ChatInitialImpl implements ChatInitial {
|
|||||||
TResult when<TResult extends Object?>({
|
TResult when<TResult extends Object?>({
|
||||||
required TResult Function() initial,
|
required TResult Function() initial,
|
||||||
required TResult Function() loading,
|
required TResult Function() loading,
|
||||||
required TResult Function(List<dynamic> chats) chatsLoaded,
|
required TResult Function(List<Chat> chats) chatsLoaded,
|
||||||
required TResult Function(String chat, List<dynamic> messages) chatSelected,
|
required TResult Function(Chat chat, List<Message> messages) chatSelected,
|
||||||
required TResult Function(List<dynamic> messages) messagesLoaded,
|
required TResult Function(List<Message> messages) messagesLoaded,
|
||||||
required TResult Function() messageSent,
|
|
||||||
required TResult Function(String message) error,
|
required TResult Function(String message) error,
|
||||||
}) {
|
}) {
|
||||||
return initial();
|
return initial();
|
||||||
@@ -157,10 +150,9 @@ class _$ChatInitialImpl implements ChatInitial {
|
|||||||
TResult? whenOrNull<TResult extends Object?>({
|
TResult? whenOrNull<TResult extends Object?>({
|
||||||
TResult? Function()? initial,
|
TResult? Function()? initial,
|
||||||
TResult? Function()? loading,
|
TResult? Function()? loading,
|
||||||
TResult? Function(List<dynamic> chats)? chatsLoaded,
|
TResult? Function(List<Chat> chats)? chatsLoaded,
|
||||||
TResult? Function(String chat, List<dynamic> messages)? chatSelected,
|
TResult? Function(Chat chat, List<Message> messages)? chatSelected,
|
||||||
TResult? Function(List<dynamic> messages)? messagesLoaded,
|
TResult? Function(List<Message> messages)? messagesLoaded,
|
||||||
TResult? Function()? messageSent,
|
|
||||||
TResult? Function(String message)? error,
|
TResult? Function(String message)? error,
|
||||||
}) {
|
}) {
|
||||||
return initial?.call();
|
return initial?.call();
|
||||||
@@ -171,10 +163,9 @@ class _$ChatInitialImpl implements ChatInitial {
|
|||||||
TResult maybeWhen<TResult extends Object?>({
|
TResult maybeWhen<TResult extends Object?>({
|
||||||
TResult Function()? initial,
|
TResult Function()? initial,
|
||||||
TResult Function()? loading,
|
TResult Function()? loading,
|
||||||
TResult Function(List<dynamic> chats)? chatsLoaded,
|
TResult Function(List<Chat> chats)? chatsLoaded,
|
||||||
TResult Function(String chat, List<dynamic> messages)? chatSelected,
|
TResult Function(Chat chat, List<Message> messages)? chatSelected,
|
||||||
TResult Function(List<dynamic> messages)? messagesLoaded,
|
TResult Function(List<Message> messages)? messagesLoaded,
|
||||||
TResult Function()? messageSent,
|
|
||||||
TResult Function(String message)? error,
|
TResult Function(String message)? error,
|
||||||
required TResult orElse(),
|
required TResult orElse(),
|
||||||
}) {
|
}) {
|
||||||
@@ -192,7 +183,6 @@ class _$ChatInitialImpl implements ChatInitial {
|
|||||||
required TResult Function(_ChatsLoaded value) chatsLoaded,
|
required TResult Function(_ChatsLoaded value) chatsLoaded,
|
||||||
required TResult Function(_ChatSelected value) chatSelected,
|
required TResult Function(_ChatSelected value) chatSelected,
|
||||||
required TResult Function(_MessagesLoaded value) messagesLoaded,
|
required TResult Function(_MessagesLoaded value) messagesLoaded,
|
||||||
required TResult Function(_MessageSent value) messageSent,
|
|
||||||
required TResult Function(ChatError value) error,
|
required TResult Function(ChatError value) error,
|
||||||
}) {
|
}) {
|
||||||
return initial(this);
|
return initial(this);
|
||||||
@@ -206,7 +196,6 @@ class _$ChatInitialImpl implements ChatInitial {
|
|||||||
TResult? Function(_ChatsLoaded value)? chatsLoaded,
|
TResult? Function(_ChatsLoaded value)? chatsLoaded,
|
||||||
TResult? Function(_ChatSelected value)? chatSelected,
|
TResult? Function(_ChatSelected value)? chatSelected,
|
||||||
TResult? Function(_MessagesLoaded value)? messagesLoaded,
|
TResult? Function(_MessagesLoaded value)? messagesLoaded,
|
||||||
TResult? Function(_MessageSent value)? messageSent,
|
|
||||||
TResult? Function(ChatError value)? error,
|
TResult? Function(ChatError value)? error,
|
||||||
}) {
|
}) {
|
||||||
return initial?.call(this);
|
return initial?.call(this);
|
||||||
@@ -220,7 +209,6 @@ class _$ChatInitialImpl implements ChatInitial {
|
|||||||
TResult Function(_ChatsLoaded value)? chatsLoaded,
|
TResult Function(_ChatsLoaded value)? chatsLoaded,
|
||||||
TResult Function(_ChatSelected value)? chatSelected,
|
TResult Function(_ChatSelected value)? chatSelected,
|
||||||
TResult Function(_MessagesLoaded value)? messagesLoaded,
|
TResult Function(_MessagesLoaded value)? messagesLoaded,
|
||||||
TResult Function(_MessageSent value)? messageSent,
|
|
||||||
TResult Function(ChatError value)? error,
|
TResult Function(ChatError value)? error,
|
||||||
required TResult orElse(),
|
required TResult orElse(),
|
||||||
}) {
|
}) {
|
||||||
@@ -275,10 +263,9 @@ class _$ChatLoadingImpl implements ChatLoading {
|
|||||||
TResult when<TResult extends Object?>({
|
TResult when<TResult extends Object?>({
|
||||||
required TResult Function() initial,
|
required TResult Function() initial,
|
||||||
required TResult Function() loading,
|
required TResult Function() loading,
|
||||||
required TResult Function(List<dynamic> chats) chatsLoaded,
|
required TResult Function(List<Chat> chats) chatsLoaded,
|
||||||
required TResult Function(String chat, List<dynamic> messages) chatSelected,
|
required TResult Function(Chat chat, List<Message> messages) chatSelected,
|
||||||
required TResult Function(List<dynamic> messages) messagesLoaded,
|
required TResult Function(List<Message> messages) messagesLoaded,
|
||||||
required TResult Function() messageSent,
|
|
||||||
required TResult Function(String message) error,
|
required TResult Function(String message) error,
|
||||||
}) {
|
}) {
|
||||||
return loading();
|
return loading();
|
||||||
@@ -289,10 +276,9 @@ class _$ChatLoadingImpl implements ChatLoading {
|
|||||||
TResult? whenOrNull<TResult extends Object?>({
|
TResult? whenOrNull<TResult extends Object?>({
|
||||||
TResult? Function()? initial,
|
TResult? Function()? initial,
|
||||||
TResult? Function()? loading,
|
TResult? Function()? loading,
|
||||||
TResult? Function(List<dynamic> chats)? chatsLoaded,
|
TResult? Function(List<Chat> chats)? chatsLoaded,
|
||||||
TResult? Function(String chat, List<dynamic> messages)? chatSelected,
|
TResult? Function(Chat chat, List<Message> messages)? chatSelected,
|
||||||
TResult? Function(List<dynamic> messages)? messagesLoaded,
|
TResult? Function(List<Message> messages)? messagesLoaded,
|
||||||
TResult? Function()? messageSent,
|
|
||||||
TResult? Function(String message)? error,
|
TResult? Function(String message)? error,
|
||||||
}) {
|
}) {
|
||||||
return loading?.call();
|
return loading?.call();
|
||||||
@@ -303,10 +289,9 @@ class _$ChatLoadingImpl implements ChatLoading {
|
|||||||
TResult maybeWhen<TResult extends Object?>({
|
TResult maybeWhen<TResult extends Object?>({
|
||||||
TResult Function()? initial,
|
TResult Function()? initial,
|
||||||
TResult Function()? loading,
|
TResult Function()? loading,
|
||||||
TResult Function(List<dynamic> chats)? chatsLoaded,
|
TResult Function(List<Chat> chats)? chatsLoaded,
|
||||||
TResult Function(String chat, List<dynamic> messages)? chatSelected,
|
TResult Function(Chat chat, List<Message> messages)? chatSelected,
|
||||||
TResult Function(List<dynamic> messages)? messagesLoaded,
|
TResult Function(List<Message> messages)? messagesLoaded,
|
||||||
TResult Function()? messageSent,
|
|
||||||
TResult Function(String message)? error,
|
TResult Function(String message)? error,
|
||||||
required TResult orElse(),
|
required TResult orElse(),
|
||||||
}) {
|
}) {
|
||||||
@@ -324,7 +309,6 @@ class _$ChatLoadingImpl implements ChatLoading {
|
|||||||
required TResult Function(_ChatsLoaded value) chatsLoaded,
|
required TResult Function(_ChatsLoaded value) chatsLoaded,
|
||||||
required TResult Function(_ChatSelected value) chatSelected,
|
required TResult Function(_ChatSelected value) chatSelected,
|
||||||
required TResult Function(_MessagesLoaded value) messagesLoaded,
|
required TResult Function(_MessagesLoaded value) messagesLoaded,
|
||||||
required TResult Function(_MessageSent value) messageSent,
|
|
||||||
required TResult Function(ChatError value) error,
|
required TResult Function(ChatError value) error,
|
||||||
}) {
|
}) {
|
||||||
return loading(this);
|
return loading(this);
|
||||||
@@ -338,7 +322,6 @@ class _$ChatLoadingImpl implements ChatLoading {
|
|||||||
TResult? Function(_ChatsLoaded value)? chatsLoaded,
|
TResult? Function(_ChatsLoaded value)? chatsLoaded,
|
||||||
TResult? Function(_ChatSelected value)? chatSelected,
|
TResult? Function(_ChatSelected value)? chatSelected,
|
||||||
TResult? Function(_MessagesLoaded value)? messagesLoaded,
|
TResult? Function(_MessagesLoaded value)? messagesLoaded,
|
||||||
TResult? Function(_MessageSent value)? messageSent,
|
|
||||||
TResult? Function(ChatError value)? error,
|
TResult? Function(ChatError value)? error,
|
||||||
}) {
|
}) {
|
||||||
return loading?.call(this);
|
return loading?.call(this);
|
||||||
@@ -352,7 +335,6 @@ class _$ChatLoadingImpl implements ChatLoading {
|
|||||||
TResult Function(_ChatsLoaded value)? chatsLoaded,
|
TResult Function(_ChatsLoaded value)? chatsLoaded,
|
||||||
TResult Function(_ChatSelected value)? chatSelected,
|
TResult Function(_ChatSelected value)? chatSelected,
|
||||||
TResult Function(_MessagesLoaded value)? messagesLoaded,
|
TResult Function(_MessagesLoaded value)? messagesLoaded,
|
||||||
TResult Function(_MessageSent value)? messageSent,
|
|
||||||
TResult Function(ChatError value)? error,
|
TResult Function(ChatError value)? error,
|
||||||
required TResult orElse(),
|
required TResult orElse(),
|
||||||
}) {
|
}) {
|
||||||
@@ -373,7 +355,7 @@ abstract class _$$ChatsLoadedImplCopyWith<$Res> {
|
|||||||
_$ChatsLoadedImpl value, $Res Function(_$ChatsLoadedImpl) then) =
|
_$ChatsLoadedImpl value, $Res Function(_$ChatsLoadedImpl) then) =
|
||||||
__$$ChatsLoadedImplCopyWithImpl<$Res>;
|
__$$ChatsLoadedImplCopyWithImpl<$Res>;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({List<dynamic> chats});
|
$Res call({List<Chat> chats});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@@ -393,7 +375,7 @@ class __$$ChatsLoadedImplCopyWithImpl<$Res>
|
|||||||
null == chats
|
null == chats
|
||||||
? _value._chats
|
? _value._chats
|
||||||
: chats // ignore: cast_nullable_to_non_nullable
|
: chats // ignore: cast_nullable_to_non_nullable
|
||||||
as List<dynamic>,
|
as List<Chat>,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -401,11 +383,11 @@ class __$$ChatsLoadedImplCopyWithImpl<$Res>
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
|
|
||||||
class _$ChatsLoadedImpl implements _ChatsLoaded {
|
class _$ChatsLoadedImpl implements _ChatsLoaded {
|
||||||
const _$ChatsLoadedImpl(final List<dynamic> chats) : _chats = chats;
|
const _$ChatsLoadedImpl(final List<Chat> chats) : _chats = chats;
|
||||||
|
|
||||||
final List<dynamic> _chats;
|
final List<Chat> _chats;
|
||||||
@override
|
@override
|
||||||
List<dynamic> get chats {
|
List<Chat> get chats {
|
||||||
if (_chats is EqualUnmodifiableListView) return _chats;
|
if (_chats is EqualUnmodifiableListView) return _chats;
|
||||||
// ignore: implicit_dynamic_type
|
// ignore: implicit_dynamic_type
|
||||||
return EqualUnmodifiableListView(_chats);
|
return EqualUnmodifiableListView(_chats);
|
||||||
@@ -439,10 +421,9 @@ class _$ChatsLoadedImpl implements _ChatsLoaded {
|
|||||||
TResult when<TResult extends Object?>({
|
TResult when<TResult extends Object?>({
|
||||||
required TResult Function() initial,
|
required TResult Function() initial,
|
||||||
required TResult Function() loading,
|
required TResult Function() loading,
|
||||||
required TResult Function(List<dynamic> chats) chatsLoaded,
|
required TResult Function(List<Chat> chats) chatsLoaded,
|
||||||
required TResult Function(String chat, List<dynamic> messages) chatSelected,
|
required TResult Function(Chat chat, List<Message> messages) chatSelected,
|
||||||
required TResult Function(List<dynamic> messages) messagesLoaded,
|
required TResult Function(List<Message> messages) messagesLoaded,
|
||||||
required TResult Function() messageSent,
|
|
||||||
required TResult Function(String message) error,
|
required TResult Function(String message) error,
|
||||||
}) {
|
}) {
|
||||||
return chatsLoaded(chats);
|
return chatsLoaded(chats);
|
||||||
@@ -453,10 +434,9 @@ class _$ChatsLoadedImpl implements _ChatsLoaded {
|
|||||||
TResult? whenOrNull<TResult extends Object?>({
|
TResult? whenOrNull<TResult extends Object?>({
|
||||||
TResult? Function()? initial,
|
TResult? Function()? initial,
|
||||||
TResult? Function()? loading,
|
TResult? Function()? loading,
|
||||||
TResult? Function(List<dynamic> chats)? chatsLoaded,
|
TResult? Function(List<Chat> chats)? chatsLoaded,
|
||||||
TResult? Function(String chat, List<dynamic> messages)? chatSelected,
|
TResult? Function(Chat chat, List<Message> messages)? chatSelected,
|
||||||
TResult? Function(List<dynamic> messages)? messagesLoaded,
|
TResult? Function(List<Message> messages)? messagesLoaded,
|
||||||
TResult? Function()? messageSent,
|
|
||||||
TResult? Function(String message)? error,
|
TResult? Function(String message)? error,
|
||||||
}) {
|
}) {
|
||||||
return chatsLoaded?.call(chats);
|
return chatsLoaded?.call(chats);
|
||||||
@@ -467,10 +447,9 @@ class _$ChatsLoadedImpl implements _ChatsLoaded {
|
|||||||
TResult maybeWhen<TResult extends Object?>({
|
TResult maybeWhen<TResult extends Object?>({
|
||||||
TResult Function()? initial,
|
TResult Function()? initial,
|
||||||
TResult Function()? loading,
|
TResult Function()? loading,
|
||||||
TResult Function(List<dynamic> chats)? chatsLoaded,
|
TResult Function(List<Chat> chats)? chatsLoaded,
|
||||||
TResult Function(String chat, List<dynamic> messages)? chatSelected,
|
TResult Function(Chat chat, List<Message> messages)? chatSelected,
|
||||||
TResult Function(List<dynamic> messages)? messagesLoaded,
|
TResult Function(List<Message> messages)? messagesLoaded,
|
||||||
TResult Function()? messageSent,
|
|
||||||
TResult Function(String message)? error,
|
TResult Function(String message)? error,
|
||||||
required TResult orElse(),
|
required TResult orElse(),
|
||||||
}) {
|
}) {
|
||||||
@@ -488,7 +467,6 @@ class _$ChatsLoadedImpl implements _ChatsLoaded {
|
|||||||
required TResult Function(_ChatsLoaded value) chatsLoaded,
|
required TResult Function(_ChatsLoaded value) chatsLoaded,
|
||||||
required TResult Function(_ChatSelected value) chatSelected,
|
required TResult Function(_ChatSelected value) chatSelected,
|
||||||
required TResult Function(_MessagesLoaded value) messagesLoaded,
|
required TResult Function(_MessagesLoaded value) messagesLoaded,
|
||||||
required TResult Function(_MessageSent value) messageSent,
|
|
||||||
required TResult Function(ChatError value) error,
|
required TResult Function(ChatError value) error,
|
||||||
}) {
|
}) {
|
||||||
return chatsLoaded(this);
|
return chatsLoaded(this);
|
||||||
@@ -502,7 +480,6 @@ class _$ChatsLoadedImpl implements _ChatsLoaded {
|
|||||||
TResult? Function(_ChatsLoaded value)? chatsLoaded,
|
TResult? Function(_ChatsLoaded value)? chatsLoaded,
|
||||||
TResult? Function(_ChatSelected value)? chatSelected,
|
TResult? Function(_ChatSelected value)? chatSelected,
|
||||||
TResult? Function(_MessagesLoaded value)? messagesLoaded,
|
TResult? Function(_MessagesLoaded value)? messagesLoaded,
|
||||||
TResult? Function(_MessageSent value)? messageSent,
|
|
||||||
TResult? Function(ChatError value)? error,
|
TResult? Function(ChatError value)? error,
|
||||||
}) {
|
}) {
|
||||||
return chatsLoaded?.call(this);
|
return chatsLoaded?.call(this);
|
||||||
@@ -516,7 +493,6 @@ class _$ChatsLoadedImpl implements _ChatsLoaded {
|
|||||||
TResult Function(_ChatsLoaded value)? chatsLoaded,
|
TResult Function(_ChatsLoaded value)? chatsLoaded,
|
||||||
TResult Function(_ChatSelected value)? chatSelected,
|
TResult Function(_ChatSelected value)? chatSelected,
|
||||||
TResult Function(_MessagesLoaded value)? messagesLoaded,
|
TResult Function(_MessagesLoaded value)? messagesLoaded,
|
||||||
TResult Function(_MessageSent value)? messageSent,
|
|
||||||
TResult Function(ChatError value)? error,
|
TResult Function(ChatError value)? error,
|
||||||
required TResult orElse(),
|
required TResult orElse(),
|
||||||
}) {
|
}) {
|
||||||
@@ -528,9 +504,9 @@ class _$ChatsLoadedImpl implements _ChatsLoaded {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class _ChatsLoaded implements ChatState {
|
abstract class _ChatsLoaded implements ChatState {
|
||||||
const factory _ChatsLoaded(final List<dynamic> chats) = _$ChatsLoadedImpl;
|
const factory _ChatsLoaded(final List<Chat> chats) = _$ChatsLoadedImpl;
|
||||||
|
|
||||||
List<dynamic> get chats;
|
List<Chat> get chats;
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
_$$ChatsLoadedImplCopyWith<_$ChatsLoadedImpl> get copyWith =>
|
_$$ChatsLoadedImplCopyWith<_$ChatsLoadedImpl> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
@@ -542,7 +518,9 @@ abstract class _$$ChatSelectedImplCopyWith<$Res> {
|
|||||||
_$ChatSelectedImpl value, $Res Function(_$ChatSelectedImpl) then) =
|
_$ChatSelectedImpl value, $Res Function(_$ChatSelectedImpl) then) =
|
||||||
__$$ChatSelectedImplCopyWithImpl<$Res>;
|
__$$ChatSelectedImplCopyWithImpl<$Res>;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({String chat, List<dynamic> messages});
|
$Res call({Chat chat, List<Message> messages});
|
||||||
|
|
||||||
|
$ChatCopyWith<$Res> get chat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@@ -563,26 +541,34 @@ class __$$ChatSelectedImplCopyWithImpl<$Res>
|
|||||||
null == chat
|
null == chat
|
||||||
? _value.chat
|
? _value.chat
|
||||||
: chat // ignore: cast_nullable_to_non_nullable
|
: chat // ignore: cast_nullable_to_non_nullable
|
||||||
as String,
|
as Chat,
|
||||||
null == messages
|
null == messages
|
||||||
? _value._messages
|
? _value._messages
|
||||||
: messages // ignore: cast_nullable_to_non_nullable
|
: messages // ignore: cast_nullable_to_non_nullable
|
||||||
as List<dynamic>,
|
as List<Message>,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$ChatCopyWith<$Res> get chat {
|
||||||
|
return $ChatCopyWith<$Res>(_value.chat, (value) {
|
||||||
|
return _then(_value.copyWith(chat: value));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
|
|
||||||
class _$ChatSelectedImpl implements _ChatSelected {
|
class _$ChatSelectedImpl implements _ChatSelected {
|
||||||
const _$ChatSelectedImpl(this.chat, final List<dynamic> messages)
|
const _$ChatSelectedImpl(this.chat, final List<Message> messages)
|
||||||
: _messages = messages;
|
: _messages = messages;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final String chat;
|
final Chat chat;
|
||||||
final List<dynamic> _messages;
|
final List<Message> _messages;
|
||||||
@override
|
@override
|
||||||
List<dynamic> get messages {
|
List<Message> get messages {
|
||||||
if (_messages is EqualUnmodifiableListView) return _messages;
|
if (_messages is EqualUnmodifiableListView) return _messages;
|
||||||
// ignore: implicit_dynamic_type
|
// ignore: implicit_dynamic_type
|
||||||
return EqualUnmodifiableListView(_messages);
|
return EqualUnmodifiableListView(_messages);
|
||||||
@@ -617,10 +603,9 @@ class _$ChatSelectedImpl implements _ChatSelected {
|
|||||||
TResult when<TResult extends Object?>({
|
TResult when<TResult extends Object?>({
|
||||||
required TResult Function() initial,
|
required TResult Function() initial,
|
||||||
required TResult Function() loading,
|
required TResult Function() loading,
|
||||||
required TResult Function(List<dynamic> chats) chatsLoaded,
|
required TResult Function(List<Chat> chats) chatsLoaded,
|
||||||
required TResult Function(String chat, List<dynamic> messages) chatSelected,
|
required TResult Function(Chat chat, List<Message> messages) chatSelected,
|
||||||
required TResult Function(List<dynamic> messages) messagesLoaded,
|
required TResult Function(List<Message> messages) messagesLoaded,
|
||||||
required TResult Function() messageSent,
|
|
||||||
required TResult Function(String message) error,
|
required TResult Function(String message) error,
|
||||||
}) {
|
}) {
|
||||||
return chatSelected(chat, messages);
|
return chatSelected(chat, messages);
|
||||||
@@ -631,10 +616,9 @@ class _$ChatSelectedImpl implements _ChatSelected {
|
|||||||
TResult? whenOrNull<TResult extends Object?>({
|
TResult? whenOrNull<TResult extends Object?>({
|
||||||
TResult? Function()? initial,
|
TResult? Function()? initial,
|
||||||
TResult? Function()? loading,
|
TResult? Function()? loading,
|
||||||
TResult? Function(List<dynamic> chats)? chatsLoaded,
|
TResult? Function(List<Chat> chats)? chatsLoaded,
|
||||||
TResult? Function(String chat, List<dynamic> messages)? chatSelected,
|
TResult? Function(Chat chat, List<Message> messages)? chatSelected,
|
||||||
TResult? Function(List<dynamic> messages)? messagesLoaded,
|
TResult? Function(List<Message> messages)? messagesLoaded,
|
||||||
TResult? Function()? messageSent,
|
|
||||||
TResult? Function(String message)? error,
|
TResult? Function(String message)? error,
|
||||||
}) {
|
}) {
|
||||||
return chatSelected?.call(chat, messages);
|
return chatSelected?.call(chat, messages);
|
||||||
@@ -645,10 +629,9 @@ class _$ChatSelectedImpl implements _ChatSelected {
|
|||||||
TResult maybeWhen<TResult extends Object?>({
|
TResult maybeWhen<TResult extends Object?>({
|
||||||
TResult Function()? initial,
|
TResult Function()? initial,
|
||||||
TResult Function()? loading,
|
TResult Function()? loading,
|
||||||
TResult Function(List<dynamic> chats)? chatsLoaded,
|
TResult Function(List<Chat> chats)? chatsLoaded,
|
||||||
TResult Function(String chat, List<dynamic> messages)? chatSelected,
|
TResult Function(Chat chat, List<Message> messages)? chatSelected,
|
||||||
TResult Function(List<dynamic> messages)? messagesLoaded,
|
TResult Function(List<Message> messages)? messagesLoaded,
|
||||||
TResult Function()? messageSent,
|
|
||||||
TResult Function(String message)? error,
|
TResult Function(String message)? error,
|
||||||
required TResult orElse(),
|
required TResult orElse(),
|
||||||
}) {
|
}) {
|
||||||
@@ -666,7 +649,6 @@ class _$ChatSelectedImpl implements _ChatSelected {
|
|||||||
required TResult Function(_ChatsLoaded value) chatsLoaded,
|
required TResult Function(_ChatsLoaded value) chatsLoaded,
|
||||||
required TResult Function(_ChatSelected value) chatSelected,
|
required TResult Function(_ChatSelected value) chatSelected,
|
||||||
required TResult Function(_MessagesLoaded value) messagesLoaded,
|
required TResult Function(_MessagesLoaded value) messagesLoaded,
|
||||||
required TResult Function(_MessageSent value) messageSent,
|
|
||||||
required TResult Function(ChatError value) error,
|
required TResult Function(ChatError value) error,
|
||||||
}) {
|
}) {
|
||||||
return chatSelected(this);
|
return chatSelected(this);
|
||||||
@@ -680,7 +662,6 @@ class _$ChatSelectedImpl implements _ChatSelected {
|
|||||||
TResult? Function(_ChatsLoaded value)? chatsLoaded,
|
TResult? Function(_ChatsLoaded value)? chatsLoaded,
|
||||||
TResult? Function(_ChatSelected value)? chatSelected,
|
TResult? Function(_ChatSelected value)? chatSelected,
|
||||||
TResult? Function(_MessagesLoaded value)? messagesLoaded,
|
TResult? Function(_MessagesLoaded value)? messagesLoaded,
|
||||||
TResult? Function(_MessageSent value)? messageSent,
|
|
||||||
TResult? Function(ChatError value)? error,
|
TResult? Function(ChatError value)? error,
|
||||||
}) {
|
}) {
|
||||||
return chatSelected?.call(this);
|
return chatSelected?.call(this);
|
||||||
@@ -694,7 +675,6 @@ class _$ChatSelectedImpl implements _ChatSelected {
|
|||||||
TResult Function(_ChatsLoaded value)? chatsLoaded,
|
TResult Function(_ChatsLoaded value)? chatsLoaded,
|
||||||
TResult Function(_ChatSelected value)? chatSelected,
|
TResult Function(_ChatSelected value)? chatSelected,
|
||||||
TResult Function(_MessagesLoaded value)? messagesLoaded,
|
TResult Function(_MessagesLoaded value)? messagesLoaded,
|
||||||
TResult Function(_MessageSent value)? messageSent,
|
|
||||||
TResult Function(ChatError value)? error,
|
TResult Function(ChatError value)? error,
|
||||||
required TResult orElse(),
|
required TResult orElse(),
|
||||||
}) {
|
}) {
|
||||||
@@ -706,11 +686,11 @@ class _$ChatSelectedImpl implements _ChatSelected {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class _ChatSelected implements ChatState {
|
abstract class _ChatSelected implements ChatState {
|
||||||
const factory _ChatSelected(final String chat, final List<dynamic> messages) =
|
const factory _ChatSelected(final Chat chat, final List<Message> messages) =
|
||||||
_$ChatSelectedImpl;
|
_$ChatSelectedImpl;
|
||||||
|
|
||||||
String get chat;
|
Chat get chat;
|
||||||
List<dynamic> get messages;
|
List<Message> get messages;
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
_$$ChatSelectedImplCopyWith<_$ChatSelectedImpl> get copyWith =>
|
_$$ChatSelectedImplCopyWith<_$ChatSelectedImpl> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
@@ -722,7 +702,7 @@ abstract class _$$MessagesLoadedImplCopyWith<$Res> {
|
|||||||
$Res Function(_$MessagesLoadedImpl) then) =
|
$Res Function(_$MessagesLoadedImpl) then) =
|
||||||
__$$MessagesLoadedImplCopyWithImpl<$Res>;
|
__$$MessagesLoadedImplCopyWithImpl<$Res>;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({List<dynamic> messages});
|
$Res call({List<Message> messages});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@@ -742,7 +722,7 @@ class __$$MessagesLoadedImplCopyWithImpl<$Res>
|
|||||||
null == messages
|
null == messages
|
||||||
? _value._messages
|
? _value._messages
|
||||||
: messages // ignore: cast_nullable_to_non_nullable
|
: messages // ignore: cast_nullable_to_non_nullable
|
||||||
as List<dynamic>,
|
as List<Message>,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -750,12 +730,12 @@ class __$$MessagesLoadedImplCopyWithImpl<$Res>
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
|
|
||||||
class _$MessagesLoadedImpl implements _MessagesLoaded {
|
class _$MessagesLoadedImpl implements _MessagesLoaded {
|
||||||
const _$MessagesLoadedImpl(final List<dynamic> messages)
|
const _$MessagesLoadedImpl(final List<Message> messages)
|
||||||
: _messages = messages;
|
: _messages = messages;
|
||||||
|
|
||||||
final List<dynamic> _messages;
|
final List<Message> _messages;
|
||||||
@override
|
@override
|
||||||
List<dynamic> get messages {
|
List<Message> get messages {
|
||||||
if (_messages is EqualUnmodifiableListView) return _messages;
|
if (_messages is EqualUnmodifiableListView) return _messages;
|
||||||
// ignore: implicit_dynamic_type
|
// ignore: implicit_dynamic_type
|
||||||
return EqualUnmodifiableListView(_messages);
|
return EqualUnmodifiableListView(_messages);
|
||||||
@@ -790,10 +770,9 @@ class _$MessagesLoadedImpl implements _MessagesLoaded {
|
|||||||
TResult when<TResult extends Object?>({
|
TResult when<TResult extends Object?>({
|
||||||
required TResult Function() initial,
|
required TResult Function() initial,
|
||||||
required TResult Function() loading,
|
required TResult Function() loading,
|
||||||
required TResult Function(List<dynamic> chats) chatsLoaded,
|
required TResult Function(List<Chat> chats) chatsLoaded,
|
||||||
required TResult Function(String chat, List<dynamic> messages) chatSelected,
|
required TResult Function(Chat chat, List<Message> messages) chatSelected,
|
||||||
required TResult Function(List<dynamic> messages) messagesLoaded,
|
required TResult Function(List<Message> messages) messagesLoaded,
|
||||||
required TResult Function() messageSent,
|
|
||||||
required TResult Function(String message) error,
|
required TResult Function(String message) error,
|
||||||
}) {
|
}) {
|
||||||
return messagesLoaded(messages);
|
return messagesLoaded(messages);
|
||||||
@@ -804,10 +783,9 @@ class _$MessagesLoadedImpl implements _MessagesLoaded {
|
|||||||
TResult? whenOrNull<TResult extends Object?>({
|
TResult? whenOrNull<TResult extends Object?>({
|
||||||
TResult? Function()? initial,
|
TResult? Function()? initial,
|
||||||
TResult? Function()? loading,
|
TResult? Function()? loading,
|
||||||
TResult? Function(List<dynamic> chats)? chatsLoaded,
|
TResult? Function(List<Chat> chats)? chatsLoaded,
|
||||||
TResult? Function(String chat, List<dynamic> messages)? chatSelected,
|
TResult? Function(Chat chat, List<Message> messages)? chatSelected,
|
||||||
TResult? Function(List<dynamic> messages)? messagesLoaded,
|
TResult? Function(List<Message> messages)? messagesLoaded,
|
||||||
TResult? Function()? messageSent,
|
|
||||||
TResult? Function(String message)? error,
|
TResult? Function(String message)? error,
|
||||||
}) {
|
}) {
|
||||||
return messagesLoaded?.call(messages);
|
return messagesLoaded?.call(messages);
|
||||||
@@ -818,10 +796,9 @@ class _$MessagesLoadedImpl implements _MessagesLoaded {
|
|||||||
TResult maybeWhen<TResult extends Object?>({
|
TResult maybeWhen<TResult extends Object?>({
|
||||||
TResult Function()? initial,
|
TResult Function()? initial,
|
||||||
TResult Function()? loading,
|
TResult Function()? loading,
|
||||||
TResult Function(List<dynamic> chats)? chatsLoaded,
|
TResult Function(List<Chat> chats)? chatsLoaded,
|
||||||
TResult Function(String chat, List<dynamic> messages)? chatSelected,
|
TResult Function(Chat chat, List<Message> messages)? chatSelected,
|
||||||
TResult Function(List<dynamic> messages)? messagesLoaded,
|
TResult Function(List<Message> messages)? messagesLoaded,
|
||||||
TResult Function()? messageSent,
|
|
||||||
TResult Function(String message)? error,
|
TResult Function(String message)? error,
|
||||||
required TResult orElse(),
|
required TResult orElse(),
|
||||||
}) {
|
}) {
|
||||||
@@ -839,7 +816,6 @@ class _$MessagesLoadedImpl implements _MessagesLoaded {
|
|||||||
required TResult Function(_ChatsLoaded value) chatsLoaded,
|
required TResult Function(_ChatsLoaded value) chatsLoaded,
|
||||||
required TResult Function(_ChatSelected value) chatSelected,
|
required TResult Function(_ChatSelected value) chatSelected,
|
||||||
required TResult Function(_MessagesLoaded value) messagesLoaded,
|
required TResult Function(_MessagesLoaded value) messagesLoaded,
|
||||||
required TResult Function(_MessageSent value) messageSent,
|
|
||||||
required TResult Function(ChatError value) error,
|
required TResult Function(ChatError value) error,
|
||||||
}) {
|
}) {
|
||||||
return messagesLoaded(this);
|
return messagesLoaded(this);
|
||||||
@@ -853,7 +829,6 @@ class _$MessagesLoadedImpl implements _MessagesLoaded {
|
|||||||
TResult? Function(_ChatsLoaded value)? chatsLoaded,
|
TResult? Function(_ChatsLoaded value)? chatsLoaded,
|
||||||
TResult? Function(_ChatSelected value)? chatSelected,
|
TResult? Function(_ChatSelected value)? chatSelected,
|
||||||
TResult? Function(_MessagesLoaded value)? messagesLoaded,
|
TResult? Function(_MessagesLoaded value)? messagesLoaded,
|
||||||
TResult? Function(_MessageSent value)? messageSent,
|
|
||||||
TResult? Function(ChatError value)? error,
|
TResult? Function(ChatError value)? error,
|
||||||
}) {
|
}) {
|
||||||
return messagesLoaded?.call(this);
|
return messagesLoaded?.call(this);
|
||||||
@@ -867,7 +842,6 @@ class _$MessagesLoadedImpl implements _MessagesLoaded {
|
|||||||
TResult Function(_ChatsLoaded value)? chatsLoaded,
|
TResult Function(_ChatsLoaded value)? chatsLoaded,
|
||||||
TResult Function(_ChatSelected value)? chatSelected,
|
TResult Function(_ChatSelected value)? chatSelected,
|
||||||
TResult Function(_MessagesLoaded value)? messagesLoaded,
|
TResult Function(_MessagesLoaded value)? messagesLoaded,
|
||||||
TResult Function(_MessageSent value)? messageSent,
|
|
||||||
TResult Function(ChatError value)? error,
|
TResult Function(ChatError value)? error,
|
||||||
required TResult orElse(),
|
required TResult orElse(),
|
||||||
}) {
|
}) {
|
||||||
@@ -879,147 +853,15 @@ class _$MessagesLoadedImpl implements _MessagesLoaded {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class _MessagesLoaded implements ChatState {
|
abstract class _MessagesLoaded implements ChatState {
|
||||||
const factory _MessagesLoaded(final List<dynamic> messages) =
|
const factory _MessagesLoaded(final List<Message> messages) =
|
||||||
_$MessagesLoadedImpl;
|
_$MessagesLoadedImpl;
|
||||||
|
|
||||||
List<dynamic> get messages;
|
List<Message> get messages;
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
_$$MessagesLoadedImplCopyWith<_$MessagesLoadedImpl> get copyWith =>
|
_$$MessagesLoadedImplCopyWith<_$MessagesLoadedImpl> get copyWith =>
|
||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract class _$$MessageSentImplCopyWith<$Res> {
|
|
||||||
factory _$$MessageSentImplCopyWith(
|
|
||||||
_$MessageSentImpl value, $Res Function(_$MessageSentImpl) then) =
|
|
||||||
__$$MessageSentImplCopyWithImpl<$Res>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
class __$$MessageSentImplCopyWithImpl<$Res>
|
|
||||||
extends _$ChatStateCopyWithImpl<$Res, _$MessageSentImpl>
|
|
||||||
implements _$$MessageSentImplCopyWith<$Res> {
|
|
||||||
__$$MessageSentImplCopyWithImpl(
|
|
||||||
_$MessageSentImpl _value, $Res Function(_$MessageSentImpl) _then)
|
|
||||||
: super(_value, _then);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
|
|
||||||
class _$MessageSentImpl implements _MessageSent {
|
|
||||||
const _$MessageSentImpl();
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'ChatState.messageSent()';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) ||
|
|
||||||
(other.runtimeType == runtimeType && other is _$MessageSentImpl);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => runtimeType.hashCode;
|
|
||||||
|
|
||||||
@override
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult when<TResult extends Object?>({
|
|
||||||
required TResult Function() initial,
|
|
||||||
required TResult Function() loading,
|
|
||||||
required TResult Function(List<dynamic> chats) chatsLoaded,
|
|
||||||
required TResult Function(String chat, List<dynamic> messages) chatSelected,
|
|
||||||
required TResult Function(List<dynamic> messages) messagesLoaded,
|
|
||||||
required TResult Function() messageSent,
|
|
||||||
required TResult Function(String message) error,
|
|
||||||
}) {
|
|
||||||
return messageSent();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult? whenOrNull<TResult extends Object?>({
|
|
||||||
TResult? Function()? initial,
|
|
||||||
TResult? Function()? loading,
|
|
||||||
TResult? Function(List<dynamic> chats)? chatsLoaded,
|
|
||||||
TResult? Function(String chat, List<dynamic> messages)? chatSelected,
|
|
||||||
TResult? Function(List<dynamic> messages)? messagesLoaded,
|
|
||||||
TResult? Function()? messageSent,
|
|
||||||
TResult? Function(String message)? error,
|
|
||||||
}) {
|
|
||||||
return messageSent?.call();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult maybeWhen<TResult extends Object?>({
|
|
||||||
TResult Function()? initial,
|
|
||||||
TResult Function()? loading,
|
|
||||||
TResult Function(List<dynamic> chats)? chatsLoaded,
|
|
||||||
TResult Function(String chat, List<dynamic> messages)? chatSelected,
|
|
||||||
TResult Function(List<dynamic> messages)? messagesLoaded,
|
|
||||||
TResult Function()? messageSent,
|
|
||||||
TResult Function(String message)? error,
|
|
||||||
required TResult orElse(),
|
|
||||||
}) {
|
|
||||||
if (messageSent != null) {
|
|
||||||
return messageSent();
|
|
||||||
}
|
|
||||||
return orElse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult map<TResult extends Object?>({
|
|
||||||
required TResult Function(ChatInitial value) initial,
|
|
||||||
required TResult Function(ChatLoading value) loading,
|
|
||||||
required TResult Function(_ChatsLoaded value) chatsLoaded,
|
|
||||||
required TResult Function(_ChatSelected value) chatSelected,
|
|
||||||
required TResult Function(_MessagesLoaded value) messagesLoaded,
|
|
||||||
required TResult Function(_MessageSent value) messageSent,
|
|
||||||
required TResult Function(ChatError value) error,
|
|
||||||
}) {
|
|
||||||
return messageSent(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult? mapOrNull<TResult extends Object?>({
|
|
||||||
TResult? Function(ChatInitial value)? initial,
|
|
||||||
TResult? Function(ChatLoading value)? loading,
|
|
||||||
TResult? Function(_ChatsLoaded value)? chatsLoaded,
|
|
||||||
TResult? Function(_ChatSelected value)? chatSelected,
|
|
||||||
TResult? Function(_MessagesLoaded value)? messagesLoaded,
|
|
||||||
TResult? Function(_MessageSent value)? messageSent,
|
|
||||||
TResult? Function(ChatError value)? error,
|
|
||||||
}) {
|
|
||||||
return messageSent?.call(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult maybeMap<TResult extends Object?>({
|
|
||||||
TResult Function(ChatInitial value)? initial,
|
|
||||||
TResult Function(ChatLoading value)? loading,
|
|
||||||
TResult Function(_ChatsLoaded value)? chatsLoaded,
|
|
||||||
TResult Function(_ChatSelected value)? chatSelected,
|
|
||||||
TResult Function(_MessagesLoaded value)? messagesLoaded,
|
|
||||||
TResult Function(_MessageSent value)? messageSent,
|
|
||||||
TResult Function(ChatError value)? error,
|
|
||||||
required TResult orElse(),
|
|
||||||
}) {
|
|
||||||
if (messageSent != null) {
|
|
||||||
return messageSent(this);
|
|
||||||
}
|
|
||||||
return orElse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class _MessageSent implements ChatState {
|
|
||||||
const factory _MessageSent() = _$MessageSentImpl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
abstract class _$$ChatErrorImplCopyWith<$Res> {
|
abstract class _$$ChatErrorImplCopyWith<$Res> {
|
||||||
factory _$$ChatErrorImplCopyWith(
|
factory _$$ChatErrorImplCopyWith(
|
||||||
@@ -1086,10 +928,9 @@ class _$ChatErrorImpl implements ChatError {
|
|||||||
TResult when<TResult extends Object?>({
|
TResult when<TResult extends Object?>({
|
||||||
required TResult Function() initial,
|
required TResult Function() initial,
|
||||||
required TResult Function() loading,
|
required TResult Function() loading,
|
||||||
required TResult Function(List<dynamic> chats) chatsLoaded,
|
required TResult Function(List<Chat> chats) chatsLoaded,
|
||||||
required TResult Function(String chat, List<dynamic> messages) chatSelected,
|
required TResult Function(Chat chat, List<Message> messages) chatSelected,
|
||||||
required TResult Function(List<dynamic> messages) messagesLoaded,
|
required TResult Function(List<Message> messages) messagesLoaded,
|
||||||
required TResult Function() messageSent,
|
|
||||||
required TResult Function(String message) error,
|
required TResult Function(String message) error,
|
||||||
}) {
|
}) {
|
||||||
return error(message);
|
return error(message);
|
||||||
@@ -1100,10 +941,9 @@ class _$ChatErrorImpl implements ChatError {
|
|||||||
TResult? whenOrNull<TResult extends Object?>({
|
TResult? whenOrNull<TResult extends Object?>({
|
||||||
TResult? Function()? initial,
|
TResult? Function()? initial,
|
||||||
TResult? Function()? loading,
|
TResult? Function()? loading,
|
||||||
TResult? Function(List<dynamic> chats)? chatsLoaded,
|
TResult? Function(List<Chat> chats)? chatsLoaded,
|
||||||
TResult? Function(String chat, List<dynamic> messages)? chatSelected,
|
TResult? Function(Chat chat, List<Message> messages)? chatSelected,
|
||||||
TResult? Function(List<dynamic> messages)? messagesLoaded,
|
TResult? Function(List<Message> messages)? messagesLoaded,
|
||||||
TResult? Function()? messageSent,
|
|
||||||
TResult? Function(String message)? error,
|
TResult? Function(String message)? error,
|
||||||
}) {
|
}) {
|
||||||
return error?.call(message);
|
return error?.call(message);
|
||||||
@@ -1114,10 +954,9 @@ class _$ChatErrorImpl implements ChatError {
|
|||||||
TResult maybeWhen<TResult extends Object?>({
|
TResult maybeWhen<TResult extends Object?>({
|
||||||
TResult Function()? initial,
|
TResult Function()? initial,
|
||||||
TResult Function()? loading,
|
TResult Function()? loading,
|
||||||
TResult Function(List<dynamic> chats)? chatsLoaded,
|
TResult Function(List<Chat> chats)? chatsLoaded,
|
||||||
TResult Function(String chat, List<dynamic> messages)? chatSelected,
|
TResult Function(Chat chat, List<Message> messages)? chatSelected,
|
||||||
TResult Function(List<dynamic> messages)? messagesLoaded,
|
TResult Function(List<Message> messages)? messagesLoaded,
|
||||||
TResult Function()? messageSent,
|
|
||||||
TResult Function(String message)? error,
|
TResult Function(String message)? error,
|
||||||
required TResult orElse(),
|
required TResult orElse(),
|
||||||
}) {
|
}) {
|
||||||
@@ -1135,7 +974,6 @@ class _$ChatErrorImpl implements ChatError {
|
|||||||
required TResult Function(_ChatsLoaded value) chatsLoaded,
|
required TResult Function(_ChatsLoaded value) chatsLoaded,
|
||||||
required TResult Function(_ChatSelected value) chatSelected,
|
required TResult Function(_ChatSelected value) chatSelected,
|
||||||
required TResult Function(_MessagesLoaded value) messagesLoaded,
|
required TResult Function(_MessagesLoaded value) messagesLoaded,
|
||||||
required TResult Function(_MessageSent value) messageSent,
|
|
||||||
required TResult Function(ChatError value) error,
|
required TResult Function(ChatError value) error,
|
||||||
}) {
|
}) {
|
||||||
return error(this);
|
return error(this);
|
||||||
@@ -1149,7 +987,6 @@ class _$ChatErrorImpl implements ChatError {
|
|||||||
TResult? Function(_ChatsLoaded value)? chatsLoaded,
|
TResult? Function(_ChatsLoaded value)? chatsLoaded,
|
||||||
TResult? Function(_ChatSelected value)? chatSelected,
|
TResult? Function(_ChatSelected value)? chatSelected,
|
||||||
TResult? Function(_MessagesLoaded value)? messagesLoaded,
|
TResult? Function(_MessagesLoaded value)? messagesLoaded,
|
||||||
TResult? Function(_MessageSent value)? messageSent,
|
|
||||||
TResult? Function(ChatError value)? error,
|
TResult? Function(ChatError value)? error,
|
||||||
}) {
|
}) {
|
||||||
return error?.call(this);
|
return error?.call(this);
|
||||||
@@ -1163,7 +1000,6 @@ class _$ChatErrorImpl implements ChatError {
|
|||||||
TResult Function(_ChatsLoaded value)? chatsLoaded,
|
TResult Function(_ChatsLoaded value)? chatsLoaded,
|
||||||
TResult Function(_ChatSelected value)? chatSelected,
|
TResult Function(_ChatSelected value)? chatSelected,
|
||||||
TResult Function(_MessagesLoaded value)? messagesLoaded,
|
TResult Function(_MessagesLoaded value)? messagesLoaded,
|
||||||
TResult Function(_MessageSent value)? messageSent,
|
|
||||||
TResult Function(ChatError value)? error,
|
TResult Function(ChatError value)? error,
|
||||||
required TResult orElse(),
|
required TResult orElse(),
|
||||||
}) {
|
}) {
|
||||||
|
|||||||
@@ -1,13 +1,21 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:messenger_app/l10n/app_localizations.dart';
|
||||||
|
import '../bloc/chat_bloc.dart';
|
||||||
|
import '../bloc/chat_event.dart';
|
||||||
|
import '../bloc/chat_state.dart';
|
||||||
|
import '../../domain/entities/chat.dart';
|
||||||
|
import '../../domain/entities/message.dart';
|
||||||
|
|
||||||
class ChatDetailPage extends StatefulWidget {
|
class ChatDetailPage extends StatefulWidget {
|
||||||
final String chatId;
|
final Chat chat;
|
||||||
final String chatTitle;
|
final String currentUserId;
|
||||||
|
|
||||||
const ChatDetailPage({
|
const ChatDetailPage({
|
||||||
super.key,
|
super.key,
|
||||||
required this.chatId,
|
required this.chat,
|
||||||
required this.chatTitle,
|
required this.currentUserId,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -16,90 +24,148 @@ class ChatDetailPage extends StatefulWidget {
|
|||||||
|
|
||||||
class _ChatDetailPageState extends State<ChatDetailPage> {
|
class _ChatDetailPageState extends State<ChatDetailPage> {
|
||||||
final _messageController = TextEditingController();
|
final _messageController = TextEditingController();
|
||||||
|
final _scrollController = ScrollController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_messageController.dispose();
|
_messageController.dispose();
|
||||||
|
_scrollController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _sendMessage() {
|
|
||||||
if (_messageController.text.trim().isEmpty) return;
|
|
||||||
_messageController.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(widget.chatTitle),
|
title: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(widget.chat.type == 'favorites' ? AppLocalizations.of(context)!.favorites : widget.chat.title),
|
||||||
|
if (widget.chat.type != 'favorites')
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.connected,
|
||||||
|
style: const TextStyle(fontSize: 12, fontWeight: FontWeight.normal),
|
||||||
),
|
),
|
||||||
body: const Center(child: Text('Chat Detail')),
|
],
|
||||||
bottomNavigationBar: _MessageInput(
|
),
|
||||||
controller: _messageController,
|
actions: [
|
||||||
onSend: _sendMessage,
|
IconButton(icon: const Icon(Icons.more_vert), onPressed: () {}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: BlocBuilder<ChatBloc, ChatState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
return state.maybeWhen(
|
||||||
|
chatSelected: (_, messages) => _buildMessageList(messages),
|
||||||
|
messagesLoaded: (messages) => _buildMessageList(messages),
|
||||||
|
loading: () => const Center(child: CircularProgressIndicator()),
|
||||||
|
error: (msg) => Center(child: Text('Ошибка: $msg')),
|
||||||
|
orElse: () => const Center(child: Text('Начните общение')),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
_buildMessageInput(),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildMessageList(List<Message> messages) {
|
||||||
|
if (messages.isEmpty) {
|
||||||
|
return const Center(child: Text('Сообщений пока нет'));
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MessageInput extends StatelessWidget {
|
return ListView.builder(
|
||||||
final TextEditingController controller;
|
controller: _scrollController,
|
||||||
final VoidCallback onSend;
|
reverse: true,
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
itemCount: messages.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final message = messages[index];
|
||||||
|
final isMe = message.senderId == widget.currentUserId;
|
||||||
|
|
||||||
const _MessageInput({
|
return Align(
|
||||||
required this.controller,
|
alignment: isMe ? Alignment.centerRight : Alignment.centerLeft,
|
||||||
required this.onSend,
|
child: Container(
|
||||||
});
|
margin: const EdgeInsets.symmetric(vertical: 4),
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: isMe ? Theme.of(context).primaryColor : Colors.grey[200],
|
||||||
|
borderRadius: BorderRadius.circular(16).copyWith(
|
||||||
|
bottomRight: isMe ? const Radius.circular(0) : const Radius.circular(16),
|
||||||
|
bottomLeft: !isMe ? const Radius.circular(0) : const Radius.circular(16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
message.content,
|
||||||
|
style: TextStyle(color: isMe ? Colors.white : Colors.black87),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
if (message.createdAt != null)
|
||||||
|
Text(
|
||||||
|
DateFormat.Hm().format(message.createdAt!),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 10,
|
||||||
|
color: isMe ? Colors.white70 : Colors.black45,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
Widget _buildMessageInput() {
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.black.withOpacity(0.1),
|
color: Colors.black.withOpacity(0.05),
|
||||||
|
offset: const Offset(0, -1),
|
||||||
blurRadius: 4,
|
blurRadius: 4,
|
||||||
offset: const Offset(0, -2),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
child: SafeArea(
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
IconButton(
|
IconButton(icon: const Icon(Icons.add), onPressed: () {}),
|
||||||
icon: const Icon(Icons.attach_file),
|
|
||||||
onPressed: () {},
|
|
||||||
),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: controller,
|
controller: _messageController,
|
||||||
decoration: InputDecoration(
|
decoration: const InputDecoration(
|
||||||
hintText: 'Сообщение',
|
hintText: 'Сообщение',
|
||||||
border: OutlineInputBorder(
|
border: InputBorder.none,
|
||||||
borderRadius: BorderRadius.circular(24),
|
|
||||||
borderSide: BorderSide.none,
|
|
||||||
),
|
),
|
||||||
filled: true,
|
onSubmitted: (_) => _sendMessage(),
|
||||||
fillColor: Colors.grey[200],
|
|
||||||
contentPadding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 16,
|
|
||||||
vertical: 8,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
maxLines: null,
|
|
||||||
onSubmitted: (_) => onSend(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.send),
|
icon: const Icon(Icons.send),
|
||||||
|
onPressed: _sendMessage,
|
||||||
color: Theme.of(context).primaryColor,
|
color: Theme.of(context).primaryColor,
|
||||||
onPressed: onSend,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _sendMessage() {
|
||||||
|
final content = _messageController.text.trim();
|
||||||
|
if (content.isNotEmpty) {
|
||||||
|
context.read<ChatBloc>().add(ChatEvent.messageSent(widget.chat.id, content));
|
||||||
|
_messageController.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +1,169 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import '../bloc/chat_bloc.dart';
|
import 'package:intl/intl.dart';
|
||||||
import '../bloc/chat_state.dart';
|
import 'package:messenger_app/features/chat/presentation/bloc/chat_bloc.dart';
|
||||||
|
import 'package:messenger_app/features/chat/presentation/bloc/chat_event.dart';
|
||||||
|
import 'package:messenger_app/features/chat/presentation/bloc/chat_state.dart';
|
||||||
|
import 'package:messenger_app/features/auth/presentation/bloc/auth_bloc.dart';
|
||||||
|
import 'package:messenger_app/features/auth/presentation/bloc/auth_state.dart';
|
||||||
|
import 'package:messenger_app/features/chat/domain/entities/chat.dart';
|
||||||
|
import 'package:messenger_app/l10n/app_localizations.dart';
|
||||||
|
import 'chat_detail_page.dart';
|
||||||
|
|
||||||
class ChatsPage extends StatelessWidget {
|
class ChatsPage extends StatefulWidget {
|
||||||
const ChatsPage({super.key});
|
const ChatsPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ChatsPage> createState() => _ChatsPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ChatsPageState extends State<ChatsPage> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
final authState = context.read<AuthBloc>().state;
|
||||||
|
final userId = authState.maybeWhen(
|
||||||
|
authenticated: (id) => id,
|
||||||
|
orElse: () => null,
|
||||||
|
);
|
||||||
|
context.read<ChatBloc>().add(ChatEvent.chatsLoaded(currentUserId: userId));
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<ChatBloc, ChatState>(
|
final l10n = AppLocalizations.of(context)!;
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(l10n.chats),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.bookmark_border),
|
||||||
|
onPressed: () {
|
||||||
|
context.read<ChatBloc>().add(const ChatEvent.favoritesRequested());
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: BlocConsumer<ChatBloc, ChatState>(
|
||||||
|
listener: (context, state) {
|
||||||
|
state.whenOrNull(
|
||||||
|
chatSelected: (chat, _) {
|
||||||
|
final authState = context.read<AuthBloc>().state;
|
||||||
|
final userId = authState.maybeWhen(
|
||||||
|
authenticated: (id) => id,
|
||||||
|
orElse: () => '',
|
||||||
|
);
|
||||||
|
|
||||||
|
Navigator.of(context).push(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (_) => ChatDetailPage(
|
||||||
|
chat: chat,
|
||||||
|
currentUserId: userId,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).then((_) {
|
||||||
|
// Reload chats when returning from detail page
|
||||||
|
if (context.mounted) {
|
||||||
|
context.read<ChatBloc>().add(ChatEvent.chatsLoaded(currentUserId: userId));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return state.when(
|
return state.maybeWhen(
|
||||||
initial: () => const Center(child: CircularProgressIndicator()),
|
|
||||||
loading: () => const Center(child: CircularProgressIndicator()),
|
loading: () => const Center(child: CircularProgressIndicator()),
|
||||||
chatsLoaded: (_) => const Center(
|
chatsLoaded: (chats) => _buildChatList(chats, l10n),
|
||||||
|
error: (message) => Center(child: Text('${l10n.error}: $message')),
|
||||||
|
orElse: () => const Center(child: CircularProgressIndicator()),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
floatingActionButton: FloatingActionButton(
|
||||||
|
onPressed: () {
|
||||||
|
// TODO: Open contact list to create chat
|
||||||
|
},
|
||||||
|
child: const Icon(Icons.edit),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildChatList(List<Chat> chats, AppLocalizations l10n) {
|
||||||
|
if (chats.isEmpty) {
|
||||||
|
return Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.chat_bubble_outline, size: 64, color: Colors.grey),
|
const Icon(Icons.chat_bubble_outline, size: 64, color: Colors.grey),
|
||||||
SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text('У вас пока нет чатов'),
|
Text(l10n.noChats),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
final authState = context.read<AuthBloc>().state;
|
||||||
|
final userId = authState.maybeWhen(
|
||||||
|
authenticated: (id) => id,
|
||||||
|
orElse: () => null,
|
||||||
|
);
|
||||||
|
context.read<ChatBloc>().add(ChatEvent.chatsLoaded(currentUserId: userId));
|
||||||
|
},
|
||||||
|
child: Text(l10n.retry),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ListView.separated(
|
||||||
|
itemCount: chats.length,
|
||||||
|
separatorBuilder: (context, index) => const Divider(height: 1),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final chat = chats[index];
|
||||||
|
return ListTile(
|
||||||
|
leading: CircleAvatar(
|
||||||
|
backgroundImage: chat.avatarUrl != null ? NetworkImage(chat.avatarUrl!) : null,
|
||||||
|
child: chat.avatarUrl == null
|
||||||
|
? Text(chat.title.isNotEmpty ? chat.title[0].toUpperCase() : '?')
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
chatSelected: (_, __) => const Center(child: Text('Chat selected')),
|
title: Text(
|
||||||
messagesLoaded: (_) => const Center(child: Text('Messages loaded')),
|
chat.type == 'favorites' ? l10n.favorites : chat.title,
|
||||||
messageSent: () => const Center(child: Text('Message sent')),
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
error: (message) => Center(child: Text('Ошибка: $message')),
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
chat.lastMessage?.content ?? l10n.noChats,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
trailing: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
if (chat.lastMessageTime != null)
|
||||||
|
Text(
|
||||||
|
DateFormat.Hm().format(chat.lastMessageTime!),
|
||||||
|
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
if (chat.unreadCount > 0)
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
chat.unreadCount.toString(),
|
||||||
|
style: const TextStyle(color: Colors.white, fontSize: 10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
context.read<ChatBloc>().add(ChatEvent.chatSelected(chat.id));
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,14 @@ import '../../features/auth/data/datasources/auth_remote_datasource_impl.dart';
|
|||||||
import '../../features/auth/data/repositories/auth_repository_impl.dart';
|
import '../../features/auth/data/repositories/auth_repository_impl.dart';
|
||||||
import '../../features/auth/domain/repositories/auth_repository.dart';
|
import '../../features/auth/domain/repositories/auth_repository.dart';
|
||||||
import '../../features/auth/presentation/bloc/auth_bloc.dart';
|
import '../../features/auth/presentation/bloc/auth_bloc.dart';
|
||||||
|
import '../../core/database/database_service.dart';
|
||||||
|
import '../../core/network/signalr_service.dart';
|
||||||
|
import '../../features/chat/data/datasources/chat_local_datasource.dart';
|
||||||
|
import '../../features/chat/data/datasources/chat_local_datasource_impl.dart';
|
||||||
|
import '../../features/chat/data/datasources/chat_remote_datasource.dart';
|
||||||
|
import '../../features/chat/data/datasources/chat_remote_datasource_impl.dart';
|
||||||
|
import '../../features/chat/data/repositories/chat_repository_impl.dart';
|
||||||
|
import '../../features/chat/domain/repositories/chat_repository.dart';
|
||||||
import '../../features/chat/presentation/bloc/chat_bloc.dart';
|
import '../../features/chat/presentation/bloc/chat_bloc.dart';
|
||||||
import '../../features/settings/data/datasources/settings_local_datasource.dart';
|
import '../../features/settings/data/datasources/settings_local_datasource.dart';
|
||||||
import '../../features/settings/data/datasources/settings_remote_datasource.dart';
|
import '../../features/settings/data/datasources/settings_remote_datasource.dart';
|
||||||
@@ -40,16 +48,34 @@ Future<void> initDependencies() async {
|
|||||||
apiUrl = apiUrl.substring(0, apiUrl.length - 4).replaceAll(RegExp(r'/+$'), '');
|
apiUrl = apiUrl.substring(0, apiUrl.length - 4).replaceAll(RegExp(r'/+$'), '');
|
||||||
}
|
}
|
||||||
|
|
||||||
return Dio(BaseOptions(
|
final dio = Dio(BaseOptions(
|
||||||
baseUrl: apiUrl,
|
baseUrl: apiUrl,
|
||||||
connectTimeout: const Duration(seconds: 30),
|
connectTimeout: const Duration(seconds: 30),
|
||||||
receiveTimeout: const Duration(seconds: 30),
|
receiveTimeout: const Duration(seconds: 30),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
dio.interceptors.add(InterceptorsWrapper(
|
||||||
|
onRequest: (options, handler) {
|
||||||
|
final token = prefs.getString('access_token');
|
||||||
|
if (token != null) {
|
||||||
|
options.headers['Authorization'] = 'Bearer $token';
|
||||||
|
}
|
||||||
|
return handler.next(options);
|
||||||
|
},
|
||||||
|
));
|
||||||
|
|
||||||
|
return dio;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Core - API Client
|
// Core - API Client
|
||||||
sl.registerLazySingleton<ApiClient>(() => ApiClient(sl()));
|
sl.registerLazySingleton<ApiClient>(() => ApiClient(sl()));
|
||||||
|
|
||||||
|
// Core - Database & SignalR
|
||||||
|
final dbService = DatabaseService();
|
||||||
|
await dbService.init();
|
||||||
|
sl.registerSingleton<DatabaseService>(dbService);
|
||||||
|
sl.registerLazySingleton<SignalRService>(() => SignalRService(sl()));
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
sl.registerLazySingleton<SettingsRemoteDataSource>(
|
sl.registerLazySingleton<SettingsRemoteDataSource>(
|
||||||
() => SettingsRemoteDataSourceImpl(sl()),
|
() => SettingsRemoteDataSourceImpl(sl()),
|
||||||
@@ -75,5 +101,18 @@ Future<void> initDependencies() async {
|
|||||||
sl.registerFactory<AuthBloc>(() => AuthBloc(authRepository: sl()));
|
sl.registerFactory<AuthBloc>(() => AuthBloc(authRepository: sl()));
|
||||||
|
|
||||||
// Chat
|
// Chat
|
||||||
sl.registerFactory<ChatBloc>(() => ChatBloc());
|
sl.registerLazySingleton<ChatLocalDataSource>(
|
||||||
|
() => ChatLocalDataSourceImpl(sl<DatabaseService>().isar),
|
||||||
|
);
|
||||||
|
sl.registerLazySingleton<ChatRemoteDataSource>(
|
||||||
|
() => ChatRemoteDataSourceImpl(sl()),
|
||||||
|
);
|
||||||
|
sl.registerLazySingleton<ChatRepository>(
|
||||||
|
() => ChatRepositoryImpl(
|
||||||
|
remoteDataSource: sl(),
|
||||||
|
localDataSource: sl(),
|
||||||
|
signalRService: sl(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
sl.registerFactory<ChatBloc>(() => ChatBloc(chatRepository: sl()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class ChatsPage extends StatelessWidget {
|
|
||||||
const ChatsPage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return const Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Icon(Icons.chat_bubble_outline, size: 64, color: Colors.grey),
|
|
||||||
SizedBox(height: 16),
|
|
||||||
Text('Чаты', style: TextStyle(fontSize: 18)),
|
|
||||||
SizedBox(height: 8),
|
|
||||||
Text('Функция в разработке', style: TextStyle(color: Colors.grey)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../../features/settings/presentation/pages/settings_page.dart';
|
import '../../features/settings/presentation/pages/settings_page.dart';
|
||||||
import '../router/chats_placeholder.dart';
|
import '../../features/chat/presentation/pages/chats_page.dart';
|
||||||
|
import '../../l10n/app_localizations.dart';
|
||||||
|
|
||||||
class MainScreen extends StatefulWidget {
|
class MainScreen extends StatefulWidget {
|
||||||
static const String routeName = '/main';
|
static const String routeName = '/main';
|
||||||
@@ -16,6 +17,7 @@ class _MainScreenState extends State<MainScreen> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final l10n = AppLocalizations.of(context)!;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: IndexedStack(
|
body: IndexedStack(
|
||||||
index: _currentIndex,
|
index: _currentIndex,
|
||||||
@@ -29,21 +31,21 @@ class _MainScreenState extends State<MainScreen> {
|
|||||||
currentIndex: _currentIndex,
|
currentIndex: _currentIndex,
|
||||||
onTap: (index) => setState(() => _currentIndex = index),
|
onTap: (index) => setState(() => _currentIndex = index),
|
||||||
type: BottomNavigationBarType.fixed,
|
type: BottomNavigationBarType.fixed,
|
||||||
items: const [
|
items: [
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(Icons.chat_bubble_outline),
|
icon: const Icon(Icons.chat_bubble_outline),
|
||||||
activeIcon: Icon(Icons.chat_bubble),
|
activeIcon: const Icon(Icons.chat_bubble),
|
||||||
label: 'Чаты',
|
label: l10n.chats,
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(Icons.contacts_outlined),
|
icon: const Icon(Icons.contacts_outlined),
|
||||||
activeIcon: Icon(Icons.contacts),
|
activeIcon: const Icon(Icons.contacts),
|
||||||
label: 'Контакты',
|
label: l10n.contacts,
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(Icons.settings_outlined),
|
icon: const Icon(Icons.settings_outlined),
|
||||||
activeIcon: Icon(Icons.settings),
|
activeIcon: const Icon(Icons.settings),
|
||||||
label: 'Настройки',
|
label: l10n.settings,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -110,6 +110,12 @@ abstract class AppLocalizations {
|
|||||||
/// **'Чаты'**
|
/// **'Чаты'**
|
||||||
String get chats;
|
String get chats;
|
||||||
|
|
||||||
|
/// No description provided for @favorites.
|
||||||
|
///
|
||||||
|
/// In ru, this message translates to:
|
||||||
|
/// **'Избранное'**
|
||||||
|
String get favorites;
|
||||||
|
|
||||||
/// No description provided for @contacts.
|
/// No description provided for @contacts.
|
||||||
///
|
///
|
||||||
/// In ru, this message translates to:
|
/// In ru, this message translates to:
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get chats => 'Chats';
|
String get chats => 'Chats';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get favorites => 'Favorites';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get contacts => 'Contacts';
|
String get contacts => 'Contacts';
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ class AppLocalizationsRu extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get chats => 'Чаты';
|
String get chats => 'Чаты';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get favorites => 'Избранное';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get contacts => 'Контакты';
|
String get contacts => 'Контакты';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user