mirror of
https://github.com/Iconica-Development/flutter_chat.git
synced 2025-05-18 18:33:49 +02:00
feat(chat-time-indicator): add small time-indicator in chat detail screens
This commit is contained in:
parent
4e0967cc33
commit
bcf2c0484b
13 changed files with 276 additions and 17 deletions
|
@ -1,3 +1,6 @@
|
||||||
|
## 5.1.0
|
||||||
|
- Added optional time indicator in chat detail screens to show which day the message is posted
|
||||||
|
|
||||||
## 5.0.0
|
## 5.0.0
|
||||||
- Removed the default values for the ChatOptions that are now nullable so they resolve to the ThemeData values
|
- Removed the default values for the ChatOptions that are now nullable so they resolve to the ThemeData values
|
||||||
- Added chatAlignment to change the alignment of the chat messages
|
- Added chatAlignment to change the alignment of the chat messages
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: chat_repository_interface
|
name: chat_repository_interface
|
||||||
description: "The interface for a chat repository"
|
description: "The interface for a chat repository"
|
||||||
version: 5.0.0
|
version: 5.1.0
|
||||||
homepage: "https://github.com/Iconica-Development"
|
homepage: "https://github.com/Iconica-Development"
|
||||||
|
|
||||||
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub/
|
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub/
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: firebase_chat_repository
|
name: firebase_chat_repository
|
||||||
description: "Firebase repository implementation for the chat domain repository interface"
|
description: "Firebase repository implementation for the chat domain repository interface"
|
||||||
version: 5.0.0
|
version: 5.1.0
|
||||||
homepage: "https://github.com/Iconica-Development"
|
homepage: "https://github.com/Iconica-Development"
|
||||||
|
|
||||||
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub/
|
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub/
|
||||||
|
@ -15,7 +15,7 @@ dependencies:
|
||||||
|
|
||||||
chat_repository_interface:
|
chat_repository_interface:
|
||||||
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub
|
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub
|
||||||
version: ^5.0.0
|
version: ^5.1.0
|
||||||
|
|
||||||
firebase_storage: any
|
firebase_storage: any
|
||||||
cloud_firestore: any
|
cloud_firestore: any
|
||||||
|
|
|
@ -8,6 +8,7 @@ export "package:flutter_chat/src/flutter_chat_navigator_userstories.dart";
|
||||||
// Options
|
// Options
|
||||||
export "src/config/chat_builders.dart";
|
export "src/config/chat_builders.dart";
|
||||||
export "src/config/chat_options.dart";
|
export "src/config/chat_options.dart";
|
||||||
|
export "src/config/chat_time_indicator_options.dart";
|
||||||
export "src/config/chat_translations.dart";
|
export "src/config/chat_translations.dart";
|
||||||
export "src/config/screen_types.dart";
|
export "src/config/screen_types.dart";
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import "package:cached_network_image/cached_network_image.dart";
|
import "package:cached_network_image/cached_network_image.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_builders.dart";
|
import "package:flutter_chat/flutter_chat.dart";
|
||||||
import "package:flutter_chat/src/config/chat_semantics.dart";
|
import "package:flutter_chat/src/config/chat_semantics.dart";
|
||||||
import "package:flutter_chat/src/config/chat_translations.dart";
|
|
||||||
|
|
||||||
/// The chat options
|
/// The chat options
|
||||||
/// Use this class to configure the chat options.
|
/// Use this class to configure the chat options.
|
||||||
|
@ -28,6 +26,7 @@ class ChatOptions {
|
||||||
this.onNoChats,
|
this.onNoChats,
|
||||||
this.imageQuality = 20,
|
this.imageQuality = 20,
|
||||||
this.imageProviderResolver = _defaultImageProviderResolver,
|
this.imageProviderResolver = _defaultImageProviderResolver,
|
||||||
|
this.timeIndicatorOptions = const ChatTimeIndicatorOptions(),
|
||||||
ChatRepositoryInterface? chatRepository,
|
ChatRepositoryInterface? chatRepository,
|
||||||
UserRepositoryInterface? userRepository,
|
UserRepositoryInterface? userRepository,
|
||||||
}) : chatRepository = chatRepository ?? LocalChatRepository(),
|
}) : chatRepository = chatRepository ?? LocalChatRepository(),
|
||||||
|
@ -109,6 +108,9 @@ class ChatOptions {
|
||||||
/// the images in the entire userstory. If not provided, CachedNetworkImage
|
/// the images in the entire userstory. If not provided, CachedNetworkImage
|
||||||
/// will be used.
|
/// will be used.
|
||||||
final ImageProviderResolver imageProviderResolver;
|
final ImageProviderResolver imageProviderResolver;
|
||||||
|
|
||||||
|
/// Options regarding the time indicator in chat screens
|
||||||
|
final ChatTimeIndicatorOptions timeIndicatorOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Typedef for the chatTitleResolver function that is used to get a title for
|
/// Typedef for the chatTitleResolver function that is used to get a title for
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
import "package:flutter/material.dart";
|
||||||
|
import "package:flutter_chat/flutter_chat.dart";
|
||||||
|
import "package:flutter_chat/src/screens/chat_detail/widgets/default_chat_time_indicator.dart";
|
||||||
|
|
||||||
|
/// All options related to the time indicator
|
||||||
|
class ChatTimeIndicatorOptions {
|
||||||
|
/// Create default ChatTimeIndicator options
|
||||||
|
const ChatTimeIndicatorOptions({
|
||||||
|
this.indicatorBuilder = DefaultChatTimeIndicator.builder,
|
||||||
|
this.labelResolver = defaultChatTimeIndicatorLabelResolver,
|
||||||
|
this.sectionCheck = defaultChatTimeIndicatorSectionChecker,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// This completely disables the chat time indicator feature
|
||||||
|
const ChatTimeIndicatorOptions.none()
|
||||||
|
: indicatorBuilder = DefaultChatTimeIndicator.builder,
|
||||||
|
labelResolver = defaultChatTimeIndicatorLabelResolver,
|
||||||
|
sectionCheck = neverShowChatTimeIndicatorSectionChecker;
|
||||||
|
|
||||||
|
/// The general builder for the indicator
|
||||||
|
final ChatTimeIndicatorBuilder indicatorBuilder;
|
||||||
|
|
||||||
|
/// A function that translates offset / time to a string label
|
||||||
|
final ChatTimeIndicatorLabelResolver labelResolver;
|
||||||
|
|
||||||
|
/// A function that determines when a new section starts
|
||||||
|
///
|
||||||
|
/// By default, all messages are prefixed with a message.
|
||||||
|
/// You can disable this using the [skipFirstChatTimeIndicatorSectionChecker]
|
||||||
|
/// instead of the default, which would skip the first section
|
||||||
|
final ChatTimeIndicatorSectionChecker sectionCheck;
|
||||||
|
|
||||||
|
/// public method on the options for readability
|
||||||
|
bool isMessageInNewTimeSection(
|
||||||
|
BuildContext context,
|
||||||
|
MessageModel? previousMessage,
|
||||||
|
MessageModel currentMessage,
|
||||||
|
) =>
|
||||||
|
sectionCheck(
|
||||||
|
context,
|
||||||
|
previousMessage,
|
||||||
|
currentMessage,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A function that would generate a string given the current window/datetime
|
||||||
|
typedef ChatTimeIndicatorLabelResolver = String Function(
|
||||||
|
BuildContext context,
|
||||||
|
int dayOffset,
|
||||||
|
DateTime currentWindow,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// A function that would determine if a chat indicator has to render
|
||||||
|
typedef ChatTimeIndicatorSectionChecker = bool Function(
|
||||||
|
BuildContext context,
|
||||||
|
MessageModel? previousMessage,
|
||||||
|
MessageModel currentMessage,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Build used to render time indicators on chat detail screens
|
||||||
|
typedef ChatTimeIndicatorBuilder = Widget Function(
|
||||||
|
BuildContext context,
|
||||||
|
String timeLabel,
|
||||||
|
);
|
||||||
|
|
||||||
|
///
|
||||||
|
String defaultChatTimeIndicatorLabelResolver(
|
||||||
|
BuildContext context,
|
||||||
|
int dayOffset,
|
||||||
|
DateTime currentWindow,
|
||||||
|
) {
|
||||||
|
var translations = ChatScope.of(context).options.translations;
|
||||||
|
return translations.chatTimeIndicatorLabel(dayOffset, currentWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A function that disables the time indicator in chat
|
||||||
|
bool neverShowChatTimeIndicatorSectionChecker(
|
||||||
|
BuildContext context,
|
||||||
|
MessageModel? previousMessage,
|
||||||
|
MessageModel currentMessage,
|
||||||
|
) =>
|
||||||
|
false;
|
||||||
|
|
||||||
|
/// Variant of the default implementation for determining if a new section
|
||||||
|
/// starts, where the first section is skipped.
|
||||||
|
///
|
||||||
|
/// Renders a new indicator every new section, skipping the first section
|
||||||
|
bool skipFirstChatTimeIndicatorSectionChecker(
|
||||||
|
BuildContext context,
|
||||||
|
MessageModel? previousMessage,
|
||||||
|
MessageModel currentMessage,
|
||||||
|
) =>
|
||||||
|
previousMessage != null &&
|
||||||
|
previousMessage.timestamp.date.isBefore(currentMessage.timestamp.date);
|
||||||
|
|
||||||
|
/// Default implementation for determining if a new section starts.
|
||||||
|
///
|
||||||
|
/// Renders a new indicator every new section
|
||||||
|
bool defaultChatTimeIndicatorSectionChecker(
|
||||||
|
BuildContext context,
|
||||||
|
MessageModel? previousMessage,
|
||||||
|
MessageModel currentMessage,
|
||||||
|
) =>
|
||||||
|
previousMessage == null ||
|
||||||
|
previousMessage.timestamp.date.isBefore(currentMessage.timestamp.date);
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
// ignore_for_file: public_member_api_docs
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
import "package:intl/intl.dart";
|
||||||
|
|
||||||
/// Class that holds all the translations for the chat component view and
|
/// Class that holds all the translations for the chat component view and
|
||||||
/// the corresponding userstory
|
/// the corresponding userstory
|
||||||
class ChatTranslations {
|
class ChatTranslations {
|
||||||
|
@ -50,6 +52,7 @@ class ChatTranslations {
|
||||||
required this.groupNameEmpty,
|
required this.groupNameEmpty,
|
||||||
required this.messagesLoadingError,
|
required this.messagesLoadingError,
|
||||||
required this.next,
|
required this.next,
|
||||||
|
required this.chatTimeIndicatorLabel,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Default translations for the chat component view
|
/// Default translations for the chat component view
|
||||||
|
@ -95,6 +98,8 @@ class ChatTranslations {
|
||||||
this.groupNameEmpty = "Group",
|
this.groupNameEmpty = "Group",
|
||||||
this.messagesLoadingError = "Error loading messages, you can reload below:",
|
this.messagesLoadingError = "Error loading messages, you can reload below:",
|
||||||
this.next = "Next",
|
this.next = "Next",
|
||||||
|
this.chatTimeIndicatorLabel =
|
||||||
|
ChatTranslations.defaultChatTimeIndicatorLabel,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String chatsTitle;
|
final String chatsTitle;
|
||||||
|
@ -140,6 +145,33 @@ class ChatTranslations {
|
||||||
/// to be loaded.
|
/// to be loaded.
|
||||||
final String messagesLoadingError;
|
final String messagesLoadingError;
|
||||||
|
|
||||||
|
/// The message of a label given a certain offset.
|
||||||
|
///
|
||||||
|
/// The offset determines whether it is today (0), yesterday (-1), or earlier.
|
||||||
|
///
|
||||||
|
/// [dateOffset] will rarely be a +1, however if anyone ever wants to see
|
||||||
|
/// future chat messages, then this number will be positive.
|
||||||
|
///
|
||||||
|
/// use the given [time] format to display exact time information.
|
||||||
|
final String Function(int dateOffset, DateTime time) chatTimeIndicatorLabel;
|
||||||
|
|
||||||
|
/// Standard function to convert an offset to a String.
|
||||||
|
///
|
||||||
|
/// Recommended to always override this in any production app with an
|
||||||
|
/// app localizations implementation.
|
||||||
|
static String defaultChatTimeIndicatorLabel(
|
||||||
|
int dateOffset,
|
||||||
|
DateTime time,
|
||||||
|
) =>
|
||||||
|
switch (dateOffset) {
|
||||||
|
0 => "Today",
|
||||||
|
-1 => "Yesterday",
|
||||||
|
1 => "Tomorrow",
|
||||||
|
int value when value < 5 && value > 1 => "In $value days",
|
||||||
|
int value when value < -1 && value > -5 => "$value days ago",
|
||||||
|
_ => DateFormat("dd-MM-YYYY").format(time),
|
||||||
|
};
|
||||||
|
|
||||||
final String next;
|
final String next;
|
||||||
|
|
||||||
// copyWith method to override the default values
|
// copyWith method to override the default values
|
||||||
|
@ -182,6 +214,7 @@ class ChatTranslations {
|
||||||
String? groupNameEmpty,
|
String? groupNameEmpty,
|
||||||
String? messagesLoadingError,
|
String? messagesLoadingError,
|
||||||
String? next,
|
String? next,
|
||||||
|
String Function(int dateOffset, DateTime time)? chatTimeIndicatorLabel,
|
||||||
}) =>
|
}) =>
|
||||||
ChatTranslations(
|
ChatTranslations(
|
||||||
chatsTitle: chatsTitle ?? this.chatsTitle,
|
chatsTitle: chatsTitle ?? this.chatsTitle,
|
||||||
|
@ -234,5 +267,7 @@ class ChatTranslations {
|
||||||
groupNameEmpty: groupNameEmpty ?? this.groupNameEmpty,
|
groupNameEmpty: groupNameEmpty ?? this.groupNameEmpty,
|
||||||
messagesLoadingError: messagesLoadingError ?? this.messagesLoadingError,
|
messagesLoadingError: messagesLoadingError ?? this.messagesLoadingError,
|
||||||
next: next ?? this.next,
|
next: next ?? this.next,
|
||||||
|
chatTimeIndicatorLabel:
|
||||||
|
chatTimeIndicatorLabel ?? this.chatTimeIndicatorLabel,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
import "dart:async";
|
import "dart:async";
|
||||||
import "dart:typed_data";
|
import "dart:typed_data";
|
||||||
|
|
||||||
import "package:chat_repository_interface/chat_repository_interface.dart";
|
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:flutter_accessibility/flutter_accessibility.dart";
|
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||||
import "package:flutter_chat/src/config/chat_options.dart";
|
import "package:flutter_chat/flutter_chat.dart";
|
||||||
import "package:flutter_chat/src/config/screen_types.dart";
|
|
||||||
import "package:flutter_chat/src/screens/chat_detail/widgets/chat_bottom.dart";
|
import "package:flutter_chat/src/screens/chat_detail/widgets/chat_bottom.dart";
|
||||||
import "package:flutter_chat/src/screens/chat_detail/widgets/chat_widgets.dart";
|
import "package:flutter_chat/src/screens/chat_detail/widgets/chat_widgets.dart";
|
||||||
import "package:flutter_chat/src/screens/creation/widgets/default_image_picker.dart";
|
import "package:flutter_chat/src/screens/creation/widgets/default_image_picker.dart";
|
||||||
import "package:flutter_chat/src/util/scope.dart";
|
|
||||||
import "package:flutter_hooks/flutter_hooks.dart";
|
import "package:flutter_hooks/flutter_hooks.dart";
|
||||||
|
|
||||||
/// Chat detail screen
|
/// Chat detail screen
|
||||||
|
@ -465,14 +462,26 @@ class _ChatBody extends HookWidget {
|
||||||
bubbleChildren
|
bubbleChildren
|
||||||
.add(ChatNoMessages(isGroupChat: chat?.isGroupChat ?? false));
|
.add(ChatNoMessages(isGroupChat: chat?.isGroupChat ?? false));
|
||||||
} else {
|
} else {
|
||||||
for (var (index, msg) in messages.indexed) {
|
for (var (index, currentMessage) in messages.indexed) {
|
||||||
var prevMsg = index > 0 ? messages[index - 1] : null;
|
var previousMessage = index > 0 ? messages[index - 1] : null;
|
||||||
|
|
||||||
|
if (options.timeIndicatorOptions.isMessageInNewTimeSection(
|
||||||
|
context,
|
||||||
|
previousMessage,
|
||||||
|
currentMessage,
|
||||||
|
)) {
|
||||||
|
bubbleChildren.add(
|
||||||
|
ChatTimeIndicator(
|
||||||
|
forDate: currentMessage.timestamp,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
bubbleChildren.add(
|
bubbleChildren.add(
|
||||||
ChatBubble(
|
ChatBubble(
|
||||||
message: msg,
|
message: currentMessage,
|
||||||
previousMessage: prevMsg,
|
previousMessage: previousMessage,
|
||||||
sender: userMap[msg.senderId],
|
sender: userMap[currentMessage.senderId],
|
||||||
onPressSender: onPressUserProfile,
|
onPressSender: onPressUserProfile,
|
||||||
semanticIdTitle: options.semantics.chatBubbleTitle(index),
|
semanticIdTitle: options.semantics.chatBubbleTitle(index),
|
||||||
semanticIdTime: options.semantics.chatBubbleTime(index),
|
semanticIdTime: options.semantics.chatBubbleTime(index),
|
||||||
|
|
|
@ -3,6 +3,7 @@ import "package:flutter/material.dart";
|
||||||
import "package:flutter_accessibility/flutter_accessibility.dart";
|
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||||
import "package:flutter_chat/src/screens/chat_detail/widgets/default_message_builder.dart";
|
import "package:flutter_chat/src/screens/chat_detail/widgets/default_message_builder.dart";
|
||||||
import "package:flutter_chat/src/util/scope.dart";
|
import "package:flutter_chat/src/util/scope.dart";
|
||||||
|
import "package:flutter_chat/src/util/utils.dart";
|
||||||
import "package:flutter_hooks/flutter_hooks.dart";
|
import "package:flutter_hooks/flutter_hooks.dart";
|
||||||
|
|
||||||
/// Widget displayed when there are no messages in the chat.
|
/// Widget displayed when there are no messages in the chat.
|
||||||
|
@ -102,3 +103,32 @@ class ChatBubble extends HookWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The indicator above a set of messages, shown per date.
|
||||||
|
class ChatTimeIndicator extends StatelessWidget {
|
||||||
|
/// Creates a ChatTimeIndicator
|
||||||
|
const ChatTimeIndicator({
|
||||||
|
required this.forDate,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// The dateTime at which the new time section starts
|
||||||
|
final DateTime forDate;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var scope = ChatScope.of(context);
|
||||||
|
var indicatorOptions = scope.options.timeIndicatorOptions;
|
||||||
|
|
||||||
|
var today = DateTime.now();
|
||||||
|
var differenceInDays = today.getDateOffsetInDays(forDate);
|
||||||
|
|
||||||
|
var message = indicatorOptions.labelResolver(
|
||||||
|
context,
|
||||||
|
differenceInDays,
|
||||||
|
forDate,
|
||||||
|
);
|
||||||
|
|
||||||
|
return indicatorOptions.indicatorBuilder(context, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
import "package:flutter/material.dart";
|
||||||
|
import "package:flutter_chat/flutter_chat.dart";
|
||||||
|
|
||||||
|
/// The default layout for a chat indicator
|
||||||
|
class DefaultChatTimeIndicator extends StatelessWidget {
|
||||||
|
/// Create a default timeindicator in a chat
|
||||||
|
const DefaultChatTimeIndicator({
|
||||||
|
required this.timeIndicatorString,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// The text shown in the time indicator
|
||||||
|
final String timeIndicatorString;
|
||||||
|
|
||||||
|
/// Standard builder for time indication
|
||||||
|
static Widget builder(BuildContext context, String timeIndicatorString) =>
|
||||||
|
DefaultChatTimeIndicator(timeIndicatorString: timeIndicatorString);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var theme = Theme.of(context);
|
||||||
|
var spacing = ChatScope.of(context).options.spacing;
|
||||||
|
return Center(
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.only(top: spacing.chatBetweenMessagesPadding),
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 4,
|
||||||
|
horizontal: 8,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(6),
|
||||||
|
color: theme.colorScheme.surfaceContainerHighest,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
timeIndicatorString,
|
||||||
|
style: theme.textTheme.labelSmall?.copyWith(
|
||||||
|
color: theme.colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1 +1,18 @@
|
||||||
// add generic utils that are used in the package
|
// add generic utils that are used in the package
|
||||||
|
|
||||||
|
/// Extension to simplify detecting how many days relative dates are
|
||||||
|
extension RelativeDates on DateTime {
|
||||||
|
/// Strips timezone information whilst keeping the exact same date
|
||||||
|
DateTime get utcDate => DateTime.utc(year, month, day);
|
||||||
|
|
||||||
|
/// Strips time information from the date
|
||||||
|
DateTime get date => DateTime(year, month, day);
|
||||||
|
|
||||||
|
/// Get relative date in offset from the current position.
|
||||||
|
///
|
||||||
|
/// `today.getDateOffsetInDays(yesterday)` would result in `-1`
|
||||||
|
///
|
||||||
|
/// `yesterday.getDateOffsetInDays(tomorrow)` would result in `2`
|
||||||
|
int getDateOffsetInDays(DateTime other) =>
|
||||||
|
other.utcDate.difference(utcDate).inDays;
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: flutter_chat
|
name: flutter_chat
|
||||||
description: "User story of the chat domain for quick integration into flutter apps"
|
description: "User story of the chat domain for quick integration into flutter apps"
|
||||||
version: 5.0.0
|
version: 5.1.0
|
||||||
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub/
|
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub/
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
@ -26,7 +26,7 @@ dependencies:
|
||||||
version: ^1.6.0
|
version: ^1.6.0
|
||||||
chat_repository_interface:
|
chat_repository_interface:
|
||||||
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub
|
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub
|
||||||
version: ^5.0.0
|
version: ^5.1.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
14
packages/flutter_chat/test/relative_date_test.dart
Normal file
14
packages/flutter_chat/test/relative_date_test.dart
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import "package:flutter_chat/src/util/utils.dart";
|
||||||
|
import "package:flutter_test/flutter_test.dart";
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group("RelativeDates", () {
|
||||||
|
test("getDateOffsetInDays", () {
|
||||||
|
var dateA = DateTime(2024, 10, 30);
|
||||||
|
var dateB = DateTime(2024, 10, 01);
|
||||||
|
|
||||||
|
expect(dateA.getDateOffsetInDays(dateB), equals(29));
|
||||||
|
expect(dateB.getDateOffsetInDays(dateA), equals(-29));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in a new issue