fix: remove NavigationWrapper to be more consistent with flutter_availability userstory

This commit is contained in:
Freek van de Ven 2025-02-12 17:28:23 +01:00 committed by Bart Ribbers
parent 44209c4d2f
commit 97c259761c
3 changed files with 414 additions and 397 deletions

View file

@ -1,87 +1,16 @@
// SPDX-FileCopyrightText: 2023 Iconica // SPDX-FileCopyrightText: 2023 Iconica
// //
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
import "package:chat_repository_interface/chat_repository_interface.dart"; import "package:chat_repository_interface/chat_repository_interface.dart";
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:flutter_chat/src/config/chat_options.dart"; import "package:flutter_chat/src/config/chat_options.dart";
import "package:flutter_chat/src/routes.dart"; import "package:flutter_chat/src/routes.dart";
import "package:flutter_chat/src/services/pop_handler.dart"; import "package:flutter_chat/src/services/pop_handler.dart";
import "package:flutter_chat/src/util/scope.dart"; import "package:flutter_chat/src/util/scope.dart";
import "package:flutter_hooks/flutter_hooks.dart";
/// Base class for both chat navigator user stories.
abstract class BaseChatNavigatorUserstory extends StatefulWidget {
/// Constructs a [BaseChatNavigatorUserstory].
const BaseChatNavigatorUserstory({
required this.userId,
required this.options,
this.onExit,
super.key,
});
/// The user ID of the person starting the chat userstory.
final String userId;
/// The chat userstory configuration.
final ChatOptions options;
/// Callback for when the user wants to navigate back to a previous screen
final VoidCallback? onExit;
@override
State<BaseChatNavigatorUserstory> createState();
}
abstract class _BaseChatNavigatorUserstoryState<
T extends BaseChatNavigatorUserstory> extends State<T> {
late ChatService _service = ChatService(
userId: widget.userId,
chatRepository: widget.options.chatRepository,
userRepository: widget.options.userRepository,
);
late final PopHandler _popHandler = PopHandler();
final GlobalKey<NavigatorState> _nestedNavigatorKey =
GlobalKey<NavigatorState>();
@override
Widget build(BuildContext context) => ChatScope(
userId: widget.userId,
options: widget.options,
service: _service,
popHandler: _popHandler,
child: NavigatorPopHandler(
onPop: () => _popHandler.handlePop(),
child: Navigator(
key: _nestedNavigatorKey,
onGenerateRoute: (settings) => MaterialPageRoute(
builder: (context) => buildInitialScreen(),
),
),
),
);
@override
void didUpdateWidget(covariant T oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.userId != widget.userId ||
oldWidget.options != widget.options) {
setState(() {
_service = ChatService(
userId: widget.userId,
chatRepository: widget.options.chatRepository,
userRepository: widget.options.userRepository,
);
});
}
}
/// Implemented by subclasses to provide the initial screen of the userstory.
Widget buildInitialScreen();
}
/// Default Chat Userstory that starts at the chat list screen. /// Default Chat Userstory that starts at the chat list screen.
class FlutterChatNavigatorUserstory extends BaseChatNavigatorUserstory { class FlutterChatNavigatorUserstory extends _BaseChatNavigatorUserstory {
/// Constructs a [FlutterChatNavigatorUserstory]. /// Constructs a [FlutterChatNavigatorUserstory].
const FlutterChatNavigatorUserstory({ const FlutterChatNavigatorUserstory({
required super.userId, required super.userId,
@ -91,23 +20,21 @@ class FlutterChatNavigatorUserstory extends BaseChatNavigatorUserstory {
}); });
@override @override
State<BaseChatNavigatorUserstory> createState() => MaterialPageRoute buildInitialRoute(
_FlutterChatNavigatorUserstoryState(); BuildContext context,
} ChatService service,
PopHandler popHandler,
class _FlutterChatNavigatorUserstoryState ) =>
extends _BaseChatNavigatorUserstoryState<FlutterChatNavigatorUserstory> { chatOverviewRoute(
@override userId: userId,
Widget buildInitialScreen() => NavigatorWrapper( chatService: service,
userId: widget.userId, chatOptions: options,
chatService: _service, onExit: onExit,
chatOptions: widget.options,
onExit: widget.onExit,
); );
} }
/// Chat Userstory that starts directly in a chat detail screen. /// Chat Userstory that starts directly in a chat detail screen.
class FlutterChatDetailNavigatorUserstory extends BaseChatNavigatorUserstory { class FlutterChatDetailNavigatorUserstory extends _BaseChatNavigatorUserstory {
/// Constructs a [FlutterChatDetailNavigatorUserstory]. /// Constructs a [FlutterChatDetailNavigatorUserstory].
const FlutterChatDetailNavigatorUserstory({ const FlutterChatDetailNavigatorUserstory({
required super.userId, required super.userId,
@ -121,22 +48,74 @@ class FlutterChatDetailNavigatorUserstory extends BaseChatNavigatorUserstory {
final ChatModel chat; final ChatModel chat;
@override @override
State<BaseChatNavigatorUserstory> createState() => MaterialPageRoute buildInitialRoute(
_FlutterChatDetailNavigatorUserstoryState(); BuildContext context,
} ChatService service,
PopHandler popHandler,
class _FlutterChatDetailNavigatorUserstoryState ) =>
extends _BaseChatNavigatorUserstoryState< chatDetailRoute(
FlutterChatDetailNavigatorUserstory> { chat: chat,
@override userId: userId,
Widget buildInitialScreen() => NavigatorWrapper( chatService: service,
userId: widget.userId, chatOptions: options,
chatService: _service, onExit: onExit,
chatOptions: widget.options,
onExit: widget.onExit,
).chatDetailScreen(
context,
widget.chat,
widget.onExit,
); );
} }
/// Base hook widget for chat navigator userstories.
abstract class _BaseChatNavigatorUserstory extends HookWidget {
/// Constructs a [_BaseChatNavigatorUserstory].
const _BaseChatNavigatorUserstory({
required this.userId,
required this.options,
this.onExit,
super.key,
});
/// The user ID of the person starting the chat userstory.
final String userId;
/// The chat userstory configuration.
final ChatOptions options;
/// Callback for when the user wants to navigate back.
final VoidCallback? onExit;
/// Implemented by subclasses to provide the initial route of the userstory.
MaterialPageRoute buildInitialRoute(
BuildContext context,
ChatService service,
PopHandler popHandler,
);
@override
Widget build(BuildContext context) {
var service = useMemoized(
() => ChatService(
userId: userId,
chatRepository: options.chatRepository,
userRepository: options.userRepository,
),
[userId, options],
);
var popHandler = useMemoized(PopHandler.new, []);
var nestedNavigatorKey = useMemoized(GlobalKey<NavigatorState>.new, []);
return ChatScope(
userId: userId,
options: options,
service: service,
popHandler: popHandler,
child: NavigatorPopHandler(
onPop: () => popHandler.handlePop(),
child: Navigator(
key: nestedNavigatorKey,
onGenerateInitialRoutes: (_, __) => [
buildInitialRoute(context, service, popHandler),
],
),
),
);
}
}

View file

@ -10,85 +10,56 @@ import "package:flutter_chat/src/screens/creation/new_chat_screen.dart";
import "package:flutter_chat/src/screens/creation/new_group_chat_overview.dart"; import "package:flutter_chat/src/screens/creation/new_group_chat_overview.dart";
import "package:flutter_chat/src/screens/creation/new_group_chat_screen.dart"; import "package:flutter_chat/src/screens/creation/new_group_chat_screen.dart";
/// The navigator wrapper /// Pushes the chat overview screen
class NavigatorWrapper extends StatelessWidget { MaterialPageRoute chatOverviewRoute({
/// Constructs a [NavigatorWrapper]. required String userId,
const NavigatorWrapper({ required ChatService chatService,
required this.userId, required ChatOptions chatOptions,
required this.chatService, required VoidCallback? onExit,
required this.chatOptions, }) =>
this.onExit, MaterialPageRoute(
super.key, builder: (context) => ChatScreen(
});
/// The user ID of the person starting the chat userstory
final String userId;
/// The chat service containing the chat repository and user repository
final ChatService chatService;
/// The chat userstory configuration
final ChatOptions chatOptions;
/// Callback for when the user wants to navigate back
final VoidCallback? onExit;
@override
Widget build(BuildContext context) => chatScreen(context);
/// The chat overview screen
Widget chatScreen(BuildContext context) => ChatScreen(
onExit: onExit, onExit: onExit,
onPressChat: (chat) async => _routeToScreen( onPressChat: (chat) async => _routeToScreen(
context, context,
chatDetailScreen( chatDetailRoute(
context, chat: chat,
chat, userId: userId,
() => Navigator.of(context).pop(), chatService: chatService,
), chatOptions: chatOptions,
onExit: () => Navigator.of(context).pop(),
).builder(context),
), ),
onDeleteChat: (chat) async { onDeleteChat: (chat) async => chatService.deleteChat(chatId: chat.id),
await chatService.deleteChat(chatId: chat.id); onPressStartChat: () async => _routeToScreen(
}, context,
onPressStartChat: () async => _newChatRoute(
_routeToScreen(context, newChatScreen(context)), userId: userId,
); chatService: chatService,
chatOptions: chatOptions,
).builder(context),
),
),
);
/// The chat screen /// Pushes the chat detail screen
Widget chatDetailScreen( MaterialPageRoute chatDetailRoute({
BuildContext context, required ChatModel chat,
ChatModel chat, required String userId,
VoidCallback? onExit, required ChatService chatService,
) => required ChatOptions chatOptions,
ChatDetailScreen( required VoidCallback? onExit,
}) =>
MaterialPageRoute(
builder: (context) => ChatDetailScreen(
chat: chat, chat: chat,
onExit: onExit, onExit: onExit,
onReadChat: (chat) async => chatService.markAsRead(chatId: chat.id), onReadChat: (chat) async => chatService.markAsRead(chatId: chat.id),
onPressChatTitle: (chat) async {
if (chat.isGroupChat) {
return _routeToScreen(
context,
chatProfileScreen(context, null, chat),
);
}
var otherUserId = chat.getOtherUser(userId);
var otherUser = await chatService.getUser(userId: otherUserId).first;
if (!context.mounted) return;
return _routeToScreen(
context,
chatProfileScreen(context, otherUser, null),
);
},
onPressUserProfile: (user) async =>
_routeToScreen(context, chatProfileScreen(context, user, null)),
onUploadImage: (data) async { onUploadImage: (data) async {
var path = await chatService.uploadImage( var path = await chatService.uploadImage(
path: "chats/${chat.id}-$userId-${DateTime.now()}", path: "chats/${chat.id}-$userId-${DateTime.now()}",
image: data, image: data,
); );
await chatService.sendMessage( await chatService.sendMessage(
messageId: "${chat.id}-$userId-${DateTime.now()}", messageId: "${chat.id}-$userId-${DateTime.now()}",
chatId: chat.id, chatId: chat.id,
@ -104,71 +75,153 @@ class NavigatorWrapper extends StatelessWidget {
text: text, text: text,
); );
}, },
); onPressChatTitle: (chat) async {
if (chat.isGroupChat) {
await _routeToScreen(
context,
_chatProfileRoute(
userId: userId,
chatService: chatService,
chatOptions: chatOptions,
chat: chat,
onExit: () => Navigator.of(context).pop(),
).builder(context),
);
} else {
var otherUserId = chat.getOtherUser(userId);
var otherUser =
await chatService.getUser(userId: otherUserId).first;
if (!context.mounted) return;
await _routeToScreen(
context,
_chatProfileRoute(
userId: userId,
chatService: chatService,
chatOptions: chatOptions,
user: otherUser,
onExit: () => Navigator.of(context).pop(),
).builder(context),
);
}
},
onPressUserProfile: (user) async => _routeToScreen(
context,
_chatProfileRoute(
userId: userId,
chatService: chatService,
chatOptions: chatOptions,
user: user,
onExit: () => Navigator.of(context).pop(),
).builder(context),
),
),
);
/// The chat profile screen MaterialPageRoute _chatProfileRoute({
Widget chatProfileScreen( required String userId,
BuildContext context, required ChatService chatService,
UserModel? user, required ChatOptions chatOptions,
ChatModel? chat, required VoidCallback onExit,
) => UserModel? user,
ChatProfileScreen( ChatModel? chat,
}) =>
MaterialPageRoute(
builder: (context) => ChatProfileScreen(
userModel: user, userModel: user,
chatModel: chat, chatModel: chat,
onExit: () => Navigator.of(context).pop(), onExit: onExit,
onTapUser: (userId) async { onTapUser: (userId) async {
var user = await chatService.getUser(userId: userId).first; var user = await chatService.getUser(userId: userId).first;
if (!context.mounted) return; if (!context.mounted) return;
await _routeToScreen(context, chatProfileScreen(context, user, null)); await _routeToScreen(
context,
_chatProfileRoute(
userId: userId,
chatService: chatService,
chatOptions: chatOptions,
user: user,
onExit: () => Navigator.of(context).pop(),
).builder(context),
);
}, },
onPressStartChat: (userId) async { onPressStartChat: (userId) async {
var chat = await _createChat(userId); var chat = await _createChat(userId, chatService, userId);
if (!context.mounted) return; if (!context.mounted) return;
return _routeToScreen( await _routeToScreen(
context, context,
chatDetailScreen( chatDetailRoute(
context, chat: chat,
chat, userId: userId,
() => Navigator.of(context).pop(), chatService: chatService,
), chatOptions: chatOptions,
onExit: () => Navigator.of(context).pop(),
).builder(context),
); );
}, },
); ),
);
/// The new chat screen MaterialPageRoute _newChatRoute({
Widget newChatScreen(BuildContext context) => NewChatScreen( required String userId,
required ChatService chatService,
required ChatOptions chatOptions,
}) =>
MaterialPageRoute(
builder: (context) => NewChatScreen(
onExit: () => Navigator.of(context).pop(), onExit: () => Navigator.of(context).pop(),
onPressCreateGroupChat: () async => onPressCreateGroupChat: () async => _routeToScreen(
_routeToScreen(context, newGroupChatScreen(context)), context,
_newGroupChatRoute(
userId: userId,
chatService: chatService,
chatOptions: chatOptions,
).builder(context),
),
onPressCreateChat: (user) async { onPressCreateChat: (user) async {
var chat = await _createChat(user.id); var chat = await _createChat(user.id, chatService, userId);
if (!context.mounted) return; if (!context.mounted) return;
return _replaceCurrentScreen( await _replaceCurrentScreen(
context, context,
chatDetailScreen( chatDetailRoute(
context, chat: chat,
chat, userId: userId,
() => Navigator.of(context).pop(), chatService: chatService,
), chatOptions: chatOptions,
onExit: () => Navigator.of(context).pop(),
).builder(context),
); );
}, },
); ),
);
/// The new group chat screen MaterialPageRoute _newGroupChatRoute({
Widget newGroupChatScreen(BuildContext context) => NewGroupChatScreen( required String userId,
required ChatService chatService,
required ChatOptions chatOptions,
}) =>
MaterialPageRoute(
builder: (context) => NewGroupChatScreen(
onExit: () => Navigator.of(context).pop(), onExit: () => Navigator.of(context).pop(),
onContinue: (users) async => _replaceCurrentScreen( onContinue: (users) async => _replaceCurrentScreen(
context, context,
newGroupChatOverview(context, users), _newGroupChatOverviewRoute(
userId: userId,
chatService: chatService,
chatOptions: chatOptions,
users: users,
).builder(context),
), ),
); ),
);
/// The new group chat overview screen MaterialPageRoute _newGroupChatOverviewRoute({
Widget newGroupChatOverview(BuildContext context, List<UserModel> users) => required String userId,
NewGroupChatOverview( required ChatService chatService,
required ChatOptions chatOptions,
required List<UserModel> users,
}) =>
MaterialPageRoute(
builder: (context) => NewGroupChatOverview(
users: users, users: users,
onExit: () => Navigator.of(context).pop(), onExit: () => Navigator.of(context).pop(),
onComplete: (users, title, description, image) async { onComplete: (users, title, description, image) async {
@ -184,116 +237,114 @@ class NavigatorWrapper extends StatelessWidget {
title, title,
description, description,
path, path,
chatService,
userId,
); );
if (!context.mounted) return; if (!context.mounted) return;
return _replaceCurrentScreen( await _replaceCurrentScreen(
context, context,
chatDetailScreen( chatDetailRoute(
context, chat: chat,
chat, userId: userId,
() => Navigator.of(context).pop(), chatService: chatService,
), chatOptions: chatOptions,
onExit: () => Navigator.of(context).pop(),
).builder(context),
); );
}, },
); ),
);
/// Creates a group chat /// Helper function to create a chat
Future<ChatModel> _createGroupChat( Future<ChatModel> _createChat(
List<UserModel> userModels, String otherUserId,
String title, ChatService chatService,
String description, String userId,
String? imageUrl, ) async {
) async { ChatModel? chat;
ChatModel? chat; try {
try { chat = await chatService.getChatByUser(
chat = await chatService.getGroupChatByUser( currentUser: userId,
currentUser: userId, otherUser: otherUserId,
otherUsers: userModels, );
chatName: title, } on Exception catch (_) {
description: description, chat = null;
);
} on Exception catch (_) {
chat = null;
}
if (chat == null) {
var currentUser = await chatService.getUser(userId: userId).first;
var otherUsers = await Future.wait(
userModels.map((e) => chatService.getUser(userId: e.id).first),
);
await chatService.createChat(
isGroupChat: true,
users: [currentUser, ...otherUsers],
chatName: title,
description: description,
imageUrl: imageUrl,
);
var chat = await chatService.getGroupChatByUser(
currentUser: userId,
otherUsers: otherUsers,
chatName: title,
description: description,
);
if (chat == null) {
throw Exception("Chat not created");
}
return chat;
}
return chat;
} }
if (chat == null) {
/// Creates a chat await chatService.createChat(
Future<ChatModel> _createChat(String otherUserId) async { isGroupChat: false,
ChatModel? chat; users: [
await chatService.getUser(userId: userId).first,
try { await chatService.getUser(userId: otherUserId).first,
chat = await chatService.getChatByUser( ],
currentUser: userId, );
otherUser: otherUserId, chat = await chatService.getChatByUser(
); currentUser: userId,
} on Exception catch (_) { otherUser: otherUserId,
chat = null; );
} if (chat == null) throw Exception("Chat not created");
if (chat == null) {
var currentUser = await chatService.getUser(userId: userId).first;
var otherUser = await chatService.getUser(userId: otherUserId).first;
await chatService.createChat(
isGroupChat: false,
users: [currentUser, otherUser],
);
var chat = await chatService.getChatByUser(
currentUser: userId,
otherUser: otherUserId,
);
if (chat == null) {
throw Exception("Chat not created");
}
return chat;
}
return chat;
} }
return chat;
/// Routes to a new screen for the userstory
Future _routeToScreen(BuildContext context, Widget screen) async =>
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => screen),
);
/// Replaces the current screen with a new screen for the userstory
Future _replaceCurrentScreen(BuildContext context, Widget screen) async =>
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (context) => screen),
);
} }
/// Helper function to create a group chat
Future<ChatModel> _createGroupChat(
List<UserModel> userModels,
String title,
String description,
String? imageUrl,
ChatService chatService,
String userId,
) async {
ChatModel? chat;
try {
chat = await chatService.getGroupChatByUser(
currentUser: userId,
otherUsers: userModels,
chatName: title,
description: description,
);
} on Exception catch (_) {
chat = null;
}
if (chat == null) {
var currentUser = await chatService.getUser(userId: userId).first;
var otherUsers = await Future.wait(
userModels.map((e) => chatService.getUser(userId: e.id).first),
);
await chatService.createChat(
isGroupChat: true,
users: [currentUser, ...otherUsers],
chatName: title,
description: description,
imageUrl: imageUrl,
);
chat = await chatService.getGroupChatByUser(
currentUser: userId,
otherUsers: otherUsers,
chatName: title,
description: description,
);
if (chat == null) {
throw Exception("Group chat not created");
}
}
return chat;
}
/// Routes to a new screen for the userstory
Future _routeToScreen(BuildContext context, Widget screen) async =>
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => screen),
);
/// Replaces the current screen with a new screen for the userstory
Future _replaceCurrentScreen(BuildContext context, Widget screen) async =>
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (context) => screen),
);

