Merge pull request #88 from GetStream/feature/createChannelInExample
Feature/create channel in example
This commit is contained in:
@@ -108,6 +108,14 @@ class ChannelListPage extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
floatingActionButton: FloatingActionButton(
|
||||||
|
child: Icon(Icons.add),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
|
||||||
|
return CreateChannelPage();
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
),
|
||||||
body: ChannelsBloc(
|
body: ChannelsBloc(
|
||||||
child: ChannelListView(
|
child: ChannelListView(
|
||||||
filter: {
|
filter: {
|
||||||
@@ -198,3 +206,189 @@ class ThreadPage extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CreateChannelPage extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_CreateChannelPageState createState() => _CreateChannelPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CreateChannelPageState extends State<CreateChannelPage> {
|
||||||
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
Client client;
|
||||||
|
List<User> users = [];
|
||||||
|
List<User> selectedUsers = [];
|
||||||
|
int offset = 0;
|
||||||
|
bool loading = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
elevation: 0,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
title: Text(
|
||||||
|
'Create a channel',
|
||||||
|
style: Theme.of(context).textTheme.headline6,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
floatingActionButton:
|
||||||
|
selectedUsers.isNotEmpty ? _buildFAB(context) : SizedBox(),
|
||||||
|
body: _buildListView(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView _buildListView() {
|
||||||
|
return ListView.builder(
|
||||||
|
controller: _scrollController,
|
||||||
|
itemBuilder: _itemBuilder,
|
||||||
|
itemCount: users.length,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _itemBuilder(context, i) {
|
||||||
|
final user = users[i];
|
||||||
|
return ListTile(
|
||||||
|
onLongPress: () {
|
||||||
|
_selectUser(user);
|
||||||
|
},
|
||||||
|
selected: selectedUsers.contains(user),
|
||||||
|
onTap: () {
|
||||||
|
if (selectedUsers.isNotEmpty) {
|
||||||
|
return _selectUser(user);
|
||||||
|
}
|
||||||
|
_createChannel(context, [user]);
|
||||||
|
},
|
||||||
|
leading: UserAvatar(
|
||||||
|
user: user,
|
||||||
|
),
|
||||||
|
title: Text(user.name),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildFAB(BuildContext context) {
|
||||||
|
return FloatingActionButton(
|
||||||
|
child: Icon(Icons.done),
|
||||||
|
onPressed: () async {
|
||||||
|
String name;
|
||||||
|
if (selectedUsers.length > 1) {
|
||||||
|
name = await _showEnterNameDialog(context);
|
||||||
|
if (name?.isNotEmpty != true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_createChannel(context, selectedUsers, name);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> _showEnterNameDialog(BuildContext context) {
|
||||||
|
final controller = TextEditingController();
|
||||||
|
return showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => SimpleDialog(
|
||||||
|
contentPadding: const EdgeInsets.all(16),
|
||||||
|
title: Text('Enter a name for the channel'),
|
||||||
|
children: [
|
||||||
|
TextField(
|
||||||
|
controller: controller,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ButtonBar(
|
||||||
|
children: [
|
||||||
|
FlatButton(
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
child: Text('Cancel'),
|
||||||
|
),
|
||||||
|
FlatButton(
|
||||||
|
onPressed: () => Navigator.pop(context, controller.text),
|
||||||
|
child: Text('Ok'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future _createChannel(
|
||||||
|
BuildContext context,
|
||||||
|
List<User> users, [
|
||||||
|
String name,
|
||||||
|
]) async {
|
||||||
|
final channel = client.channel('messaging', extraData: {
|
||||||
|
'members': [
|
||||||
|
client.state.user.id,
|
||||||
|
...users.map((e) => e.id),
|
||||||
|
],
|
||||||
|
if (name != null) 'name': name,
|
||||||
|
});
|
||||||
|
await channel.watch();
|
||||||
|
Navigator.pushReplacement(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) {
|
||||||
|
return StreamChannel(
|
||||||
|
child: ChannelPage(),
|
||||||
|
channel: channel,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _selectUser(User user) {
|
||||||
|
if (!selectedUsers.contains(user)) {
|
||||||
|
setState(() {
|
||||||
|
selectedUsers.add(user);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
selectedUsers.remove(user);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
client = StreamChat.of(context).client;
|
||||||
|
|
||||||
|
_scrollController.addListener(() async {
|
||||||
|
if (!loading &&
|
||||||
|
_scrollController.offset >=
|
||||||
|
_scrollController.position.maxScrollExtent - 100) {
|
||||||
|
offset += 25;
|
||||||
|
await _queryUsers();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_queryUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _queryUsers() {
|
||||||
|
loading = true;
|
||||||
|
return client.queryUsers(
|
||||||
|
pagination: PaginationParams(
|
||||||
|
limit: 25,
|
||||||
|
offset: offset,
|
||||||
|
),
|
||||||
|
sort: [
|
||||||
|
SortOption(
|
||||||
|
'name',
|
||||||
|
direction: SortOption.ASC,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).then((value) {
|
||||||
|
setState(() {
|
||||||
|
users = [
|
||||||
|
...users,
|
||||||
|
...value.users,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}).whenComplete(() => loading = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
name: example
|
name: example
|
||||||
description: A new Flutter project.
|
description: A new Flutter project.
|
||||||
|
|
||||||
version: 1.0.3+4
|
version: 1.0.6+7
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.2.2 <3.0.0"
|
sdk: ">=2.2.2 <3.0.0"
|
||||||
|
|||||||
@@ -120,15 +120,17 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
stream: channel.lastMessageAtStream,
|
stream: channel.lastMessageAtStream,
|
||||||
initialData: channel.lastMessageAt,
|
initialData: channel.lastMessageAt,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
return (snapshot.data != null)
|
if (snapshot.data == null) {
|
||||||
? Text(
|
return SizedBox();
|
||||||
'Active ${Jiffy(snapshot.data.toLocal()).fromNow()}',
|
}
|
||||||
style: StreamChatTheme.of(context)
|
final jiffyDate = Jiffy(snapshot.data?.toLocal());
|
||||||
.channelTheme
|
return Text(
|
||||||
.channelHeaderTheme
|
'Active ${jiffyDate.isBefore(Jiffy()) ? jiffyDate.fromNow() : 'now'}',
|
||||||
.lastMessageAt,
|
style: StreamChatTheme.of(context)
|
||||||
)
|
.channelTheme
|
||||||
: SizedBox();
|
.channelHeaderTheme
|
||||||
|
.lastMessageAt,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ class ChannelName extends StatelessWidget {
|
|||||||
return Text(
|
return Text(
|
||||||
title,
|
title,
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -124,18 +124,23 @@ class ChannelsBlocState extends State<ChannelsBloc>
|
|||||||
_subscriptions.add(client.on(EventType.messageNew).listen((e) {
|
_subscriptions.add(client.on(EventType.messageNew).listen((e) {
|
||||||
final newChannels = List<Channel>.from(channels ?? []);
|
final newChannels = List<Channel>.from(channels ?? []);
|
||||||
final index = newChannels.indexWhere((c) => c.cid == e.cid);
|
final index = newChannels.indexWhere((c) => c.cid == e.cid);
|
||||||
if (index > 0) {
|
if (index > -1) {
|
||||||
final channel = newChannels.removeAt(index);
|
if (index > 0) {
|
||||||
newChannels.insert(0, channel);
|
final channel = newChannels.removeAt(index);
|
||||||
_channelsController.add(newChannels);
|
newChannels.insert(0, channel);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
final hiddenIndex = _hiddenChannels.indexWhere((c) => c.cid == e.cid);
|
final hiddenIndex = _hiddenChannels.indexWhere((c) => c.cid == e.cid);
|
||||||
if (hiddenIndex > -1) {
|
if (hiddenIndex > -1) {
|
||||||
newChannels.insert(0, _hiddenChannels[hiddenIndex]);
|
newChannels.insert(0, _hiddenChannels[hiddenIndex]);
|
||||||
_hiddenChannels.removeAt(hiddenIndex);
|
_hiddenChannels.removeAt(hiddenIndex);
|
||||||
_channelsController.add(newChannels);
|
} else {
|
||||||
|
if (client.state.channels[e.cid] != null) {
|
||||||
|
newChannels.insert(0, client.state.channels[e.cid]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_channelsController.add(newChannels);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user