wip: testing positioned list

This commit is contained in:
Gordon Hayes
2021-09-08 11:48:26 +02:00
parent 386df52048
commit 2badecbde6
3 changed files with 150 additions and 134 deletions
@@ -2311,75 +2311,78 @@ class _PickerWidgetState extends State<_PickerWidget> {
if (widget.filePickerIndex != 0) { if (widget.filePickerIndex != 0) {
return const Offstage(); return const Offstage();
} }
return FutureBuilder<bool>( return RepaintBoundary(
future: requestPermission, child: FutureBuilder<bool>(
builder: (context, snapshot) { future: requestPermission,
if (!snapshot.hasData) { builder: (context, snapshot) {
return const Center(child: CircularProgressIndicator()); if (!snapshot.hasData) {
} return const Center(child: CircularProgressIndicator());
if (snapshot.data!) {
if (widget.containsFile) {
return GestureDetector(
onTap: () {
widget.onAddMoreFilesClick(DefaultAttachmentTypes.file);
},
child: Container(
constraints: const BoxConstraints.expand(),
color: widget.streamChatTheme.colorTheme.inputBg,
alignment: Alignment.center,
child: Text(
context.translations.addMoreFilesLabel,
style: TextStyle(
color: widget.streamChatTheme.colorTheme.accentPrimary,
fontWeight: FontWeight.bold,
),
),
),
);
} }
return MediaListView(
selectedIds: widget.selectedMedias,
onSelect: widget.onMediaSelected,
);
}
return InkWell( if (snapshot.data!) {
onTap: () async { if (widget.containsFile) {
PhotoManager.openSetting(); return GestureDetector(
}, onTap: () {
child: Container( widget.onAddMoreFilesClick(DefaultAttachmentTypes.file);
color: widget.streamChatTheme.colorTheme.inputBg, },
child: Column( child: Container(
mainAxisAlignment: MainAxisAlignment.center, constraints: const BoxConstraints.expand(),
crossAxisAlignment: CrossAxisAlignment.stretch, color: widget.streamChatTheme.colorTheme.inputBg,
children: [ alignment: Alignment.center,
SvgPicture.asset(
'svgs/icon_picture_empty_state.svg',
package: 'stream_chat_flutter',
height: 140,
color: widget.streamChatTheme.colorTheme.disabled,
),
Text(
context.translations.enablePhotoAndVideoAccessMessage,
style: widget.streamChatTheme.textTheme.body.copyWith(
color: widget.streamChatTheme.colorTheme.textLowEmphasis),
textAlign: TextAlign.center,
),
const SizedBox(height: 6),
Center(
child: Text( child: Text(
context.translations.allowGalleryAccessMessage, context.translations.addMoreFilesLabel,
style: widget.streamChatTheme.textTheme.bodyBold.copyWith( style: TextStyle(
color: widget.streamChatTheme.colorTheme.accentPrimary, color: widget.streamChatTheme.colorTheme.accentPrimary,
fontWeight: FontWeight.bold,
), ),
), ),
), ),
], );
}
return MediaListView(
selectedIds: widget.selectedMedias,
onSelect: widget.onMediaSelected,
);
}
return InkWell(
onTap: () async {
PhotoManager.openSetting();
},
child: Container(
color: widget.streamChatTheme.colorTheme.inputBg,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SvgPicture.asset(
'svgs/icon_picture_empty_state.svg',
package: 'stream_chat_flutter',
height: 140,
color: widget.streamChatTheme.colorTheme.disabled,
),
Text(
context.translations.enablePhotoAndVideoAccessMessage,
style: widget.streamChatTheme.textTheme.body.copyWith(
color:
widget.streamChatTheme.colorTheme.textLowEmphasis),
textAlign: TextAlign.center,
),
const SizedBox(height: 6),
Center(
child: Text(
context.translations.allowGalleryAccessMessage,
style: widget.streamChatTheme.textTheme.bodyBold.copyWith(
color: widget.streamChatTheme.colorTheme.accentPrimary,
),
),
),
],
),
), ),
), );
); },
}, ),
); );
} }
} }
@@ -455,7 +455,7 @@ class _MessageListViewState extends State<MessageListView> {
onInBetweenOfPage: () { onInBetweenOfPage: () {
_inBetweenList = true; _inBetweenList = true;
}, },
child: ScrollablePositionedList.separated( child: ScrollablePositionedList.builder(
key: _upToDate key: _upToDate
? null ? null
: ValueKey(initialIndex + initialAlignment), : ValueKey(initialIndex + initialAlignment),
@@ -465,8 +465,13 @@ class _MessageListViewState extends State<MessageListView> {
physics: widget.scrollPhysics, physics: widget.scrollPhysics,
itemScrollController: _scrollController, itemScrollController: _scrollController,
reverse: widget.reverse, reverse: widget.reverse,
addAutomaticKeepAlives: false, itemCount: messages.length,
itemCount: itemCount, findChildIndexCallback: (Key key) {
final String data = (key as ValueKey).value;
final index =
messages.indexWhere((element) => element.id == data);
return index + 1;
},
// Item Count -> 8 (1 parent, 2 header+footer, 2 top+bottom, 3 messages) // Item Count -> 8 (1 parent, 2 header+footer, 2 top+bottom, 3 messages)
// eg: |Type| rev(|Index(item)|) rev(|Index(separator)|) |Index(item)| |Index(separator)| // eg: |Type| rev(|Index(item)|) rev(|Index(separator)|) |Index(item)| |Index(separator)|
@@ -486,72 +491,74 @@ class _MessageListViewState extends State<MessageListView> {
// Separator(Footer -> 8??30) -> 0 (count-8) // Separator(Footer -> 8??30) -> 0 (count-8)
// Footer -> 0 (count-8) // Footer -> 0 (count-8)
separatorBuilder: (context, i) { // separatorBuilder: (context, i) {
if (i == itemCount - 2) { // if (i == itemCount - 2) {
if (widget.parentMessage == null) { // if (widget.parentMessage == null) {
return const Offstage(); // return const Offstage();
} // }
return _buildThreadSeparator(); // return _buildThreadSeparator();
} // }
if (i == itemCount - 3) { // if (i == itemCount - 3) {
if (widget.headerBuilder == null) { // if (widget.headerBuilder == null) {
if (_isThreadConversation) return const Offstage(); // if (_isThreadConversation) return const Offstage();
return const SizedBox(height: 52); // return const SizedBox(height: 52);
} // }
return const SizedBox(height: 8); // return const SizedBox(height: 8);
} // }
if (i == 0) { // if (i == 0) {
if (widget.footerBuilder == null) { // if (widget.footerBuilder == null) {
return const SizedBox(height: 30); // return const SizedBox(height: 30);
} // }
return const SizedBox(height: 8); // return const SizedBox(height: 8);
} // }
if (i == 1 || i == itemCount - 4) return const Offstage(); // if (i == 1 || i == itemCount - 4) return const Offstage();
late final Message message, nextMessage; // late final Message message, nextMessage;
if (widget.reverse) { // if (widget.reverse) {
message = messages[i - 1]; // message = messages[i - 1];
nextMessage = messages[i - 2]; // nextMessage = messages[i - 2];
} else { // } else {
message = messages[i - 2]; // message = messages[i - 2];
nextMessage = messages[i - 1]; // nextMessage = messages[i - 1];
} // }
if (!Jiffy(message.createdAt.toLocal()).isSame( // if (!Jiffy(message.createdAt.toLocal()).isSame(
nextMessage.createdAt.toLocal(), // nextMessage.createdAt.toLocal(),
Units.DAY, // Units.DAY,
)) { // )) {
final divider = widget.dateDividerBuilder != null // final divider = widget.dateDividerBuilder != null
? widget.dateDividerBuilder!( // ? widget.dateDividerBuilder!(
nextMessage.createdAt.toLocal(), // nextMessage.createdAt.toLocal(),
) // )
: DateDivider( // : DateDivider(
dateTime: nextMessage.createdAt.toLocal(), // dateTime: nextMessage.createdAt.toLocal(),
); // );
return Padding( // return Padding(
padding: const EdgeInsets.symmetric(vertical: 12), // padding: const EdgeInsets.symmetric(vertical: 12),
child: divider, // child: divider,
); // );
} // }
final timeDiff = // final timeDiff =
Jiffy(nextMessage.createdAt.toLocal()).diff( // Jiffy(nextMessage.createdAt.toLocal()).diff(
message.createdAt.toLocal(), // message.createdAt.toLocal(),
Units.MINUTE, // Units.MINUTE,
); // );
final isNextUserSame = // final isNextUserSame =
message.user!.id == nextMessage.user?.id; // message.user!.id == nextMessage.user?.id;
final isThread = message.replyCount! > 0; // final isThread = message.replyCount! > 0;
final isDeleted = message.isDeleted; // final isDeleted = message.isDeleted;
if (timeDiff >= 1 || // if (timeDiff >= 1 ||
!isNextUserSame || // !isNextUserSame ||
isThread || // isThread ||
isDeleted) { // isDeleted) {
return const SizedBox(height: 8); // return const SizedBox(height: 8);
} // }
return const SizedBox(height: 2); // return const SizedBox(height: 2);
}, // },
itemBuilder: (context, i) { itemBuilder: (context, i) {
// final myMessage = messages[i];
// return buildMessage(myMessage, messages, i, i);
if (i == itemCount - 1) { if (i == itemCount - 1) {
if (widget.parentMessage == null) { if (widget.parentMessage == null) {
return const Offstage(); return const Offstage();
@@ -597,7 +604,7 @@ class _MessageListViewState extends State<MessageListView> {
i - 2, i - 2,
); );
} else { } else {
messageWidget = buildMessage(message, messages, i - 2); messageWidget = buildMessage(message, messages, i - 2, i);
} }
return messageWidget; return messageWidget;
}, },
@@ -915,16 +922,13 @@ class _MessageListViewState extends State<MessageListView> {
return defaultMessageWidget; return defaultMessageWidget;
} }
Widget buildMessage( Widget buildMessage(Message message, List<Message> messages, int index,
Message message, [int? actualIndex]) {
List<Message> messages,
int index,
) {
if ((message.type == 'system' || message.type == 'error') && if ((message.type == 'system' || message.type == 'error') &&
message.text?.isNotEmpty == true) { message.text?.isNotEmpty == true) {
return widget.systemMessageBuilder?.call(context, message) ?? return widget.systemMessageBuilder?.call(context, message) ??
SystemMessage( SystemMessage(
key: ValueKey<String>('MESSAGE-${message.id}'), key: ValueKey<String>(message.id),
message: message, message: message,
onMessageTap: (message) { onMessageTap: (message) {
if (widget.onSystemMessageTap != null) { if (widget.onSystemMessageTap != null) {
@@ -1004,7 +1008,8 @@ class _MessageListViewState extends State<MessageListView> {
members.firstWhereOrNull((e) => e.user!.id == currentUser!.id); members.firstWhereOrNull((e) => e.user!.id == currentUser!.id);
Widget messageWidget = MessageWidget( Widget messageWidget = MessageWidget(
key: ValueKey<String>('MESSAGE-${message.id}'), key: ValueKey<String>(message.id),
actualIndex: actualIndex,
message: message, message: message,
reverse: isMyMessage, reverse: isMyMessage,
showReactions: !message.isDeleted, showReactions: !message.isDeleted,
@@ -74,6 +74,7 @@ class MessageWidget extends StatefulWidget {
this.showInChannelIndicator = false, this.showInChannelIndicator = false,
this.onReplyTap, this.onReplyTap,
this.onThreadTap, this.onThreadTap,
this.actualIndex,
this.showUsername = true, this.showUsername = true,
this.showTimestamp = true, this.showTimestamp = true,
this.showReactions = true, this.showReactions = true,
@@ -257,6 +258,8 @@ class MessageWidget extends StatefulWidget {
}..addAll(customAttachmentBuilders ?? {}), }..addAll(customAttachmentBuilders ?? {}),
super(key: key); super(key: key);
final int? actualIndex;
/// Function called on mention tap /// Function called on mention tap
final void Function(User)? onMentionTap; final void Function(User)? onMentionTap;
@@ -590,6 +593,10 @@ class _MessageWidgetState extends State<MessageWidget>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.build(context); super.build(context);
return Container(
decoration: BoxDecoration(border: Border.all()),
child: Text('${widget.message.text ?? 'valu'} ${widget.actualIndex}'),
);
final avatarWidth = final avatarWidth =
widget.messageTheme.avatarTheme?.constraints.maxWidth ?? 40; widget.messageTheme.avatarTheme?.constraints.maxWidth ?? 40;
final bottomRowPadding = final bottomRowPadding =
@@ -658,6 +665,7 @@ class _MessageWidgetState extends State<MessageWidget>
SizedBox(width: avatarWidth + 4), SizedBox(width: avatarWidth + 4),
Flexible( Flexible(
child: PortalEntry( child: PortalEntry(
visible: false,
portal: Container( portal: Container(
transform: Matrix4.translationValues( transform: Matrix4.translationValues(
widget.reverse ? 12 : -12, 0, 0), widget.reverse ? 12 : -12, 0, 0),