Merge pull request #568 from GetStream/hotfix/listBackground
fix(ui): list background
This commit is contained in:
@@ -231,13 +231,21 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ColoredBox(
|
child = LazyLoadScrollView(
|
||||||
color: ChannelListViewTheme.of(context).backgroundColor!,
|
onEndOfPage: () => _channelListController.paginateData!(),
|
||||||
child: LazyLoadScrollView(
|
child: child,
|
||||||
onEndOfPage: () => _channelListController.paginateData!(),
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final backgroundColor = ChannelListViewTheme.of(context).backgroundColor;
|
||||||
|
|
||||||
|
if (backgroundColor != null) {
|
||||||
|
return ColoredBox(
|
||||||
|
color: backgroundColor,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildListView(BuildContext context, List<Channel> channels) {
|
Widget _buildListView(BuildContext context, List<Channel> channels) {
|
||||||
|
|||||||
@@ -386,210 +386,217 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
1 // parent message
|
1 // parent message
|
||||||
;
|
;
|
||||||
|
|
||||||
return ColoredBox(
|
final child = Stack(
|
||||||
color: MessageListViewTheme.of(context).backgroundColor!,
|
alignment: Alignment.center,
|
||||||
child: Stack(
|
children: [
|
||||||
alignment: Alignment.center,
|
ConnectionStatusBuilder(
|
||||||
children: [
|
statusBuilder: (context, status) {
|
||||||
ConnectionStatusBuilder(
|
var statusString = '';
|
||||||
statusBuilder: (context, status) {
|
var showStatus = true;
|
||||||
var statusString = '';
|
switch (status) {
|
||||||
var showStatus = true;
|
case ConnectionStatus.connected:
|
||||||
switch (status) {
|
statusString = 'Connected';
|
||||||
case ConnectionStatus.connected:
|
showStatus = false;
|
||||||
statusString = 'Connected';
|
break;
|
||||||
showStatus = false;
|
case ConnectionStatus.connecting:
|
||||||
break;
|
statusString = 'Reconnecting...';
|
||||||
case ConnectionStatus.connecting:
|
break;
|
||||||
statusString = 'Reconnecting...';
|
case ConnectionStatus.disconnected:
|
||||||
break;
|
statusString = 'Disconnected';
|
||||||
case ConnectionStatus.disconnected:
|
break;
|
||||||
statusString = 'Disconnected';
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return InfoTile(
|
return InfoTile(
|
||||||
showMessage: widget.showConnectionStateTile && showStatus,
|
showMessage: widget.showConnectionStateTile && showStatus,
|
||||||
tileAnchor: Alignment.topCenter,
|
tileAnchor: Alignment.topCenter,
|
||||||
childAnchor: Alignment.topCenter,
|
childAnchor: Alignment.topCenter,
|
||||||
message: statusString,
|
message: statusString,
|
||||||
child: LazyLoadScrollView(
|
child: LazyLoadScrollView(
|
||||||
onPageScrollStart: () {
|
onPageScrollStart: () {
|
||||||
FocusScope.of(context).unfocus();
|
FocusScope.of(context).unfocus();
|
||||||
|
},
|
||||||
|
onStartOfPage: () async {
|
||||||
|
_inBetweenList = false;
|
||||||
|
if (!_upToDate) {
|
||||||
|
_topPaginationActive = false;
|
||||||
|
_bottomPaginationActive = true;
|
||||||
|
return _paginateData(
|
||||||
|
streamChannel,
|
||||||
|
QueryDirection.bottom,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onEndOfPage: () async {
|
||||||
|
_inBetweenList = false;
|
||||||
|
_topPaginationActive = true;
|
||||||
|
_bottomPaginationActive = false;
|
||||||
|
return _paginateData(
|
||||||
|
streamChannel,
|
||||||
|
QueryDirection.top,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onInBetweenOfPage: () {
|
||||||
|
_inBetweenList = true;
|
||||||
|
},
|
||||||
|
child: ScrollablePositionedList.separated(
|
||||||
|
key: ValueKey(initialIndex! + initialAlignment!),
|
||||||
|
itemPositionsListener: _itemPositionListener,
|
||||||
|
initialScrollIndex: initialIndex ?? 0,
|
||||||
|
initialAlignment: initialAlignment ?? 0,
|
||||||
|
physics: widget.scrollPhysics,
|
||||||
|
itemScrollController: _scrollController,
|
||||||
|
reverse: true,
|
||||||
|
addAutomaticKeepAlives: false,
|
||||||
|
itemCount: itemCount,
|
||||||
|
|
||||||
|
// 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)|
|
||||||
|
// ParentMessage -> 7 (count-1)
|
||||||
|
// Separator(ThreadSeparator) -> 6 (count-2)
|
||||||
|
// Header -> 6 (count-2)
|
||||||
|
// Separator(Header -> 8??T -> 0||52) -> 5 (count-3)
|
||||||
|
// TopLoader -> 5 (count-3)
|
||||||
|
// Separator(0) -> 4 (count-4)
|
||||||
|
// Message -> 4 (count-4)
|
||||||
|
// Separator(2||8) -> 3 (count-5)
|
||||||
|
// Message -> 3 (count-5)
|
||||||
|
// Separator(2||8) -> 2 (count-6)
|
||||||
|
// Message -> 2 (count-6)
|
||||||
|
// Separator(0) -> 1 (count-7)
|
||||||
|
// BottomLoader -> 1 (count-7)
|
||||||
|
// Separator(Footer -> 8??30) -> 0 (count-8)
|
||||||
|
// Footer -> 0 (count-8)
|
||||||
|
|
||||||
|
separatorBuilder: (context, i) {
|
||||||
|
if (i == itemCount - 2) {
|
||||||
|
if (widget.parentMessage == null) {
|
||||||
|
return const Offstage();
|
||||||
|
}
|
||||||
|
return _buildThreadSeparator();
|
||||||
|
}
|
||||||
|
if (i == itemCount - 3) {
|
||||||
|
if (widget.headerBuilder == null) {
|
||||||
|
if (_isThreadConversation) return const Offstage();
|
||||||
|
return const SizedBox(height: 52);
|
||||||
|
}
|
||||||
|
return const SizedBox(height: 8);
|
||||||
|
}
|
||||||
|
if (i == 0) {
|
||||||
|
if (widget.footerBuilder == null) {
|
||||||
|
return const SizedBox(height: 30);
|
||||||
|
}
|
||||||
|
return const SizedBox(height: 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 1 || i == itemCount - 4) return const Offstage();
|
||||||
|
|
||||||
|
final message = messages[i - 1];
|
||||||
|
final nextMessage = messages[i - 2];
|
||||||
|
if (!Jiffy(message.createdAt.toLocal()).isSame(
|
||||||
|
nextMessage.createdAt.toLocal(),
|
||||||
|
Units.DAY,
|
||||||
|
)) {
|
||||||
|
final divider = widget.dateDividerBuilder != null
|
||||||
|
? widget.dateDividerBuilder!(
|
||||||
|
nextMessage.createdAt.toLocal(),
|
||||||
|
)
|
||||||
|
: DateDivider(
|
||||||
|
dateTime: nextMessage.createdAt.toLocal(),
|
||||||
|
);
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
|
child: divider,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
final timeDiff =
|
||||||
|
Jiffy(nextMessage.createdAt.toLocal()).diff(
|
||||||
|
message.createdAt.toLocal(),
|
||||||
|
Units.MINUTE,
|
||||||
|
);
|
||||||
|
|
||||||
|
final isNextUserSame =
|
||||||
|
message.user!.id == nextMessage.user?.id;
|
||||||
|
final isThread = message.replyCount! > 0;
|
||||||
|
final isDeleted = message.isDeleted;
|
||||||
|
if (timeDiff >= 1 ||
|
||||||
|
!isNextUserSame ||
|
||||||
|
isThread ||
|
||||||
|
isDeleted) {
|
||||||
|
return const SizedBox(height: 8);
|
||||||
|
}
|
||||||
|
return const SizedBox(height: 2);
|
||||||
},
|
},
|
||||||
onStartOfPage: () async {
|
itemBuilder: (context, i) {
|
||||||
_inBetweenList = false;
|
if (i == itemCount - 1) {
|
||||||
if (!_upToDate) {
|
if (widget.parentMessage == null) {
|
||||||
_topPaginationActive = false;
|
return const Offstage();
|
||||||
_bottomPaginationActive = true;
|
}
|
||||||
return _paginateData(
|
return buildParentMessage(widget.parentMessage!);
|
||||||
streamChannel,
|
}
|
||||||
|
|
||||||
|
if (i == itemCount - 2) {
|
||||||
|
return widget.headerBuilder?.call(context) ??
|
||||||
|
const Offstage();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == itemCount - 3) {
|
||||||
|
return _buildLoadingIndicator(
|
||||||
|
streamChannel!,
|
||||||
|
QueryDirection.top,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 1) {
|
||||||
|
return _buildLoadingIndicator(
|
||||||
|
streamChannel!,
|
||||||
QueryDirection.bottom,
|
QueryDirection.bottom,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
onEndOfPage: () async {
|
|
||||||
_inBetweenList = false;
|
|
||||||
_topPaginationActive = true;
|
|
||||||
_bottomPaginationActive = false;
|
|
||||||
return _paginateData(
|
|
||||||
streamChannel,
|
|
||||||
QueryDirection.top,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onInBetweenOfPage: () {
|
|
||||||
_inBetweenList = true;
|
|
||||||
},
|
|
||||||
child: ScrollablePositionedList.separated(
|
|
||||||
key: ValueKey(initialIndex! + initialAlignment!),
|
|
||||||
itemPositionsListener: _itemPositionListener,
|
|
||||||
initialScrollIndex: initialIndex ?? 0,
|
|
||||||
initialAlignment: initialAlignment ?? 0,
|
|
||||||
physics: widget.scrollPhysics,
|
|
||||||
itemScrollController: _scrollController,
|
|
||||||
reverse: true,
|
|
||||||
addAutomaticKeepAlives: false,
|
|
||||||
itemCount: itemCount,
|
|
||||||
|
|
||||||
// Item Count -> 8 (1 parent, 2 header+footer, 2 top+bottom, 3 messages)
|
if (i == 0) {
|
||||||
// eg: |Type| rev(|Index(item)|) rev(|Index(separator)|) |Index(item)| |Index(separator)|
|
return widget.footerBuilder?.call(context) ??
|
||||||
// ParentMessage -> 7 (count-1)
|
const Offstage();
|
||||||
// Separator(ThreadSeparator) -> 6 (count-2)
|
}
|
||||||
// Header -> 6 (count-2)
|
|
||||||
// Separator(Header -> 8??T -> 0||52) -> 5 (count-3)
|
|
||||||
// TopLoader -> 5 (count-3)
|
|
||||||
// Separator(0) -> 4 (count-4)
|
|
||||||
// Message -> 4 (count-4)
|
|
||||||
// Separator(2||8) -> 3 (count-5)
|
|
||||||
// Message -> 3 (count-5)
|
|
||||||
// Separator(2||8) -> 2 (count-6)
|
|
||||||
// Message -> 2 (count-6)
|
|
||||||
// Separator(0) -> 1 (count-7)
|
|
||||||
// BottomLoader -> 1 (count-7)
|
|
||||||
// Separator(Footer -> 8??30) -> 0 (count-8)
|
|
||||||
// Footer -> 0 (count-8)
|
|
||||||
|
|
||||||
separatorBuilder: (context, i) {
|
const bottomMessageIndex = 2; // 1 -> loader // 0 -> footer
|
||||||
if (i == itemCount - 2) {
|
|
||||||
if (widget.parentMessage == null) {
|
|
||||||
return const Offstage();
|
|
||||||
}
|
|
||||||
return _buildThreadSeparator();
|
|
||||||
}
|
|
||||||
if (i == itemCount - 3) {
|
|
||||||
if (widget.headerBuilder == null) {
|
|
||||||
if (_isThreadConversation) return const Offstage();
|
|
||||||
return const SizedBox(height: 52);
|
|
||||||
}
|
|
||||||
return const SizedBox(height: 8);
|
|
||||||
}
|
|
||||||
if (i == 0) {
|
|
||||||
if (widget.footerBuilder == null) {
|
|
||||||
return const SizedBox(height: 30);
|
|
||||||
}
|
|
||||||
return const SizedBox(height: 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == 1 || i == itemCount - 4) return const Offstage();
|
final message = messages[i - 2];
|
||||||
|
Widget messageWidget;
|
||||||
|
|
||||||
final message = messages[i - 1];
|
if (i == bottomMessageIndex) {
|
||||||
final nextMessage = messages[i - 2];
|
messageWidget = _buildBottomMessage(
|
||||||
if (!Jiffy(message.createdAt.toLocal()).isSame(
|
context,
|
||||||
nextMessage.createdAt.toLocal(),
|
message,
|
||||||
Units.DAY,
|
messages,
|
||||||
)) {
|
streamChannel!,
|
||||||
final divider = widget.dateDividerBuilder != null
|
i - 2,
|
||||||
? widget.dateDividerBuilder!(
|
|
||||||
nextMessage.createdAt.toLocal(),
|
|
||||||
)
|
|
||||||
: DateDivider(
|
|
||||||
dateTime: nextMessage.createdAt.toLocal(),
|
|
||||||
);
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
|
||||||
child: divider,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
final timeDiff =
|
|
||||||
Jiffy(nextMessage.createdAt.toLocal()).diff(
|
|
||||||
message.createdAt.toLocal(),
|
|
||||||
Units.MINUTE,
|
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
final isNextUserSame =
|
messageWidget = buildMessage(message, messages, i - 2);
|
||||||
message.user!.id == nextMessage.user?.id;
|
}
|
||||||
final isThread = message.replyCount! > 0;
|
return messageWidget;
|
||||||
final isDeleted = message.isDeleted;
|
},
|
||||||
if (timeDiff >= 1 ||
|
|
||||||
!isNextUserSame ||
|
|
||||||
isThread ||
|
|
||||||
isDeleted) {
|
|
||||||
return const SizedBox(height: 8);
|
|
||||||
}
|
|
||||||
return const SizedBox(height: 2);
|
|
||||||
},
|
|
||||||
itemBuilder: (context, i) {
|
|
||||||
if (i == itemCount - 1) {
|
|
||||||
if (widget.parentMessage == null) {
|
|
||||||
return const Offstage();
|
|
||||||
}
|
|
||||||
return buildParentMessage(widget.parentMessage!);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == itemCount - 2) {
|
|
||||||
return widget.headerBuilder?.call(context) ??
|
|
||||||
const Offstage();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == itemCount - 3) {
|
|
||||||
return _buildLoadingIndicator(
|
|
||||||
streamChannel!,
|
|
||||||
QueryDirection.top,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == 1) {
|
|
||||||
return _buildLoadingIndicator(
|
|
||||||
streamChannel!,
|
|
||||||
QueryDirection.bottom,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == 0) {
|
|
||||||
return widget.footerBuilder?.call(context) ??
|
|
||||||
const Offstage();
|
|
||||||
}
|
|
||||||
|
|
||||||
const bottomMessageIndex =
|
|
||||||
2; // 1 -> loader // 0 -> footer
|
|
||||||
|
|
||||||
final message = messages[i - 2];
|
|
||||||
Widget messageWidget;
|
|
||||||
|
|
||||||
if (i == bottomMessageIndex) {
|
|
||||||
messageWidget = _buildBottomMessage(
|
|
||||||
context,
|
|
||||||
message,
|
|
||||||
messages,
|
|
||||||
streamChannel!,
|
|
||||||
i - 2,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
messageWidget = buildMessage(message, messages, i - 2);
|
|
||||||
}
|
|
||||||
return messageWidget;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
},
|
);
|
||||||
),
|
},
|
||||||
if (widget.showScrollToBottom) _buildScrollToBottom(),
|
),
|
||||||
if (widget.showFloatingDateDivider)
|
if (widget.showScrollToBottom) _buildScrollToBottom(),
|
||||||
_buildFloatingDateDivider(itemCount),
|
if (widget.showFloatingDateDivider)
|
||||||
],
|
_buildFloatingDateDivider(itemCount),
|
||||||
),
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final backgroundColor = MessageListViewTheme.of(context).backgroundColor;
|
||||||
|
|
||||||
|
if (backgroundColor != null) {
|
||||||
|
return ColoredBox(
|
||||||
|
color: backgroundColor,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildThreadSeparator() {
|
Widget _buildThreadSeparator() {
|
||||||
|
|||||||
@@ -144,61 +144,72 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
|||||||
widget.messageSearchListController ?? _defaultController;
|
widget.messageSearchListController ?? _defaultController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => ColoredBox(
|
Widget build(BuildContext context) {
|
||||||
color: MessageSearchListViewTheme.of(context).backgroundColor!,
|
final messageSearchListCore = MessageSearchListCore(
|
||||||
child: MessageSearchListCore(
|
filters: widget.filters,
|
||||||
filters: widget.filters,
|
sortOptions: widget.sortOptions,
|
||||||
sortOptions: widget.sortOptions,
|
messageQuery: widget.messageQuery,
|
||||||
messageQuery: widget.messageQuery,
|
paginationParams: widget.paginationParams,
|
||||||
paginationParams: widget.paginationParams,
|
messageFilters: widget.messageFilters,
|
||||||
messageFilters: widget.messageFilters,
|
messageSearchListController: _messageSearchListController,
|
||||||
messageSearchListController: _messageSearchListController,
|
emptyBuilder: widget.emptyBuilder ??
|
||||||
emptyBuilder: widget.emptyBuilder ??
|
(context) => LayoutBuilder(
|
||||||
(context) => LayoutBuilder(
|
builder: (context, viewportConstraints) =>
|
||||||
builder: (context, viewportConstraints) =>
|
SingleChildScrollView(
|
||||||
SingleChildScrollView(
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
child: ConstrainedBox(
|
||||||
child: ConstrainedBox(
|
constraints: BoxConstraints(
|
||||||
constraints: BoxConstraints(
|
minHeight: viewportConstraints.maxHeight,
|
||||||
minHeight: viewportConstraints.maxHeight,
|
),
|
||||||
),
|
child: const Center(
|
||||||
child: const Center(
|
child: Text('There are no messages currently'),
|
||||||
child: Text('There are no messages currently'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
errorBuilder: widget.errorBuilder ??
|
),
|
||||||
(BuildContext context, dynamic error) {
|
),
|
||||||
if (error is Error) {
|
errorBuilder: widget.errorBuilder ??
|
||||||
print(error.stackTrace);
|
(BuildContext context, dynamic error) {
|
||||||
}
|
if (error is Error) {
|
||||||
return InfoTile(
|
print(error.stackTrace);
|
||||||
showMessage: widget.showErrorTile,
|
}
|
||||||
tileAnchor: Alignment.topCenter,
|
return InfoTile(
|
||||||
childAnchor: Alignment.topCenter,
|
showMessage: widget.showErrorTile,
|
||||||
message: 'An error occurred.',
|
tileAnchor: Alignment.topCenter,
|
||||||
child: Container(),
|
childAnchor: Alignment.topCenter,
|
||||||
);
|
message: 'An error occurred.',
|
||||||
},
|
child: Container(),
|
||||||
loadingBuilder: widget.loadingBuilder ??
|
);
|
||||||
(context) => LayoutBuilder(
|
},
|
||||||
builder: (context, viewportConstraints) =>
|
loadingBuilder: widget.loadingBuilder ??
|
||||||
SingleChildScrollView(
|
(context) => LayoutBuilder(
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
builder: (context, viewportConstraints) =>
|
||||||
child: ConstrainedBox(
|
SingleChildScrollView(
|
||||||
constraints: BoxConstraints(
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
minHeight: viewportConstraints.maxHeight,
|
child: ConstrainedBox(
|
||||||
),
|
constraints: BoxConstraints(
|
||||||
child: const Center(
|
minHeight: viewportConstraints.maxHeight,
|
||||||
child: CircularProgressIndicator(),
|
),
|
||||||
),
|
child: const Center(
|
||||||
),
|
child: CircularProgressIndicator(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
childBuilder: widget.childBuilder ?? _buildListView,
|
),
|
||||||
),
|
),
|
||||||
|
childBuilder: widget.childBuilder ?? _buildListView,
|
||||||
|
);
|
||||||
|
|
||||||
|
final backgroundColor =
|
||||||
|
MessageSearchListViewTheme.of(context).backgroundColor;
|
||||||
|
|
||||||
|
if (backgroundColor != null) {
|
||||||
|
return ColoredBox(
|
||||||
|
color: backgroundColor,
|
||||||
|
child: messageSearchListCore,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return messageSearchListCore;
|
||||||
|
}
|
||||||
|
|
||||||
Widget _separatorBuilder(BuildContext context, int index) => Container(
|
Widget _separatorBuilder(BuildContext context, int index) => Container(
|
||||||
height: 1,
|
height: 1,
|
||||||
|
|||||||
@@ -160,38 +160,48 @@ class _UserListViewState extends State<UserListView>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final child = ColoredBox(
|
final userListCore = UserListCore(
|
||||||
color: UserListViewTheme.of(context).backgroundColor!,
|
errorBuilder: widget.errorBuilder ??
|
||||||
child: UserListCore(
|
(BuildContext context, Object err) => _buildError(err),
|
||||||
errorBuilder: widget.errorBuilder ??
|
emptyBuilder: widget.emptyBuilder ?? (context) => _buildEmpty(),
|
||||||
(BuildContext context, Object err) => _buildError(err),
|
loadingBuilder: widget.loadingBuilder ??
|
||||||
emptyBuilder: widget.emptyBuilder ?? (context) => _buildEmpty(),
|
(context) => LayoutBuilder(
|
||||||
loadingBuilder: widget.loadingBuilder ??
|
builder: (context, viewportConstraints) =>
|
||||||
(context) => LayoutBuilder(
|
SingleChildScrollView(
|
||||||
builder: (context, viewportConstraints) =>
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
SingleChildScrollView(
|
child: ConstrainedBox(
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
constraints: BoxConstraints(
|
||||||
child: ConstrainedBox(
|
minHeight: viewportConstraints.maxHeight,
|
||||||
constraints: BoxConstraints(
|
),
|
||||||
minHeight: viewportConstraints.maxHeight,
|
child: const Center(
|
||||||
),
|
child: CircularProgressIndicator(),
|
||||||
child: const Center(
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
listBuilder:
|
),
|
||||||
widget.listBuilder ?? (context, list) => _buildListView(list),
|
listBuilder:
|
||||||
pagination: widget.pagination,
|
widget.listBuilder ?? (context, list) => _buildListView(list),
|
||||||
sort: widget.sort,
|
pagination: widget.pagination,
|
||||||
filter: widget.filter,
|
sort: widget.sort,
|
||||||
presence: widget.presence,
|
filter: widget.filter,
|
||||||
groupAlphabetically: widget.groupAlphabetically,
|
presence: widget.presence,
|
||||||
userListController: _userListController,
|
groupAlphabetically: widget.groupAlphabetically,
|
||||||
),
|
userListController: _userListController,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final backgroundColor = UserListViewTheme.of(context).backgroundColor;
|
||||||
|
|
||||||
|
Widget child;
|
||||||
|
|
||||||
|
if (backgroundColor != null) {
|
||||||
|
child = ColoredBox(
|
||||||
|
color: backgroundColor,
|
||||||
|
child: userListCore,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
child = userListCore;
|
||||||
|
}
|
||||||
|
|
||||||
if (!widget.pullToRefresh) {
|
if (!widget.pullToRefresh) {
|
||||||
return child;
|
return child;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user