feat(ui): Render date bubbles in a less stupid way
This commit is contained in:
parent
e78dae0950
commit
28591a6787
@ -3,9 +3,9 @@ import 'package:emoji_picker_flutter/emoji_picker_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_list_view/flutter_list_view.dart';
|
||||
import 'package:flutter_vibrate/flutter_vibrate.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:grouped_list/grouped_list.dart';
|
||||
import 'package:moxxyv2/i18n/strings.g.dart';
|
||||
import 'package:moxxyv2/shared/error_types.dart';
|
||||
import 'package:moxxyv2/shared/helpers.dart';
|
||||
@ -40,7 +40,7 @@ class ConversationPage extends StatefulWidget {
|
||||
|
||||
class ConversationPageState extends State<ConversationPage> with TickerProviderStateMixin {
|
||||
final TextEditingController _controller = TextEditingController();
|
||||
final FlutterListViewController _scrollController = FlutterListViewController();
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
late final AnimationController _animationController;
|
||||
late final AnimationController _overviewAnimationController;
|
||||
late final TabController _tabController;
|
||||
@ -111,63 +111,8 @@ class ConversationPageState extends State<ConversationPage> with TickerProviderS
|
||||
}
|
||||
}
|
||||
|
||||
Widget _renderBubble(ConversationState state, BuildContext context, int _index, double maxWidth, String jid) {
|
||||
if (_index.isEven) {
|
||||
// Render a date bubble at the top of the list
|
||||
if (_index == 2 * state.messages.length - 1) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
DateBubble(
|
||||
formatDateBubble(
|
||||
DateTime.fromMillisecondsSinceEpoch(
|
||||
state.messages.last.timestamp,
|
||||
),
|
||||
DateTime.now(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
final prevIndexRaw = (_index + 2) ~/ 2;
|
||||
final prevIndex = state.messages.length - prevIndexRaw;
|
||||
final prevMessageDateTime = prevIndex < 0 || prevIndexRaw == 0 ?
|
||||
null :
|
||||
DateTime.fromMillisecondsSinceEpoch(
|
||||
state.messages[prevIndex].timestamp,
|
||||
);
|
||||
|
||||
if (prevMessageDateTime == null) return const SizedBox();
|
||||
|
||||
final nextIndexRaw = _index ~/ 2;
|
||||
final nextIndex = state.messages.length - nextIndexRaw;
|
||||
final nextMessageDateTime = nextIndex < 0 || nextIndexRaw == 0 ?
|
||||
null :
|
||||
DateTime.fromMillisecondsSinceEpoch(
|
||||
state.messages[nextIndex].timestamp,
|
||||
);
|
||||
if (nextMessageDateTime == null) return const SizedBox();
|
||||
|
||||
// Check if we have to render a date bubble
|
||||
if (prevMessageDateTime.day != nextMessageDateTime.day ||
|
||||
prevMessageDateTime.month != nextMessageDateTime.month ||
|
||||
prevMessageDateTime.year != nextMessageDateTime.year) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
DateBubble(
|
||||
formatDateBubble(nextMessageDateTime, DateTime.now()),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return const SizedBox();
|
||||
}
|
||||
|
||||
final index = state.messages.length - 1 - (_index - 1) ~/ 2;
|
||||
final item = state.messages[index];
|
||||
Widget _renderBubble(ConversationState state, Message message, int index, double maxWidth) {
|
||||
final item = message;
|
||||
|
||||
if (item.isPseudoMessage) {
|
||||
return Row(
|
||||
@ -188,12 +133,12 @@ class ConversationPageState extends State<ConversationPage> with TickerProviderS
|
||||
|
||||
final start = index - 1 < 0 ?
|
||||
true :
|
||||
isSent(state.messages[index - 1], jid) != isSent(item, jid);
|
||||
isSent(state.messages[index - 1], state.jid) != isSent(item, state.jid);
|
||||
final end = index + 1 >= state.messages.length ?
|
||||
true :
|
||||
isSent(state.messages[index + 1], jid) != isSent(item, jid);
|
||||
isSent(state.messages[index + 1], state.jid) != isSent(item, state.jid);
|
||||
final between = !start && !end;
|
||||
final sentBySelf = isSent(item, jid);
|
||||
final sentBySelf = isSent(message, state.jid);
|
||||
|
||||
final bubble = RawChatBubble(
|
||||
item,
|
||||
@ -210,27 +155,29 @@ class ConversationPageState extends State<ConversationPage> with TickerProviderS
|
||||
message: item,
|
||||
sentBySelf: sentBySelf,
|
||||
maxWidth: maxWidth,
|
||||
onSwipedCallback: (_) => _quoteMessage(context, item),
|
||||
onSwipedCallback: (_) => _quoteMessage(context, message),
|
||||
onReactionTap: (reaction) {
|
||||
final bloc = context.read<ConversationBloc>();
|
||||
if (reaction.reactedBySelf) {
|
||||
bloc.add(
|
||||
ReactionRemovedEvent(
|
||||
reaction.emoji,
|
||||
index,
|
||||
//index,
|
||||
0,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
bloc.add(
|
||||
ReactionAddedEvent(
|
||||
reaction.emoji,
|
||||
index,
|
||||
//index,
|
||||
0,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
onLongPressed: (event) async {
|
||||
if (!item.isLongpressable) {
|
||||
if (!message.isLongpressable) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -301,7 +248,8 @@ class ConversationPageState extends State<ConversationPage> with TickerProviderS
|
||||
if (emoji != null) {
|
||||
// ignore: use_build_context_synchronously
|
||||
context.read<ConversationBloc>().add(
|
||||
ReactionAddedEvent(emoji, index),
|
||||
//ReactionAddedEvent(emoji, index),
|
||||
ReactionAddedEvent(emoji, 0),
|
||||
);
|
||||
}
|
||||
|
||||
@ -552,22 +500,36 @@ class ConversationPageState extends State<ConversationPage> with TickerProviderS
|
||||
// be static over the entire lifetime of the BLoC.
|
||||
buildWhen: (prev, next) => prev.messages != next.messages || prev.conversation?.encrypted != next.conversation?.encrypted,
|
||||
builder: (context, state) => Expanded(
|
||||
child: FlutterListView(
|
||||
shrinkWrap: true,
|
||||
controller: _scrollController,
|
||||
// Inspired by https://github.com/SimformSolutionsPvtLtd/flutter_chatview/blob/main/lib/src/widgets/chat_groupedlist_widget.dart
|
||||
child: SingleChildScrollView(
|
||||
reverse: true,
|
||||
delegate: FlutterListViewDelegate(
|
||||
(BuildContext context, int index) => _renderBubble(
|
||||
controller: _scrollController,
|
||||
child: GroupedListView<Message, DateTime>(
|
||||
elements: state.messages,
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
groupBy: (message) {
|
||||
final dt = DateTime.fromMillisecondsSinceEpoch(message.timestamp);
|
||||
return DateTime(
|
||||
dt.year,
|
||||
dt.month,
|
||||
dt.day,
|
||||
);
|
||||
},
|
||||
groupSeparatorBuilder: (DateTime dt) => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
DateBubble(
|
||||
formatDateBubble(dt, DateTime.now()),
|
||||
),
|
||||
],
|
||||
),
|
||||
indexedItemBuilder: (context, message, index) => _renderBubble(
|
||||
state,
|
||||
context,
|
||||
message,
|
||||
index,
|
||||
maxWidth,
|
||||
state.jid,
|
||||
),
|
||||
childCount: state.messages.length * 2,
|
||||
keepPosition: true,
|
||||
keepPositionOffset: 40,
|
||||
firstItemAlign: FirstItemAlign.end,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
14
pubspec.lock
14
pubspec.lock
@ -489,13 +489,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
flutter_list_view:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_list_view
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.21"
|
||||
flutter_localizations:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@ -642,6 +635,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
grouped_list:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: grouped_list
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.1.2"
|
||||
hex:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -34,7 +34,6 @@ dependencies:
|
||||
flutter_image_compress: 1.1.0
|
||||
flutter_isolate: 2.0.2
|
||||
flutter_keyboard_visibility: 5.4.0
|
||||
flutter_list_view: 1.1.21
|
||||
flutter_localizations:
|
||||
sdk: flutter
|
||||
flutter_parsed_text: 2.2.1
|
||||
@ -45,6 +44,7 @@ dependencies:
|
||||
fluttertoast: 8.1.1
|
||||
freezed_annotation: 2.1.0
|
||||
get_it: 7.2.0
|
||||
grouped_list: 5.1.2
|
||||
hex: 0.2.0
|
||||
image: 3.2.0
|
||||
json_annotation: 4.6.0
|
||||
|
Loading…
Reference in New Issue
Block a user