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
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
floatingActionButton: FloatingActionButton(
|
||||
child: Icon(Icons.add),
|
||||
onPressed: () {
|
||||
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
|
||||
return CreateChannelPage();
|
||||
}));
|
||||
},
|
||||
),
|
||||
body: ChannelsBloc(
|
||||
child: ChannelListView(
|
||||
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
|
||||
description: A new Flutter project.
|
||||
|
||||
version: 1.0.3+4
|
||||
version: 1.0.6+7
|
||||
|
||||
environment:
|
||||
sdk: ">=2.2.2 <3.0.0"
|
||||
|
||||
@@ -120,15 +120,17 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
stream: channel.lastMessageAtStream,
|
||||
initialData: channel.lastMessageAt,
|
||||
builder: (context, snapshot) {
|
||||
return (snapshot.data != null)
|
||||
? Text(
|
||||
'Active ${Jiffy(snapshot.data.toLocal()).fromNow()}',
|
||||
style: StreamChatTheme.of(context)
|
||||
.channelTheme
|
||||
.channelHeaderTheme
|
||||
.lastMessageAt,
|
||||
)
|
||||
: SizedBox();
|
||||
if (snapshot.data == null) {
|
||||
return SizedBox();
|
||||
}
|
||||
final jiffyDate = Jiffy(snapshot.data?.toLocal());
|
||||
return Text(
|
||||
'Active ${jiffyDate.isBefore(Jiffy()) ? jiffyDate.fromNow() : 'now'}',
|
||||
style: StreamChatTheme.of(context)
|
||||
.channelTheme
|
||||
.channelHeaderTheme
|
||||
.lastMessageAt,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ class ChannelName extends StatelessWidget {
|
||||
return Text(
|
||||
title,
|
||||
style: textStyle,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -124,18 +124,23 @@ class ChannelsBlocState extends State<ChannelsBloc>
|
||||
_subscriptions.add(client.on(EventType.messageNew).listen((e) {
|
||||
final newChannels = List<Channel>.from(channels ?? []);
|
||||
final index = newChannels.indexWhere((c) => c.cid == e.cid);
|
||||
if (index > 0) {
|
||||
final channel = newChannels.removeAt(index);
|
||||
newChannels.insert(0, channel);
|
||||
_channelsController.add(newChannels);
|
||||
if (index > -1) {
|
||||
if (index > 0) {
|
||||
final channel = newChannels.removeAt(index);
|
||||
newChannels.insert(0, channel);
|
||||
}
|
||||
} else {
|
||||
final hiddenIndex = _hiddenChannels.indexWhere((c) => c.cid == e.cid);
|
||||
if (hiddenIndex > -1) {
|
||||
newChannels.insert(0, _hiddenChannels[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