mirror of
https://github.com/Iconica-Development/flutter_chat.git
synced 2025-05-18 18:33:49 +02:00
Merge pull request #92 from Iconica-Development/bugfix/feedback
fix: feedback
This commit is contained in:
commit
5e4a9c7ab4
38 changed files with 702 additions and 625 deletions
|
@ -1,3 +1,10 @@
|
|||
## 3.0.0
|
||||
|
||||
- Add theming
|
||||
- add validator for group name
|
||||
- fix spamming buttons
|
||||
- fix user list flickering on the group creation screen
|
||||
|
||||
## 2.0.0
|
||||
|
||||
- Add a serviceBuilder to the userstory configuration
|
||||
|
|
|
@ -1,28 +1,9 @@
|
|||
# This file configures the analyzer, which statically analyzes Dart code to
|
||||
# check for errors, warnings, and lints.
|
||||
#
|
||||
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
||||
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
||||
# invoked from the command line by running `flutter analyze`.
|
||||
include: package:flutter_iconica_analysis/analysis_options.yaml
|
||||
|
||||
# The following line activates a set of recommended lints for Flutter apps,
|
||||
# packages, and plugins designed to encourage good coding practices.
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
# Possible to overwrite the rules from the package
|
||||
|
||||
analyzer:
|
||||
exclude:
|
||||
|
||||
linter:
|
||||
# The lint rules applied to this project can be customized in the
|
||||
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||
# included above or to enable additional rules. A list of all available lints
|
||||
# and their documentation is published at https://dart.dev/lints.
|
||||
#
|
||||
# Instead of disabling a lint rule for the entire project in the
|
||||
# section below, it can also be suppressed for a single line of code
|
||||
# or a specific dart file by using the `// ignore: name_of_lint` and
|
||||
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||
# producing the lint.
|
||||
rules:
|
||||
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_chat/flutter_chat.dart';
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter_chat/flutter_chat.dart";
|
||||
|
||||
void main(List<String> args) async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
@ -11,25 +11,22 @@ class App extends StatelessWidget {
|
|||
const App({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const MaterialApp(
|
||||
home: Home(),
|
||||
);
|
||||
}
|
||||
Widget build(BuildContext context) => const MaterialApp(
|
||||
home: Home(),
|
||||
);
|
||||
}
|
||||
|
||||
class Home extends StatelessWidget {
|
||||
const Home({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: chatNavigatorUserStory(context,
|
||||
configuration: ChatUserStoryConfiguration(
|
||||
chatService: LocalChatService(),
|
||||
chatOptionsBuilder: (ctx) => ChatOptions(
|
||||
noChatsPlaceholderBuilder: (translations) =>
|
||||
Text(translations.noUsersFound),
|
||||
))));
|
||||
}
|
||||
Widget build(BuildContext context) => Center(
|
||||
child: chatNavigatorUserStory(
|
||||
context,
|
||||
configuration: ChatUserStoryConfiguration(
|
||||
chatService: LocalChatService(),
|
||||
chatOptionsBuilder: (ctx) => const ChatOptions(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -16,11 +16,23 @@ dependencies:
|
|||
path: ../
|
||||
flutter_chat_firebase:
|
||||
path: ../../flutter_chat_firebase
|
||||
dependency_overrides:
|
||||
flutter_chat:
|
||||
path: ../../flutter_chat
|
||||
flutter_chat_interface:
|
||||
path: ../../flutter_chat_interface
|
||||
flutter_chat_local:
|
||||
path: ../../flutter_chat_local
|
||||
flutter_chat_view:
|
||||
path: ../../flutter_chat_view
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^2.0.0
|
||||
flutter_iconica_analysis:
|
||||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_iconica_analysis
|
||||
ref: 7.0.0
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
// gestures. You can also use WidgetTester to find child widgets in the widget
|
||||
// tree, read text, and verify that the values of widget properties are correct.
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import "package:flutter_test/flutter_test.dart";
|
||||
|
||||
void main() {
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||
testWidgets("Counter increments smoke test", (WidgetTester tester) async {
|
||||
expect(true, true);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -284,7 +284,7 @@ Widget _newGroupChatOverviewScreenRoute(
|
|||
),
|
||||
);
|
||||
if (context.mounted) {
|
||||
await Navigator.of(context).push(
|
||||
await Navigator.of(context).pushReplacement(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => _chatDetailScreenRoute(
|
||||
configuration,
|
||||
|
|
|
@ -14,6 +14,7 @@ List<GoRoute> getChatStoryRoutes(
|
|||
GoRoute(
|
||||
path: ChatUserStoryRoutes.chatScreen,
|
||||
pageBuilder: (context, state) {
|
||||
var theme = Theme.of(context);
|
||||
var service = configuration.chatServiceBuilder?.call(context) ??
|
||||
configuration.chatService;
|
||||
var chatScreen = ChatScreen(
|
||||
|
@ -47,6 +48,7 @@ List<GoRoute> getChatStoryRoutes(
|
|||
chatScreen,
|
||||
) ??
|
||||
Scaffold(
|
||||
backgroundColor: theme.colorScheme.surface,
|
||||
body: chatScreen,
|
||||
),
|
||||
);
|
||||
|
@ -58,6 +60,8 @@ List<GoRoute> getChatStoryRoutes(
|
|||
var chatId = state.pathParameters['id'];
|
||||
var service = configuration.chatServiceBuilder?.call(context) ??
|
||||
configuration.chatService;
|
||||
var theme = Theme.of(context);
|
||||
|
||||
var chatDetailScreen = ChatDetailScreen(
|
||||
chatTitleBuilder: configuration.chatTitleBuilder,
|
||||
usernameBuilder: configuration.usernameBuilder,
|
||||
|
@ -118,6 +122,7 @@ List<GoRoute> getChatStoryRoutes(
|
|||
chatDetailScreen,
|
||||
) ??
|
||||
Scaffold(
|
||||
backgroundColor: theme.colorScheme.surface,
|
||||
body: chatDetailScreen,
|
||||
),
|
||||
);
|
||||
|
@ -128,6 +133,8 @@ List<GoRoute> getChatStoryRoutes(
|
|||
pageBuilder: (context, state) {
|
||||
var service = configuration.chatServiceBuilder?.call(context) ??
|
||||
configuration.chatService;
|
||||
var theme = Theme.of(context);
|
||||
|
||||
var newChatScreen = NewChatScreen(
|
||||
options: configuration.chatOptionsBuilder(context),
|
||||
translations: configuration.translationsBuilder?.call(context) ??
|
||||
|
@ -165,6 +172,7 @@ List<GoRoute> getChatStoryRoutes(
|
|||
newChatScreen,
|
||||
) ??
|
||||
Scaffold(
|
||||
backgroundColor: theme.colorScheme.surface,
|
||||
body: newChatScreen,
|
||||
),
|
||||
);
|
||||
|
@ -175,6 +183,8 @@ List<GoRoute> getChatStoryRoutes(
|
|||
pageBuilder: (context, state) {
|
||||
var service = configuration.chatServiceBuilder?.call(context) ??
|
||||
configuration.chatService;
|
||||
var theme = Theme.of(context);
|
||||
|
||||
var newGroupChatScreen = NewGroupChatScreen(
|
||||
options: configuration.chatOptionsBuilder(context),
|
||||
translations: configuration.translationsBuilder?.call(context) ??
|
||||
|
@ -193,6 +203,7 @@ List<GoRoute> getChatStoryRoutes(
|
|||
newGroupChatScreen,
|
||||
) ??
|
||||
Scaffold(
|
||||
backgroundColor: theme.colorScheme.surface,
|
||||
body: newGroupChatScreen,
|
||||
),
|
||||
);
|
||||
|
@ -204,6 +215,8 @@ List<GoRoute> getChatStoryRoutes(
|
|||
var service = configuration.chatServiceBuilder?.call(context) ??
|
||||
configuration.chatService;
|
||||
var users = state.extra! as List<ChatUserModel>;
|
||||
var theme = Theme.of(context);
|
||||
|
||||
var newGroupChatOverviewScreen = NewGroupChatOverviewScreen(
|
||||
options: configuration.chatOptionsBuilder(context),
|
||||
translations: configuration.translationsBuilder?.call(context) ??
|
||||
|
@ -223,7 +236,7 @@ List<GoRoute> getChatStoryRoutes(
|
|||
),
|
||||
);
|
||||
if (context.mounted) {
|
||||
await context.push(
|
||||
context.go(
|
||||
ChatUserStoryRoutes.chatDetailViewPath(chat.id ?? ''),
|
||||
);
|
||||
}
|
||||
|
@ -237,6 +250,7 @@ List<GoRoute> getChatStoryRoutes(
|
|||
newGroupChatOverviewScreen,
|
||||
) ??
|
||||
Scaffold(
|
||||
backgroundColor: theme.colorScheme.surface,
|
||||
body: newGroupChatOverviewScreen,
|
||||
),
|
||||
);
|
||||
|
@ -250,6 +264,8 @@ List<GoRoute> getChatStoryRoutes(
|
|||
var id = userId == 'null' ? null : userId;
|
||||
var service = configuration.chatServiceBuilder?.call(context) ??
|
||||
configuration.chatService;
|
||||
var theme = Theme.of(context);
|
||||
|
||||
var profileScreen = ChatProfileScreen(
|
||||
translations: configuration.translationsBuilder?.call(context) ??
|
||||
configuration.translations,
|
||||
|
@ -274,6 +290,7 @@ List<GoRoute> getChatStoryRoutes(
|
|||
profileScreen,
|
||||
) ??
|
||||
Scaffold(
|
||||
backgroundColor: theme.colorScheme.surface,
|
||||
body: profileScreen,
|
||||
),
|
||||
);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
name: flutter_chat
|
||||
description: A new Flutter package project.
|
||||
version: 2.0.0
|
||||
version: 3.0.0
|
||||
|
||||
publish_to: none
|
||||
|
||||
|
@ -20,23 +20,23 @@ dependencies:
|
|||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_chat
|
||||
path: packages/flutter_chat_view
|
||||
ref: 2.0.0
|
||||
ref: 3.0.0
|
||||
flutter_chat_interface:
|
||||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_chat
|
||||
path: packages/flutter_chat_interface
|
||||
ref: 2.0.0
|
||||
ref: 3.0.0
|
||||
flutter_chat_local:
|
||||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_chat
|
||||
path: packages/flutter_chat_local
|
||||
ref: 2.0.0
|
||||
ref: 3.0.0
|
||||
uuid: ^4.3.3
|
||||
|
||||
dev_dependencies:
|
||||
flutter_iconica_analysis:
|
||||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_iconica_analysis
|
||||
ref: 6.0.0
|
||||
ref: 7.0.0
|
||||
|
||||
flutter:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
name: flutter_chat_firebase
|
||||
description: A new Flutter package project.
|
||||
version: 2.0.0
|
||||
version: 3.0.0
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
|
@ -23,12 +23,12 @@ dependencies:
|
|||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_chat
|
||||
path: packages/flutter_chat_interface
|
||||
ref: 2.0.0
|
||||
ref: 3.0.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_iconica_analysis:
|
||||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_iconica_analysis
|
||||
ref: 6.0.0
|
||||
ref: 7.0.0
|
||||
|
||||
flutter:
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
///
|
||||
library flutter_chat_interface;
|
||||
|
||||
export 'package:flutter_chat_interface/src/chat_data_provider.dart';
|
||||
export 'package:flutter_chat_interface/src/model/model.dart';
|
||||
export 'package:flutter_chat_interface/src/service/service.dart';
|
||||
export "package:flutter_chat_interface/src/chat_data_provider.dart";
|
||||
export "package:flutter_chat_interface/src/model/model.dart";
|
||||
export "package:flutter_chat_interface/src/service/service.dart";
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter_chat_interface/flutter_chat_interface.dart';
|
||||
import 'package:flutter_data_interface/flutter_data_interface.dart';
|
||||
import "package:flutter_chat_interface/flutter_chat_interface.dart";
|
||||
import "package:flutter_data_interface/flutter_data_interface.dart";
|
||||
|
||||
class ChatDataProvider extends DataInterface {
|
||||
ChatDataProvider({
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter_chat_interface/flutter_chat_interface.dart';
|
||||
import "package:flutter_chat_interface/flutter_chat_interface.dart";
|
||||
|
||||
abstract class ChatModelInterface {
|
||||
ChatModelInterface copyWith();
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter_chat_interface/flutter_chat_interface.dart';
|
||||
import "package:flutter_chat_interface/flutter_chat_interface.dart";
|
||||
|
||||
/// An abstract class defining the interface for an image message in a chat.
|
||||
abstract class ChatImageMessageModelInterface extends ChatMessageModel {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter_chat_interface/src/model/chat_user.dart';
|
||||
import "package:flutter_chat_interface/src/model/chat_user.dart";
|
||||
|
||||
abstract class ChatMessageModelInterface {
|
||||
ChatUserModel get sender;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter_chat_interface/flutter_chat_interface.dart';
|
||||
import "package:flutter_chat_interface/flutter_chat_interface.dart";
|
||||
|
||||
abstract class ChatTextMessageModelInterface extends ChatMessageModel {
|
||||
ChatTextMessageModelInterface({
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import "package:flutter/material.dart";
|
||||
|
||||
abstract class ChatUserModelInterface {
|
||||
String? get id;
|
||||
|
@ -49,17 +49,17 @@ class ChatUserModel implements ChatUserModelInterface {
|
|||
|
||||
@override
|
||||
String? get fullName {
|
||||
var fullName = '';
|
||||
var fullName = "";
|
||||
|
||||
if (firstName != null && lastName != null) {
|
||||
fullName += '$firstName $lastName';
|
||||
fullName += "$firstName $lastName";
|
||||
} else if (firstName != null) {
|
||||
fullName += firstName!;
|
||||
} else if (lastName != null) {
|
||||
fullName += lastName!;
|
||||
}
|
||||
|
||||
return fullName == '' ? null : fullName;
|
||||
return fullName == "" ? null : fullName;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter_chat_interface/flutter_chat_interface.dart';
|
||||
import "package:flutter_chat_interface/flutter_chat_interface.dart";
|
||||
|
||||
abstract class GroupChatModelInterface extends ChatModel {
|
||||
GroupChatModelInterface({
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
export 'chat.dart';
|
||||
export 'chat_image_message.dart';
|
||||
export 'chat_message.dart';
|
||||
export 'chat_text_message.dart';
|
||||
export 'chat_user.dart';
|
||||
export 'group_chat.dart';
|
||||
export 'personal_chat.dart';
|
||||
export "chat.dart";
|
||||
export "chat_image_message.dart";
|
||||
export "chat_message.dart";
|
||||
export "chat_text_message.dart";
|
||||
export "chat_user.dart";
|
||||
export "group_chat.dart";
|
||||
export "personal_chat.dart";
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import 'package:flutter_chat_interface/flutter_chat_interface.dart';
|
||||
import "package:flutter_chat_interface/flutter_chat_interface.dart";
|
||||
|
||||
abstract class PersonalChatModelInterface extends ChatModel {
|
||||
PersonalChatModelInterface({
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'dart:typed_data';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_chat_interface/flutter_chat_interface.dart';
|
||||
import "dart:typed_data";
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter_chat_interface/flutter_chat_interface.dart";
|
||||
|
||||
/// An abstract class defining the interface for a chat detail service.
|
||||
abstract class ChatDetailService with ChangeNotifier {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:flutter_chat_interface/flutter_chat_interface.dart';
|
||||
import "package:flutter_chat_interface/flutter_chat_interface.dart";
|
||||
|
||||
abstract class ChatOverviewService {
|
||||
/// Retrieves a stream of chats.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
||||
import 'package:flutter_chat_interface/flutter_chat_interface.dart';
|
||||
import "package:flutter_chat_interface/flutter_chat_interface.dart";
|
||||
|
||||
class ChatService {
|
||||
final ChatUserService chatUserService;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export 'chat_detail_service.dart';
|
||||
export 'chat_overview_service.dart';
|
||||
export 'chat_service.dart';
|
||||
export 'user_service.dart';
|
||||
export "chat_detail_service.dart";
|
||||
export "chat_overview_service.dart";
|
||||
export "chat_service.dart";
|
||||
export "user_service.dart";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:flutter_chat_interface/flutter_chat_interface.dart';
|
||||
import "package:flutter_chat_interface/flutter_chat_interface.dart";
|
||||
|
||||
abstract class ChatUserService {
|
||||
/// Retrieves a user based on the ID.
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
name: flutter_chat_interface
|
||||
description: A new Flutter package project.
|
||||
version: 2.0.0
|
||||
version: 3.0.0
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
|
@ -23,6 +23,6 @@ dev_dependencies:
|
|||
flutter_iconica_analysis:
|
||||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_iconica_analysis
|
||||
ref: 6.0.0
|
||||
ref: 7.0.0
|
||||
|
||||
flutter:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
name: flutter_chat_local
|
||||
description: "A new Flutter package project."
|
||||
version: 2.0.0
|
||||
version: 3.0.0
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
|
@ -14,7 +14,7 @@ dependencies:
|
|||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_chat
|
||||
path: packages/flutter_chat_interface
|
||||
ref: 2.0.0
|
||||
ref: 3.0.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
@ -22,5 +22,5 @@ dev_dependencies:
|
|||
flutter_iconica_analysis:
|
||||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_iconica_analysis
|
||||
ref: 6.0.0
|
||||
ref: 7.0.0
|
||||
flutter:
|
||||
|
|
|
@ -73,7 +73,7 @@ class _ChatBottomState extends State<ChatBottom> {
|
|||
IconButton(
|
||||
onPressed: widget.onPressSelectImage,
|
||||
icon: Icon(
|
||||
Icons.image,
|
||||
Icons.image_outlined,
|
||||
color: widget.iconColor,
|
||||
),
|
||||
),
|
||||
|
@ -105,6 +105,7 @@ class _ChatBottomState extends State<ChatBottom> {
|
|||
],
|
||||
),
|
||||
widget.translations,
|
||||
context,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -54,7 +54,7 @@ class _ChatDetailRowState extends State<ChatDetailRow> {
|
|||
widget.message.timestamp.minute ==
|
||||
widget.previousMessage?.timestamp.minute;
|
||||
var hasHeader = isNewDate || isSameSender;
|
||||
|
||||
var theme = Theme.of(context);
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: isNewDate || isSameSender ? 25.0 : 0,
|
||||
|
@ -160,10 +160,7 @@ class _ChatDetailRowState extends State<ChatDetailRow> {
|
|||
)
|
||||
.split(' ')
|
||||
.last,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: Color(0xFFBBBBBB),
|
||||
),
|
||||
style: theme.textTheme.bodySmall,
|
||||
textAlign: TextAlign.end,
|
||||
),
|
||||
],
|
||||
|
|
|
@ -30,84 +30,83 @@ class ChatRow extends StatelessWidget {
|
|||
final Widget? avatar;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 10.0),
|
||||
child: avatar,
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: unreadMessages > 0
|
||||
? FontWeight.w900
|
||||
: FontWeight.w500,
|
||||
Widget build(BuildContext context) {
|
||||
var theme = Theme.of(context);
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 10.0),
|
||||
child: avatar,
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: unreadMessages > 0
|
||||
? theme.textTheme.bodyLarge
|
||||
: theme.textTheme.bodyMedium,
|
||||
),
|
||||
if (subTitle != null) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 3.0),
|
||||
child: Text(
|
||||
subTitle!,
|
||||
style: unreadMessages > 0
|
||||
? theme.textTheme.bodyLarge
|
||||
: theme.textTheme.bodyMedium,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 2,
|
||||
),
|
||||
),
|
||||
if (subTitle != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 3.0),
|
||||
child: Text(
|
||||
subTitle!,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: unreadMessages > 0
|
||||
? FontWeight.w500
|
||||
: FontWeight.w300,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 2,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
if (lastUsed != null) // Check if lastUsed is not null
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 4.0),
|
||||
),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
if (lastUsed != null) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 4.0),
|
||||
child: Text(
|
||||
lastUsed!,
|
||||
style: const TextStyle(
|
||||
color: Color(0xFFBBBBBB),
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
if (unreadMessages > 0) ...[
|
||||
Container(
|
||||
width: 20,
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
lastUsed!,
|
||||
unreadMessages.toString(),
|
||||
style: const TextStyle(
|
||||
color: Color(0xFFBBBBBB),
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (unreadMessages > 0) ...[
|
||||
Container(
|
||||
width: 20,
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
unreadMessages.toString(),
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,10 @@ Widget _createNewChatButton(
|
|||
ChatTranslations translations,
|
||||
) =>
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(5, 24, 5, 24),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 24,
|
||||
horizontal: 5,
|
||||
),
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
|
@ -74,7 +77,7 @@ Widget _createNewChatButton(
|
|||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w800,
|
||||
fontSize: 18,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -84,43 +87,43 @@ Widget _createMessageInput(
|
|||
TextEditingController textEditingController,
|
||||
Widget suffixIcon,
|
||||
ChatTranslations translations,
|
||||
) =>
|
||||
TextField(
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
controller: textEditingController,
|
||||
decoration: InputDecoration(
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(26.5),
|
||||
borderSide: const BorderSide(
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(26.5),
|
||||
borderSide: const BorderSide(
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
vertical: 0,
|
||||
horizontal: 30,
|
||||
),
|
||||
hintText: translations.messagePlaceholder,
|
||||
hintStyle: const TextStyle(
|
||||
fontWeight: FontWeight.normal,
|
||||
BuildContext context,
|
||||
) {
|
||||
var theme = Theme.of(context);
|
||||
return TextField(
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
controller: textEditingController,
|
||||
decoration: InputDecoration(
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(25),
|
||||
borderSide: const BorderSide(
|
||||
color: Colors.black,
|
||||
),
|
||||
fillColor: Colors.white,
|
||||
filled: true,
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(26.5),
|
||||
),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
suffixIcon: suffixIcon,
|
||||
),
|
||||
);
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(25),
|
||||
borderSide: const BorderSide(
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
vertical: 0,
|
||||
horizontal: 30,
|
||||
),
|
||||
hintText: translations.messagePlaceholder,
|
||||
hintStyle: theme.inputDecorationTheme.hintStyle,
|
||||
fillColor: Colors.white,
|
||||
filled: true,
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(25),
|
||||
),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
suffixIcon: suffixIcon,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _createChatRowContainer(
|
||||
Widget chatRow,
|
||||
|
@ -130,7 +133,10 @@ Widget _createChatRowContainer(
|
|||
vertical: 12.0,
|
||||
horizontal: 10.0,
|
||||
),
|
||||
child: chatRow,
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: chatRow,
|
||||
),
|
||||
);
|
||||
|
||||
Widget _createImagePickerContainer(
|
||||
|
@ -166,6 +172,7 @@ Widget _createImagePickerContainer(
|
|||
Scaffold _createScaffold(
|
||||
AppBar appbar,
|
||||
Widget body,
|
||||
Color backgroundColor,
|
||||
) =>
|
||||
Scaffold(
|
||||
appBar: appbar,
|
||||
|
@ -196,31 +203,32 @@ Widget _createGroupAvatar(
|
|||
|
||||
Widget _createNoChatsPlaceholder(
|
||||
ChatTranslations translations,
|
||||
) =>
|
||||
Center(
|
||||
child: Text(
|
||||
translations.noChatsFound,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
);
|
||||
BuildContext context,
|
||||
) {
|
||||
var theme = Theme.of(context);
|
||||
return Center(
|
||||
child: Text(
|
||||
translations.noChatsFound,
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.bodySmall,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _createNoUsersPlaceholder(
|
||||
ChatTranslations translations,
|
||||
) =>
|
||||
Center(
|
||||
child: Text(
|
||||
translations.noUsersFound,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
);
|
||||
BuildContext context,
|
||||
) {
|
||||
var theme = Theme.of(context);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
child: Text(
|
||||
translations.noUsersFound,
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.bodySmall,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
typedef ButtonBuilder = Widget Function(
|
||||
BuildContext context,
|
||||
|
@ -232,6 +240,7 @@ typedef TextInputBuilder = Widget Function(
|
|||
TextEditingController textEditingController,
|
||||
Widget suffixIcon,
|
||||
ChatTranslations translations,
|
||||
BuildContext context,
|
||||
);
|
||||
|
||||
typedef ContainerBuilder = Widget Function(
|
||||
|
@ -247,6 +256,7 @@ typedef ImagePickerContainerBuilder = Widget Function(
|
|||
typedef ScaffoldBuilder = Scaffold Function(
|
||||
AppBar appBar,
|
||||
Widget body,
|
||||
Color backgroundColor,
|
||||
);
|
||||
|
||||
typedef UserAvatarBuilder = Widget Function(
|
||||
|
@ -262,8 +272,10 @@ typedef GroupAvatarBuilder = Widget Function(
|
|||
|
||||
typedef NoChatsPlaceholderBuilder = Widget Function(
|
||||
ChatTranslations translations,
|
||||
BuildContext context,
|
||||
);
|
||||
|
||||
typedef NoUsersPlaceholderBuilder = Widget Function(
|
||||
ChatTranslations translations,
|
||||
BuildContext context,
|
||||
);
|
||||
|
|
|
@ -36,13 +36,17 @@ class ChatTranslations {
|
|||
required this.uploadFile,
|
||||
required this.takePicture,
|
||||
required this.anonymousUser,
|
||||
required this.groupNameValidatorEmpty,
|
||||
required this.groupNameValidatorTooLong,
|
||||
required this.groupNameHintText,
|
||||
required this.newGroupChatTitle,
|
||||
});
|
||||
|
||||
/// Default translations for the chat component view
|
||||
const ChatTranslations.empty({
|
||||
this.chatsTitle = 'Chats',
|
||||
this.chatsUnread = 'unread',
|
||||
this.newChatButton = 'Start a chat',
|
||||
this.newChatButton = 'Start chat',
|
||||
this.newGroupChatButton = 'Create a group chat',
|
||||
this.newChatTitle = 'Start a chat',
|
||||
this.image = 'Image',
|
||||
|
@ -68,6 +72,11 @@ class ChatTranslations {
|
|||
this.imagePickerTitle = 'Do you want to upload a file or take a picture?',
|
||||
this.uploadFile = 'UPLOAD FILE',
|
||||
this.takePicture = 'TAKE PICTURE',
|
||||
this.groupNameHintText = 'Group chat name',
|
||||
this.groupNameValidatorEmpty = 'Please enter a group chat name',
|
||||
this.groupNameValidatorTooLong =
|
||||
'Group name is too long, max 15 characters',
|
||||
this.newGroupChatTitle = 'New Group Chat',
|
||||
});
|
||||
|
||||
final String chatsTitle;
|
||||
|
@ -98,6 +107,10 @@ class ChatTranslations {
|
|||
|
||||
/// Shown when the user has no name
|
||||
final String anonymousUser;
|
||||
final String groupNameValidatorEmpty;
|
||||
final String groupNameValidatorTooLong;
|
||||
final String groupNameHintText;
|
||||
final String newGroupChatTitle;
|
||||
|
||||
// copyWith method to override the default values
|
||||
ChatTranslations copyWith({
|
||||
|
@ -127,6 +140,10 @@ class ChatTranslations {
|
|||
String? uploadFile,
|
||||
String? takePicture,
|
||||
String? anonymousUser,
|
||||
String? groupNameValidatorEmpty,
|
||||
String? groupNameValidatorTooLong,
|
||||
String? groupNameHintText,
|
||||
String? newGroupChatTitle,
|
||||
}) =>
|
||||
ChatTranslations(
|
||||
chatsTitle: chatsTitle ?? this.chatsTitle,
|
||||
|
@ -160,5 +177,9 @@ class ChatTranslations {
|
|||
uploadFile: uploadFile ?? this.uploadFile,
|
||||
takePicture: takePicture ?? this.takePicture,
|
||||
anonymousUser: anonymousUser ?? this.anonymousUser,
|
||||
groupNameValidatorEmpty: this.groupNameValidatorEmpty,
|
||||
groupNameValidatorTooLong: this.groupNameValidatorTooLong,
|
||||
groupNameHintText: this.groupNameHintText,
|
||||
newGroupChatTitle: this.newGroupChatTitle,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -168,8 +168,9 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
|||
builder: (context, AsyncSnapshot<ChatModel> snapshot) {
|
||||
var chatModel = snapshot.data;
|
||||
return Scaffold(
|
||||
backgroundColor: theme.colorScheme.surface,
|
||||
appBar: AppBar(
|
||||
backgroundColor: theme.appBarTheme.backgroundColor ?? Colors.black,
|
||||
backgroundColor: theme.appBarTheme.backgroundColor,
|
||||
iconTheme: theme.appBarTheme.iconTheme ??
|
||||
const IconThemeData(color: Colors.white),
|
||||
centerTitle: true,
|
||||
|
@ -188,14 +189,6 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
|||
children: chat == null
|
||||
? []
|
||||
: [
|
||||
if (chatModel is GroupChatModel) ...[
|
||||
widget.options.groupAvatarBuilder(
|
||||
chatModel.title,
|
||||
chatModel.imageUrl,
|
||||
36.0,
|
||||
),
|
||||
] else
|
||||
...[],
|
||||
Padding(
|
||||
padding: (chatModel is GroupChatModel)
|
||||
? const EdgeInsets.only(left: 15.5)
|
||||
|
@ -216,12 +209,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
|||
? chatModel.user.firstName ??
|
||||
widget.translations.anonymousUser
|
||||
: '',
|
||||
style: theme.appBarTheme.titleTextStyle ??
|
||||
TextStyle(
|
||||
fontWeight: FontWeight.w800,
|
||||
fontSize: 24,
|
||||
color: Theme.of(context).primaryColor,
|
||||
),
|
||||
style: theme.appBarTheme.titleTextStyle,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -271,11 +259,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
|||
.writeFirstMessageInGroupChat
|
||||
: widget
|
||||
.translations.writeMessageToStartChat,
|
||||
style: const TextStyle(
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Color.fromRGBO(33, 33, 33, 1),
|
||||
),
|
||||
style: theme.textTheme.bodySmall,
|
||||
),
|
||||
),
|
||||
...detailRows,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_chat_view/flutter_chat_view.dart';
|
||||
import 'package:flutter_chat_view/src/services/profile_service.dart';
|
||||
import 'package:flutter_profile/flutter_profile.dart';
|
||||
|
||||
class ChatProfileScreen extends StatefulWidget {
|
||||
|
@ -35,7 +34,6 @@ class ChatProfileScreen extends StatefulWidget {
|
|||
class _ProfileScreenState extends State<ChatProfileScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var size = MediaQuery.of(context).size;
|
||||
var hasUser = widget.userId == null;
|
||||
var theme = Theme.of(context);
|
||||
return FutureBuilder<dynamic>(
|
||||
|
@ -67,10 +65,10 @@ class _ProfileScreenState extends State<ChatProfileScreen> {
|
|||
imageUrl: data.imageUrl,
|
||||
);
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: theme.colorScheme.surface,
|
||||
appBar: AppBar(
|
||||
backgroundColor: theme.appBarTheme.backgroundColor ?? Colors.black,
|
||||
backgroundColor: theme.appBarTheme.backgroundColor,
|
||||
iconTheme: theme.appBarTheme.iconTheme ??
|
||||
const IconThemeData(color: Colors.white),
|
||||
title: Text(
|
||||
|
@ -81,32 +79,28 @@ class _ProfileScreenState extends State<ChatProfileScreen> {
|
|||
: (data is GroupChatModel)
|
||||
? data.title
|
||||
: '',
|
||||
style: theme.appBarTheme.titleTextStyle ??
|
||||
const TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
style: theme.appBarTheme.titleTextStyle,
|
||||
),
|
||||
),
|
||||
body: snapshot.hasData
|
||||
? ListView(
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
SizedBox(
|
||||
height: 200,
|
||||
width: size.width,
|
||||
child: ProfilePage(
|
||||
user: user!,
|
||||
itemBuilderOptions: ItemBuilderOptions(
|
||||
readOnly: true,
|
||||
),
|
||||
service: ChatProfileService(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 20),
|
||||
child: Avatar(
|
||||
user: user,
|
||||
),
|
||||
),
|
||||
const Divider(
|
||||
color: Colors.white,
|
||||
thickness: 10,
|
||||
),
|
||||
if (data is GroupChatModel) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 100),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 100,
|
||||
vertical: 20,
|
||||
),
|
||||
child: Text(
|
||||
widget.translations.chatProfileUsers,
|
||||
style: const TextStyle(
|
||||
|
|
|
@ -77,16 +77,10 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||
var theme = Theme.of(context);
|
||||
return widget.options.scaffoldBuilder(
|
||||
AppBar(
|
||||
backgroundColor:
|
||||
theme.appBarTheme.backgroundColor ?? const Color(0xff212121),
|
||||
backgroundColor: theme.appBarTheme.backgroundColor,
|
||||
title: Text(
|
||||
translations.chatsTitle,
|
||||
style: theme.appBarTheme.titleTextStyle ??
|
||||
TextStyle(
|
||||
fontWeight: FontWeight.w800,
|
||||
fontSize: 24,
|
||||
color: Theme.of(context).primaryColor,
|
||||
),
|
||||
style: theme.appBarTheme.titleTextStyle,
|
||||
),
|
||||
centerTitle: true,
|
||||
actions: [
|
||||
|
@ -120,7 +114,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||
controller: controller,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
padding: widget.options.paddingAroundChatList ??
|
||||
const EdgeInsets.fromLTRB(28, 16, 28, 0),
|
||||
const EdgeInsets.symmetric(vertical: 16, horizontal: 28),
|
||||
children: [
|
||||
StreamBuilder<List<ChatModel>>(
|
||||
stream: widget.service.chatOverviewService.getChatsStream(),
|
||||
|
@ -138,157 +132,172 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||
return Center(
|
||||
child: Text(
|
||||
translations.noChatsFound,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
style: theme.textTheme.bodySmall,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
_hasCalledOnNoChats =
|
||||
false; // Reset the flag if there are chats
|
||||
_hasCalledOnNoChats = false;
|
||||
}
|
||||
return Column(
|
||||
children: [
|
||||
for (ChatModel chat in (snapshot.data ?? []).where(
|
||||
(chat) => !deletedChats.contains(chat.id),
|
||||
)) ...[
|
||||
Builder(
|
||||
builder: (context) => !(widget
|
||||
.disableDismissForPermanentChats &&
|
||||
!chat.canBeDeleted)
|
||||
? Dismissible(
|
||||
confirmDismiss: (_) async =>
|
||||
widget.deleteChatDialog
|
||||
?.call(context, chat) ??
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (BuildContext context) =>
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
chat.canBeDeleted
|
||||
? translations
|
||||
.deleteChatModalTitle
|
||||
: translations
|
||||
.chatCantBeDeleted,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
if (chat.canBeDeleted)
|
||||
Padding(
|
||||
padding: const EdgeInsets
|
||||
.symmetric(
|
||||
horizontal: 16,
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondary
|
||||
.withOpacity(0.3),
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Builder(
|
||||
builder: (context) => !(widget
|
||||
.disableDismissForPermanentChats &&
|
||||
!chat.canBeDeleted)
|
||||
? Dismissible(
|
||||
confirmDismiss: (_) async =>
|
||||
widget.deleteChatDialog
|
||||
?.call(context, chat) ??
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (BuildContext context) =>
|
||||
Container(
|
||||
padding:
|
||||
const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
chat.canBeDeleted
|
||||
? translations
|
||||
.deleteChatModalTitle
|
||||
: translations
|
||||
.chatCantBeDeleted,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight:
|
||||
FontWeight.bold,
|
||||
),
|
||||
child: Text(
|
||||
translations
|
||||
.deleteChatModalDescription,
|
||||
textAlign:
|
||||
TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
if (chat.canBeDeleted)
|
||||
Padding(
|
||||
padding: const EdgeInsets
|
||||
.symmetric(
|
||||
horizontal: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: () =>
|
||||
Navigator.of(
|
||||
context,
|
||||
).pop(false),
|
||||
child: Text(
|
||||
translations
|
||||
.deleteChatModalCancel,
|
||||
.deleteChatModalDescription,
|
||||
textAlign:
|
||||
TextAlign.center,
|
||||
style: const TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (chat.canBeDeleted)
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
if (chat.canBeDeleted)
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.center,
|
||||
children: [
|
||||
ElevatedButton(
|
||||
style: ElevatedButton
|
||||
.styleFrom(
|
||||
backgroundColor:
|
||||
Theme.of(context)
|
||||
.primaryColor,
|
||||
),
|
||||
onPressed: () =>
|
||||
Navigator.of(
|
||||
context,
|
||||
).pop(
|
||||
true,
|
||||
),
|
||||
).pop(false),
|
||||
child: Text(
|
||||
translations
|
||||
.deleteChatModalConfirm,
|
||||
.deleteChatModalCancel,
|
||||
style:
|
||||
const TextStyle(
|
||||
color: Colors.white,
|
||||
color: Colors.black,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
if (chat.canBeDeleted)
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
if (chat.canBeDeleted)
|
||||
ElevatedButton(
|
||||
style: ElevatedButton
|
||||
.styleFrom(
|
||||
backgroundColor:
|
||||
Theme.of(
|
||||
context,
|
||||
).primaryColor,
|
||||
),
|
||||
onPressed: () =>
|
||||
Navigator.of(
|
||||
context,
|
||||
).pop(
|
||||
true,
|
||||
),
|
||||
child: Text(
|
||||
translations
|
||||
.deleteChatModalConfirm,
|
||||
style:
|
||||
const TextStyle(
|
||||
color:
|
||||
Colors.white,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
onDismissed: (_) {
|
||||
setState(() {
|
||||
deletedChats.add(chat.id!);
|
||||
});
|
||||
widget.onDeleteChat(chat);
|
||||
},
|
||||
background: Container(
|
||||
color: Colors.red,
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
translations.deleteChatButton,
|
||||
),
|
||||
),
|
||||
),
|
||||
onDismissed: (_) {
|
||||
setState(() {
|
||||
deletedChats.add(chat.id!);
|
||||
});
|
||||
widget.onDeleteChat(chat);
|
||||
},
|
||||
background: Container(
|
||||
color: Colors.red,
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
translations.deleteChatButton,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
key: ValueKey(
|
||||
chat.id.toString(),
|
||||
),
|
||||
child: ChatListItem(
|
||||
key: ValueKey(
|
||||
chat.id.toString(),
|
||||
),
|
||||
child: ChatListItem(
|
||||
widget: widget,
|
||||
chat: chat,
|
||||
translations: translations,
|
||||
dateFormatter: _dateFormatter,
|
||||
),
|
||||
)
|
||||
: ChatListItem(
|
||||
widget: widget,
|
||||
chat: chat,
|
||||
translations: translations,
|
||||
dateFormatter: _dateFormatter,
|
||||
),
|
||||
)
|
||||
: ChatListItem(
|
||||
widget: widget,
|
||||
chat: chat,
|
||||
translations: translations,
|
||||
dateFormatter: _dateFormatter,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
|
@ -308,6 +317,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||
),
|
||||
],
|
||||
),
|
||||
theme.colorScheme.surface,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -327,59 +337,52 @@ class ChatListItem extends StatelessWidget {
|
|||
final DateFormatter _dateFormatter;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Column(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => widget.onPressChat(chat),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: widget.options.chatRowContainerBuilder(
|
||||
(chat is PersonalChatModel)
|
||||
? ChatRow(
|
||||
unreadMessages: chat.unreadMessages ?? 0,
|
||||
avatar: widget.options.userAvatarBuilder(
|
||||
(chat as PersonalChatModel).user,
|
||||
40.0,
|
||||
),
|
||||
title: (chat as PersonalChatModel).user.fullName ??
|
||||
translations.anonymousUser,
|
||||
subTitle: chat.lastMessage != null
|
||||
? chat.lastMessage is ChatTextMessageModel
|
||||
? (chat.lastMessage! as ChatTextMessageModel)
|
||||
.text
|
||||
: '📷 '
|
||||
'${translations.image}'
|
||||
: '',
|
||||
lastUsed: chat.lastUsed != null
|
||||
? _dateFormatter.format(
|
||||
date: chat.lastUsed!,
|
||||
)
|
||||
: null,
|
||||
)
|
||||
: ChatRow(
|
||||
title: (chat as GroupChatModel).title,
|
||||
unreadMessages: chat.unreadMessages ?? 0,
|
||||
subTitle: chat.lastMessage != null
|
||||
? chat.lastMessage is ChatTextMessageModel
|
||||
? (chat.lastMessage! as ChatTextMessageModel)
|
||||
.text
|
||||
: '📷 '
|
||||
'${translations.image}'
|
||||
: '',
|
||||
avatar: widget.options.groupAvatarBuilder(
|
||||
(chat as GroupChatModel).title,
|
||||
(chat as GroupChatModel).imageUrl,
|
||||
40.0,
|
||||
),
|
||||
lastUsed: chat.lastUsed != null
|
||||
? _dateFormatter.format(
|
||||
date: chat.lastUsed!,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
Widget build(BuildContext context) => GestureDetector(
|
||||
onTap: () {
|
||||
widget.onPressChat(chat);
|
||||
},
|
||||
child: widget.options.chatRowContainerBuilder(
|
||||
(chat is PersonalChatModel)
|
||||
? ChatRow(
|
||||
unreadMessages: chat.unreadMessages ?? 0,
|
||||
avatar: widget.options.userAvatarBuilder(
|
||||
(chat as PersonalChatModel).user,
|
||||
40.0,
|
||||
),
|
||||
title: (chat as PersonalChatModel).user.fullName ??
|
||||
translations.anonymousUser,
|
||||
subTitle: chat.lastMessage != null
|
||||
? chat.lastMessage is ChatTextMessageModel
|
||||
? (chat.lastMessage! as ChatTextMessageModel).text
|
||||
: '📷 '
|
||||
'${translations.image}'
|
||||
: '',
|
||||
lastUsed: chat.lastUsed != null
|
||||
? _dateFormatter.format(
|
||||
date: chat.lastUsed!,
|
||||
)
|
||||
: null,
|
||||
)
|
||||
: ChatRow(
|
||||
title: (chat as GroupChatModel).title,
|
||||
unreadMessages: chat.unreadMessages ?? 0,
|
||||
subTitle: chat.lastMessage != null
|
||||
? chat.lastMessage is ChatTextMessageModel
|
||||
? (chat.lastMessage! as ChatTextMessageModel).text
|
||||
: '📷 '
|
||||
'${translations.image}'
|
||||
: '',
|
||||
avatar: widget.options.groupAvatarBuilder(
|
||||
(chat as GroupChatModel).title,
|
||||
(chat as GroupChatModel).imageUrl,
|
||||
40.0,
|
||||
),
|
||||
lastUsed: chat.lastUsed != null
|
||||
? _dateFormatter.format(
|
||||
date: chat.lastUsed!,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -47,10 +47,11 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||
Widget build(BuildContext context) {
|
||||
var theme = Theme.of(context);
|
||||
return Scaffold(
|
||||
backgroundColor: theme.colorScheme.surface,
|
||||
appBar: AppBar(
|
||||
iconTheme: theme.appBarTheme.iconTheme ??
|
||||
const IconThemeData(color: Colors.white),
|
||||
backgroundColor: theme.appBarTheme.backgroundColor ?? Colors.black,
|
||||
backgroundColor: theme.appBarTheme.backgroundColor,
|
||||
title: _buildSearchField(),
|
||||
actions: [
|
||||
_buildSearchIcon(),
|
||||
|
@ -114,7 +115,8 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||
} else if (snapshot.hasData) {
|
||||
return _buildUserList(snapshot.data!);
|
||||
} else {
|
||||
return Text(widget.translations.noUsersFound);
|
||||
return widget.options
|
||||
.noUsersPlaceholderBuilder(widget.translations, context);
|
||||
}
|
||||
},
|
||||
),
|
||||
|
@ -128,44 +130,28 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||
var theme = Theme.of(context);
|
||||
|
||||
return _isSearching
|
||||
? Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: TextField(
|
||||
focusNode: _textFieldFocusNode,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
query = value;
|
||||
});
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
hintText: widget.translations.searchPlaceholder,
|
||||
hintStyle: theme.inputDecorationTheme.hintStyle ??
|
||||
const TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: theme.inputDecorationTheme.focusedBorder?.borderSide
|
||||
.color ??
|
||||
Colors.white,
|
||||
),
|
||||
? TextField(
|
||||
focusNode: _textFieldFocusNode,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
query = value;
|
||||
});
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
hintText: widget.translations.searchPlaceholder,
|
||||
hintStyle: theme.inputDecorationTheme.hintStyle,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
style: theme.inputDecorationTheme.hintStyle ??
|
||||
const TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
cursorColor: theme.textSelectionTheme.cursorColor ?? Colors.white,
|
||||
),
|
||||
style: theme.inputDecorationTheme.hintStyle,
|
||||
cursorColor: theme.textSelectionTheme.cursorColor ?? Colors.white,
|
||||
)
|
||||
: Text(
|
||||
widget.translations.newChatTitle,
|
||||
style: theme.appBarTheme.titleTextStyle ??
|
||||
TextStyle(
|
||||
fontWeight: FontWeight.w800,
|
||||
fontSize: 24,
|
||||
color: Theme.of(context).primaryColor,
|
||||
),
|
||||
style: theme.appBarTheme.titleTextStyle,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -191,6 +177,7 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||
}
|
||||
|
||||
Widget _buildUserList(List<ChatUserModel> users) {
|
||||
var theme = Theme.of(context);
|
||||
var filteredUsers = users
|
||||
.where(
|
||||
(user) =>
|
||||
|
@ -204,60 +191,71 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||
if (_textFieldFocusNode.hasFocus && query.isEmpty) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 20.0),
|
||||
child: Center(
|
||||
child: Text(
|
||||
widget.translations.startTyping,
|
||||
style: const TextStyle(
|
||||
fontSize: 16.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
widget.translations.startTyping,
|
||||
style: theme.textTheme.bodySmall,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (filteredUsers.isEmpty) {
|
||||
return widget.options.noChatsPlaceholderBuilder(widget.translations);
|
||||
return widget.options
|
||||
.noUsersPlaceholderBuilder(widget.translations, context);
|
||||
}
|
||||
|
||||
var isPressed = false;
|
||||
return ListView.builder(
|
||||
itemCount: filteredUsers.length,
|
||||
itemBuilder: (context, index) {
|
||||
var user = filteredUsers[index];
|
||||
return GestureDetector(
|
||||
child: widget.options.chatRowContainerBuilder(
|
||||
Container(
|
||||
color: Colors.transparent,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 12.0, right: 12),
|
||||
child: widget.options.userAvatarBuilder(user, 40.0),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 40.0,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
user.fullName ?? widget.translations.anonymousUser,
|
||||
style: const TextStyle(
|
||||
fontSize: 18.0,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: theme.colorScheme.secondary.withOpacity(0.3),
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
onTap: () async {
|
||||
await widget.onPressCreateChat(user);
|
||||
},
|
||||
child: GestureDetector(
|
||||
child: widget.options.chatRowContainerBuilder(
|
||||
Padding(
|
||||
padding: widget.options.paddingAroundChatList ??
|
||||
const EdgeInsets.symmetric(vertical: 8, horizontal: 28),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: widget.options.userAvatarBuilder(user, 40.0),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 40.0,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
user.fullName ??
|
||||
widget.translations.anonymousUser,
|
||||
style: theme.textTheme.bodyLarge,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
onTap: () async {
|
||||
if (!isPressed) {
|
||||
isPressed = true;
|
||||
await widget.onPressCreateChat(user);
|
||||
isPressed = false;
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -33,34 +33,57 @@ class _NewGroupChatOverviewScreenState
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var theme = Theme.of(context);
|
||||
var formKey = GlobalKey<FormState>();
|
||||
var isPressed = false;
|
||||
return Scaffold(
|
||||
backgroundColor: theme.colorScheme.surface,
|
||||
appBar: AppBar(
|
||||
iconTheme: theme.appBarTheme.iconTheme ??
|
||||
const IconThemeData(color: Colors.white),
|
||||
backgroundColor: theme.appBarTheme.backgroundColor ?? Colors.black,
|
||||
title: const Text(
|
||||
'New Group Chat',
|
||||
style: TextStyle(color: Colors.white),
|
||||
backgroundColor: theme.appBarTheme.backgroundColor,
|
||||
title: Text(
|
||||
widget.translations.newGroupChatTitle,
|
||||
style: theme.appBarTheme.titleTextStyle,
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: TextField(
|
||||
controller: _textEditingController,
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'Group chat name',
|
||||
child: Form(
|
||||
key: formKey,
|
||||
child: TextFormField(
|
||||
controller: _textEditingController,
|
||||
decoration: InputDecoration(
|
||||
hintText: widget.translations.groupNameHintText,
|
||||
hintStyle: theme.inputDecorationTheme.hintStyle,
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return widget.translations.groupNameValidatorEmpty;
|
||||
}
|
||||
if (value.length > 15)
|
||||
return widget.translations.groupNameValidatorTooLong;
|
||||
return null;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
onPressed: () async {
|
||||
await widget.onPressCompleteGroupChatCreation(
|
||||
widget.users,
|
||||
_textEditingController.text,
|
||||
);
|
||||
if (!isPressed) {
|
||||
isPressed = true;
|
||||
if (formKey.currentState!.validate()) {
|
||||
await widget.onPressCompleteGroupChatCreation(
|
||||
widget.users,
|
||||
_textEditingController.text,
|
||||
);
|
||||
}
|
||||
isPressed = false;
|
||||
}
|
||||
},
|
||||
child: const Icon(Icons.check_circle),
|
||||
child: const Icon(
|
||||
Icons.check_circle,
|
||||
),
|
||||
),
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
|
||||
);
|
||||
|
|
|
@ -32,10 +32,11 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||
Widget build(BuildContext context) {
|
||||
var theme = Theme.of(context);
|
||||
return Scaffold(
|
||||
backgroundColor: theme.colorScheme.surface,
|
||||
appBar: AppBar(
|
||||
iconTheme: theme.appBarTheme.iconTheme ??
|
||||
const IconThemeData(color: Colors.white),
|
||||
backgroundColor: theme.appBarTheme.backgroundColor ?? Colors.black,
|
||||
backgroundColor: theme.appBarTheme.backgroundColor,
|
||||
title: _buildSearchField(),
|
||||
actions: [
|
||||
_buildSearchIcon(),
|
||||
|
@ -51,10 +52,8 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||
return Text('Error: ${snapshot.error}');
|
||||
} else if (snapshot.hasData) {
|
||||
return _buildUserList(snapshot.data!);
|
||||
} else {
|
||||
return widget.options
|
||||
.noChatsPlaceholderBuilder(widget.translations);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
|
@ -72,44 +71,28 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||
var theme = Theme.of(context);
|
||||
|
||||
return _isSearching
|
||||
? Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: TextField(
|
||||
focusNode: _textFieldFocusNode,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
query = value;
|
||||
});
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
hintText: widget.translations.searchPlaceholder,
|
||||
hintStyle: theme.inputDecorationTheme.hintStyle ??
|
||||
const TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: theme.inputDecorationTheme.focusedBorder?.borderSide
|
||||
.color ??
|
||||
Colors.white,
|
||||
),
|
||||
? TextField(
|
||||
focusNode: _textFieldFocusNode,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
query = value;
|
||||
});
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
hintText: widget.translations.searchPlaceholder,
|
||||
hintStyle: theme.inputDecorationTheme.hintStyle,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
style: theme.inputDecorationTheme.hintStyle ??
|
||||
const TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
cursorColor: theme.textSelectionTheme.cursorColor ?? Colors.white,
|
||||
),
|
||||
style: theme.inputDecorationTheme.hintStyle,
|
||||
cursorColor: theme.textSelectionTheme.cursorColor ?? Colors.white,
|
||||
)
|
||||
: Text(
|
||||
widget.translations.newGroupChatButton,
|
||||
style: theme.appBarTheme.titleTextStyle ??
|
||||
TextStyle(
|
||||
fontWeight: FontWeight.w800,
|
||||
fontSize: 24,
|
||||
color: Theme.of(context).primaryColor,
|
||||
),
|
||||
style: theme.appBarTheme.titleTextStyle,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -146,65 +129,113 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||
.toList();
|
||||
|
||||
if (filteredUsers.isEmpty) {
|
||||
return widget.options.noChatsPlaceholderBuilder(widget.translations);
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
widget.options
|
||||
.noUsersPlaceholderBuilder(widget.translations, context),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.separated(
|
||||
itemCount: filteredUsers.length,
|
||||
separatorBuilder: (context, index) => const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 28.0),
|
||||
child: Divider(),
|
||||
), // Add Divider here
|
||||
itemBuilder: (context, index) {
|
||||
var user = filteredUsers[index];
|
||||
var isSelected =
|
||||
selectedUserList.any((selectedUser) => selectedUser == user);
|
||||
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
if (selectedUserList.contains(user)) {
|
||||
selectedUserList.remove(user);
|
||||
} else {
|
||||
selectedUserList.add(user);
|
||||
}
|
||||
debugPrint('The list of selected users is $selectedUserList');
|
||||
});
|
||||
},
|
||||
child: Container(
|
||||
color: isSelected ? Colors.amber.shade200 : Colors.white,
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 12.0, horizontal: 30),
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 12.0, right: 12),
|
||||
child: widget.options.userAvatarBuilder(user, 40.0),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 40.0, // Adjust the height as needed
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
user.fullName ?? widget.translations.anonymousUser,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (isSelected)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(right: 16.0),
|
||||
child: Icon(Icons.check_circle, color: Colors.green),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
return UserList(
|
||||
filteredUsers: filteredUsers,
|
||||
selectedUserList: selectedUserList,
|
||||
options: widget.options,
|
||||
translations: widget.translations,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class UserList extends StatefulWidget {
|
||||
const UserList({
|
||||
required this.filteredUsers,
|
||||
required this.selectedUserList,
|
||||
required this.options,
|
||||
required this.translations,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final List<ChatUserModel> filteredUsers;
|
||||
final List<ChatUserModel> selectedUserList;
|
||||
final ChatOptions options;
|
||||
final ChatTranslations translations;
|
||||
|
||||
@override
|
||||
State<UserList> createState() => _UserListState();
|
||||
}
|
||||
|
||||
class _UserListState extends State<UserList> {
|
||||
@override
|
||||
Widget build(BuildContext context) => ListView.builder(
|
||||
itemCount: widget.filteredUsers.length,
|
||||
itemBuilder: (context, index) {
|
||||
var user = widget.filteredUsers[index];
|
||||
var isSelected = widget.selectedUserList
|
||||
.any((selectedUser) => selectedUser == user);
|
||||
var theme = Theme.of(context);
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: theme.colorScheme.secondary.withOpacity(0.3),
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
if (widget.selectedUserList.contains(user)) {
|
||||
widget.selectedUserList.remove(user);
|
||||
} else {
|
||||
widget.selectedUserList.add(user);
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Padding(
|
||||
padding: widget.options.paddingAroundChatList ??
|
||||
const EdgeInsets.fromLTRB(28, 8, 28, 8),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 12.0,
|
||||
horizontal: 30,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: widget.options.userAvatarBuilder(user, 40.0),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
height: 40,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
user.fullName ??
|
||||
widget.translations.anonymousUser,
|
||||
style: theme.textTheme.bodyLarge,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (isSelected) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 16.0),
|
||||
child: Icon(
|
||||
Icons.check_circle,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
name: flutter_chat_view
|
||||
description: A standard flutter package.
|
||||
version: 2.0.0
|
||||
version: 3.0.0
|
||||
|
||||
publish_to: none
|
||||
|
||||
|
@ -20,7 +20,7 @@ dependencies:
|
|||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_chat
|
||||
path: packages/flutter_chat_interface
|
||||
ref: 2.0.0
|
||||
ref: 3.0.0
|
||||
cached_network_image: ^3.2.2
|
||||
flutter_image_picker:
|
||||
git:
|
||||
|
@ -37,6 +37,6 @@ dev_dependencies:
|
|||
flutter_iconica_analysis:
|
||||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_iconica_analysis
|
||||
ref: 6.0.0
|
||||
ref: 7.0.0
|
||||
|
||||
flutter:
|
||||
|
|
Loading…
Reference in a new issue