View file

@ -47,42 +47,34 @@ class ChatProfileScreen extends HookWidget {
return () => chatScope.popHandler.remove(onExit); return () => chatScope.popHandler.remove(onExit);
}); });
var appBar = _AppBar(
user: userModel,
chat: chatModel,
options: options,
);
var body = _Body(
currentUser: userId,
options: options,
service: service,
user: userModel,
chat: chatModel,
onTapUser: onTapUser,
onPressStartChat: onPressStartChat,
);
if (options.builders.baseScreenBuilder == null) { if (options.builders.baseScreenBuilder == null) {
return Scaffold( return Scaffold(
appBar: _AppBar( appBar: appBar,
user: userModel, body: body,
chat: chatModel,
options: options,
),
body: _Body(
currentUser: userId,
options: options,
service: service,
user: userModel,
chat: chatModel,
onTapUser: onTapUser,
onPressStartChat: onPressStartChat,
),
); );
} }
return options.builders.baseScreenBuilder!.call( return options.builders.baseScreenBuilder!.call(
context, context,
mapScreenType, mapScreenType,
_AppBar( appBar,
user: userModel, body,
chat: chatModel,
options: options,
),
_Body(
currentUser: userId,
options: options,
service: service,
user: userModel,
chat: chatModel,
onTapUser: onTapUser,
onPressStartChat: onPressStartChat,
),
); );
} }
} }
@ -102,8 +94,7 @@ class _AppBar extends StatelessWidget implements PreferredSizeWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
var theme = Theme.of(context); var theme = Theme.of(context);
return AppBar( return AppBar(
iconTheme: theme.appBarTheme.iconTheme ?? iconTheme: theme.appBarTheme.iconTheme,
const IconThemeData(color: Colors.white),
title: Text( title: Text(
user != null user != null
? "${user!.fullname}" ? "${user!.fullname}"
@ -143,57 +134,58 @@ class _Body extends StatelessWidget {
var chatUserDisplay = Wrap( var chatUserDisplay = Wrap(
children: [ children: [
...chat!.users.map( if (chat != null) ...[
(tappedUser) => Padding( ...chat!.users.map(
padding: const EdgeInsets.only( (tappedUser) => Padding(
bottom: 8, padding: const EdgeInsets.only(
right: 8, bottom: 8,
), right: 8,
child: InkWell( ),
onTap: () { child: InkWell(
onTapUser?.call(tappedUser); onTap: () => onTapUser?.call(tappedUser),
}, child: Column(
child: Column( mainAxisAlignment: MainAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisSize: MainAxisSize.min,
mainAxisSize: MainAxisSize.min, children: [
children: [ FutureBuilder<UserModel>(
FutureBuilder<UserModel>( future: service.getUser(userId: tappedUser).first,
future: service.getUser(userId: tappedUser).first, builder: (context, snapshot) {
builder: (context, snapshot) { if (snapshot.connectionState ==
if (snapshot.connectionState == ConnectionState.waiting) { ConnectionState.waiting) {
return const CircularProgressIndicator(); return const CircularProgressIndicator();
} }
var user = snapshot.data; var user = snapshot.data;
if (user == null) { if (user == null) {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
return options.builders.userAvatarBuilder?.call( return options.builders.userAvatarBuilder?.call(
context, context,
user, user,
44, 44,
) ?? ) ??
Avatar( Avatar(
boxfit: BoxFit.cover, boxfit: BoxFit.cover,
user: User( user: User(
firstName: user.firstName, firstName: user.firstName,
lastName: user.lastName, lastName: user.lastName,
imageUrl: imageUrl:
user.imageUrl != null || user.imageUrl != "" user.imageUrl != null || user.imageUrl != ""
? user.imageUrl ? user.imageUrl
: null, : null,
), ),
size: 60, size: 60,
); );
}, },
), ),
], ],
),
), ),
), ),
), ),
), ],
], ],
); );
@ -210,6 +202,7 @@ class _Body extends StatelessWidget {
firstName: options.translations.groupNameEmpty, firstName: options.translations.groupNameEmpty,
), ),
) as UserModel; ) as UserModel;
return Stack( return Stack(
children: [ children: [
ListView( ListView(
@ -268,23 +261,17 @@ class _Body extends StatelessWidget {
options.translations.groupProfileBioHeader, options.translations.groupProfileBioHeader,
style: theme.textTheme.titleMedium, style: theme.textTheme.titleMedium,
), ),
const SizedBox( const SizedBox(height: 12),
height: 12,
),
Text( Text(
chat!.description ?? "", chat!.description ?? "",
style: theme.textTheme.bodyMedium, style: theme.textTheme.bodyMedium,
), ),
const SizedBox( const SizedBox(height: 12),
height: 12,
),
Text( Text(
options.translations.chatProfileUsers, options.translations.chatProfileUsers,
style: theme.textTheme.titleMedium, style: theme.textTheme.titleMedium,
), ),
const SizedBox( const SizedBox(height: 12),
height: 12,
),
chatUserDisplay, chatUserDisplay,
], ],
), ),