UI nit picks
This commit is contained in:
@@ -34,10 +34,8 @@ class ChipInputTextFieldState<T> extends State<ChipsInputTextField<T>> {
|
|||||||
bool _pauseItemAddition = false;
|
bool _pauseItemAddition = false;
|
||||||
|
|
||||||
void addItem(T item) {
|
void addItem(T item) {
|
||||||
if (!_pauseItemAddition) {
|
setState(() => _chips.add(item));
|
||||||
setState(() => _chips.add(item));
|
if (widget.onChipAdded != null) widget.onChipAdded(item);
|
||||||
if (widget.onChipAdded != null) widget.onChipAdded(item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeItem(T item) {
|
void removeItem(T item) {
|
||||||
@@ -108,6 +106,9 @@ class ChipInputTextFieldState<T> extends State<ChipsInputTextField<T>> {
|
|||||||
disabledBorder: InputBorder.none,
|
disabledBorder: InputBorder.none,
|
||||||
contentPadding: const EdgeInsets.only(top: 4.0),
|
contentPadding: const EdgeInsets.only(top: 4.0),
|
||||||
hintText: widget.hint,
|
hintText: widget.hint,
|
||||||
|
hintStyle: TextStyle(
|
||||||
|
color: Colors.black.withOpacity(0.5),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
+54
-24
@@ -309,6 +309,7 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
backgroundColor: Color.fromRGBO(252, 252, 252, 1),
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
@@ -367,7 +368,6 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
),
|
),
|
||||||
if (!_isSearchActive)
|
if (!_isSearchActive)
|
||||||
Container(
|
Container(
|
||||||
color: Colors.white54,
|
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
@@ -375,23 +375,26 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
MaterialPageRoute(builder: (_) => NewGroupChatScreen()),
|
MaterialPageRoute(builder: (_) => NewGroupChatScreen()),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Padding(
|
||||||
children: [
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
NeumorphicButton(
|
child: Row(
|
||||||
child: Icon(
|
children: [
|
||||||
StreamIcons.group,
|
NeumorphicButton(
|
||||||
color: Colors.blue.shade700,
|
child: Icon(
|
||||||
|
StreamIcons.group,
|
||||||
|
color: Color(0xFF006CFF),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
SizedBox(width: 8),
|
||||||
SizedBox(width: 8),
|
Text(
|
||||||
Text(
|
'Create a Group',
|
||||||
'Create a Group',
|
style: TextStyle(
|
||||||
style: TextStyle(
|
fontWeight: FontWeight.bold,
|
||||||
fontWeight: FontWeight.w500,
|
fontSize: 16,
|
||||||
fontSize: 18,
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -425,20 +428,33 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: UserListView(
|
child: UserListView(
|
||||||
filterByUserName: _userNameQuery,
|
|
||||||
selectedUsers: _selectedUsers,
|
selectedUsers: _selectedUsers,
|
||||||
groupAlphabetically: _isSearchActive ? false : true,
|
groupAlphabetically: _isSearchActive ? false : true,
|
||||||
onUserTap: (user, _) {
|
onUserTap: (user, _) {
|
||||||
|
_controller.clear();
|
||||||
if (!_selectedUsers.contains(user)) {
|
if (!_selectedUsers.contains(user)) {
|
||||||
_controller.clear();
|
|
||||||
_chipInputTextFieldState
|
_chipInputTextFieldState
|
||||||
..addItem(user)
|
..addItem(user)
|
||||||
..pauseItemAddition();
|
..pauseItemAddition();
|
||||||
|
} else {
|
||||||
|
_chipInputTextFieldState.removeItem(user);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
pagination: PaginationParams(
|
pagination: PaginationParams(
|
||||||
limit: 25,
|
limit: 25,
|
||||||
),
|
),
|
||||||
|
filter: {
|
||||||
|
if (_userNameQuery.isNotEmpty)
|
||||||
|
'name': {
|
||||||
|
r'$autocomplete': _userNameQuery,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sort: [
|
||||||
|
SortOption(
|
||||||
|
'name',
|
||||||
|
direction: 1,
|
||||||
|
),
|
||||||
|
],
|
||||||
emptyBuilder: (_) {
|
emptyBuilder: (_) {
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (context, viewportConstraints) {
|
builder: (context, viewportConstraints) {
|
||||||
@@ -541,6 +557,7 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
backgroundColor: Color.fromRGBO(252, 252, 252, 1),
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
@@ -555,7 +572,7 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
StreamIcons.arrow_right,
|
StreamIcons.arrow_right,
|
||||||
color: Colors.blue.shade700,
|
color: Color(0xFF006CFF),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
@@ -576,6 +593,7 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||||||
Container(
|
Container(
|
||||||
height: 36,
|
height: 36,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: Colors.grey.shade300,
|
color: Colors.grey.shade300,
|
||||||
),
|
),
|
||||||
@@ -593,8 +611,10 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
),
|
),
|
||||||
hintText: 'Search',
|
hintText: 'Search',
|
||||||
|
hintStyle: TextStyle(
|
||||||
|
color: Colors.black.withOpacity(0.5),
|
||||||
|
),
|
||||||
contentPadding: const EdgeInsets.all(0),
|
contentPadding: const EdgeInsets.all(0),
|
||||||
// isDense: true,
|
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderSide: BorderSide.none,
|
borderSide: BorderSide.none,
|
||||||
borderRadius: BorderRadius.circular(24),
|
borderRadius: BorderRadius.circular(24),
|
||||||
@@ -696,7 +716,6 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: UserListView(
|
child: UserListView(
|
||||||
filterByUserName: _userNameQuery,
|
|
||||||
selectedUsers: _selectedUsers,
|
selectedUsers: _selectedUsers,
|
||||||
groupAlphabetically: _isSearchActive ? false : true,
|
groupAlphabetically: _isSearchActive ? false : true,
|
||||||
onUserTap: (user, _) {
|
onUserTap: (user, _) {
|
||||||
@@ -709,6 +728,18 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||||||
pagination: PaginationParams(
|
pagination: PaginationParams(
|
||||||
limit: 25,
|
limit: 25,
|
||||||
),
|
),
|
||||||
|
filter: {
|
||||||
|
if (_userNameQuery.isNotEmpty)
|
||||||
|
'name': {
|
||||||
|
r'$autocomplete': _userNameQuery,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sort: [
|
||||||
|
SortOption(
|
||||||
|
'name',
|
||||||
|
direction: 1,
|
||||||
|
),
|
||||||
|
],
|
||||||
emptyBuilder: (_) {
|
emptyBuilder: (_) {
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (context, viewportConstraints) {
|
builder: (context, viewportConstraints) {
|
||||||
@@ -797,6 +828,7 @@ class _GroupChatDetailsScreenState extends State<GroupChatDetailsScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
backgroundColor: Color.fromRGBO(252, 252, 252, 1),
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
@@ -840,12 +872,10 @@ class _GroupChatDetailsScreenState extends State<GroupChatDetailsScreen> {
|
|||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
NeumorphicButton(
|
NeumorphicButton(
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
margin: const EdgeInsets.symmetric(vertical: 8),
|
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
padding: const EdgeInsets.all(0),
|
padding: const EdgeInsets.all(0),
|
||||||
icon: Icon(StreamIcons.check),
|
icon: Icon(StreamIcons.check),
|
||||||
color: Colors.blue.shade700,
|
color: Color(0xFF006CFF),
|
||||||
onPressed: _isGroupNameEmpty
|
onPressed: _isGroupNameEmpty
|
||||||
? null
|
? null
|
||||||
: () async {
|
: () async {
|
||||||
|
|||||||
@@ -1,50 +1,38 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
extension ColorUtils on Color {
|
|
||||||
Color mix(Color another, double amount) {
|
|
||||||
return Color.lerp(this, another, amount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NeumorphicButton extends StatelessWidget {
|
class NeumorphicButton extends StatelessWidget {
|
||||||
final Widget child;
|
final Widget child;
|
||||||
final Color backgroundColor;
|
final Color backgroundColor;
|
||||||
final EdgeInsets margin;
|
|
||||||
final EdgeInsets padding;
|
|
||||||
|
|
||||||
const NeumorphicButton({
|
const NeumorphicButton({
|
||||||
Key key,
|
Key key,
|
||||||
@required this.child,
|
@required this.child,
|
||||||
this.backgroundColor = Colors.white,
|
this.backgroundColor = Colors.white,
|
||||||
this.margin = const EdgeInsets.all(8),
|
|
||||||
this.padding = const EdgeInsets.all(14),
|
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
child: child,
|
child: child,
|
||||||
margin: margin,
|
margin: EdgeInsets.all(8.0),
|
||||||
padding: padding,
|
height: 40,
|
||||||
|
width: 40,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
|
||||||
color: backgroundColor,
|
color: backgroundColor,
|
||||||
gradient: LinearGradient(
|
shape: BoxShape.circle,
|
||||||
begin: Alignment.topLeft,
|
|
||||||
end: Alignment.bottomRight,
|
|
||||||
colors: [
|
|
||||||
backgroundColor.mix(Colors.white, 0.2),
|
|
||||||
backgroundColor.mix(Colors.black, 0.1),
|
|
||||||
]),
|
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
blurRadius: 1,
|
color: Colors.grey[700],
|
||||||
color: backgroundColor.mix(Colors.white, 0.6),
|
offset: Offset(0, 1.0),
|
||||||
|
blurRadius: 0.5,
|
||||||
|
spreadRadius: 0,
|
||||||
),
|
),
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
blurRadius: 1,
|
color: Colors.white,
|
||||||
color: backgroundColor.mix(Colors.black, 0.3),
|
offset: Offset.zero,
|
||||||
)
|
blurRadius: 0.5,
|
||||||
|
spreadRadius: 0,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
+30
-58
@@ -1,7 +1,6 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:rxdart/rxdart.dart';
|
|
||||||
import 'package:stream_chat/stream_chat.dart';
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
import 'package:stream_chat_flutter/src/users_bloc.dart';
|
import 'package:stream_chat_flutter/src/users_bloc.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
@@ -66,13 +65,7 @@ class UserListView extends StatefulWidget {
|
|||||||
this.swipeToAction = false,
|
this.swipeToAction = false,
|
||||||
this.pullToRefresh = true,
|
this.pullToRefresh = true,
|
||||||
this.groupAlphabetically = false,
|
this.groupAlphabetically = false,
|
||||||
this.filterByUserName = '',
|
}) : super(key: key);
|
||||||
this.filterByUserNameStream,
|
|
||||||
}) : assert(
|
|
||||||
filterByUserName == null || filterByUserNameStream == null,
|
|
||||||
'Cannot provide both filterByUserName and filterByUserNameStream.',
|
|
||||||
),
|
|
||||||
super(key: key);
|
|
||||||
|
|
||||||
/// The builder that will be used in case of error
|
/// The builder that will be used in case of error
|
||||||
final Widget Function(Error error) errorBuilder;
|
final Widget Function(Error error) errorBuilder;
|
||||||
@@ -137,12 +130,6 @@ class UserListView extends StatefulWidget {
|
|||||||
/// defaults to false
|
/// defaults to false
|
||||||
final bool groupAlphabetically;
|
final bool groupAlphabetically;
|
||||||
|
|
||||||
///
|
|
||||||
final String filterByUserName;
|
|
||||||
|
|
||||||
///
|
|
||||||
final Stream<String> filterByUserNameStream;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_UserListViewState createState() => _UserListViewState();
|
_UserListViewState createState() => _UserListViewState();
|
||||||
}
|
}
|
||||||
@@ -154,8 +141,8 @@ class _UserListViewState extends State<UserListView>
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
final channelsBloc = UsersBloc.of(context);
|
final usersBloc = UsersBloc.of(context);
|
||||||
channelsBloc.queryUsers(
|
usersBloc.queryUsers(
|
||||||
filter: widget.filter,
|
filter: widget.filter,
|
||||||
sort: widget.sort,
|
sort: widget.sort,
|
||||||
pagination: widget.pagination,
|
pagination: widget.pagination,
|
||||||
@@ -163,9 +150,9 @@ class _UserListViewState extends State<UserListView>
|
|||||||
);
|
);
|
||||||
|
|
||||||
_scrollController.addListener(() {
|
_scrollController.addListener(() {
|
||||||
channelsBloc.queryUsersLoading.first.then((loading) {
|
usersBloc.queryUsersLoading.first.then((loading) {
|
||||||
if (!loading) {
|
if (!loading) {
|
||||||
_listenUserPagination(channelsBloc);
|
_listenUserPagination(usersBloc);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -192,42 +179,28 @@ class _UserListViewState extends State<UserListView>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ListItem> _getFilteredItems(List<User> users, String query) {
|
|
||||||
if (widget.groupAlphabetically) {
|
|
||||||
var temp = users..sort((curr, next) => curr.name.compareTo(next.name));
|
|
||||||
temp = temp
|
|
||||||
.where((it) => it.name.toLowerCase().contains(query.toLowerCase()))
|
|
||||||
.toList();
|
|
||||||
final groupedUsers = <String, List<User>>{};
|
|
||||||
for (var e in temp) {
|
|
||||||
final alphabet = e.name[0];
|
|
||||||
groupedUsers[alphabet] = [...groupedUsers[alphabet] ?? [], e];
|
|
||||||
}
|
|
||||||
final items = <ListItem>[];
|
|
||||||
for (var key in groupedUsers.keys) {
|
|
||||||
items.add(ListHeaderItem(key));
|
|
||||||
items.addAll(groupedUsers[key].map((e) => ListUserItem(e)));
|
|
||||||
}
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
return users
|
|
||||||
.where((it) => it.name.toLowerCase().contains(query.toLowerCase()))
|
|
||||||
.map((e) => ListUserItem(e))
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
Stream<List<ListItem>> _buildUserStream(
|
Stream<List<ListItem>> _buildUserStream(
|
||||||
UsersBlocState usersBlocState,
|
UsersBlocState usersBlocState,
|
||||||
) {
|
) {
|
||||||
if (widget.filterByUserNameStream == null) {
|
return usersBlocState.usersStream.map(
|
||||||
return usersBlocState.usersStream.map(
|
(users) {
|
||||||
(users) => _getFilteredItems(users, widget.filterByUserName),
|
if (widget.groupAlphabetically) {
|
||||||
);
|
var temp = users
|
||||||
}
|
..sort((curr, next) => curr.name.compareTo(next.name));
|
||||||
return Rx.combineLatest2(
|
final groupedUsers = <String, List<User>>{};
|
||||||
usersBlocState.usersStream,
|
for (var e in temp) {
|
||||||
widget.filterByUserNameStream,
|
final alphabet = e.name[0];
|
||||||
_getFilteredItems,
|
groupedUsers[alphabet] = [...groupedUsers[alphabet] ?? [], e];
|
||||||
|
}
|
||||||
|
final items = <ListItem>[];
|
||||||
|
for (var key in groupedUsers.keys) {
|
||||||
|
items.add(ListHeaderItem(key));
|
||||||
|
items.addAll(groupedUsers[key].map((e) => ListUserItem(e)));
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
return users.map((e) => ListUserItem(e)).toList();
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,14 +351,13 @@ class _UserListViewState extends State<UserListView>
|
|||||||
key: ValueKey<String>('HEADER-$header'),
|
key: ValueKey<String>('HEADER-$header'),
|
||||||
color: Colors.black.withOpacity(0.05),
|
color: Colors.black.withOpacity(0.05),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal:8.0,vertical: 6),
|
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 6),
|
||||||
child: Text(
|
child: Text(
|
||||||
header,
|
header,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color:Colors.black.withOpacity(0.3)
|
color: Colors.black.withOpacity(0.3)),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -469,8 +441,8 @@ class _UserListViewState extends State<UserListView>
|
|||||||
widget.pagination?.toJson()?.toString() !=
|
widget.pagination?.toJson()?.toString() !=
|
||||||
oldWidget.pagination?.toJson()?.toString() ||
|
oldWidget.pagination?.toJson()?.toString() ||
|
||||||
widget.options?.toString() != oldWidget.options?.toString()) {
|
widget.options?.toString() != oldWidget.options?.toString()) {
|
||||||
final channelsBloc = UsersBloc.of(context);
|
final usersBloc = UsersBloc.of(context);
|
||||||
channelsBloc.queryUsers(
|
usersBloc.queryUsers(
|
||||||
filter: widget.filter,
|
filter: widget.filter,
|
||||||
sort: widget.sort,
|
sort: widget.sort,
|
||||||
pagination: widget.pagination,
|
pagination: widget.pagination,
|
||||||
|
|||||||
Reference in New Issue
Block a user